corda/docs/source/generating-a-node.rst
2020-03-09 14:05:28 +00:00

478 lines
19 KiB
ReStructuredText

Creating nodes locally
======================
.. contents::
Handcrafting a node
-------------------
A node can be created manually by creating a folder that contains the following items:
* The Corda JAR, downloaded from https://r3.bintray.com/corda/net/corda/corda/ (under /|corda_version|/corda-|corda_version|.jar)
* A node configuration file entitled ``node.conf``, configured as per :doc:`corda-configuration-file`
* A folder entitled ``cordapps`` containing any CorDapp JARs you want the node to load
* An up-to-date version of the ``network-parameters`` file (:ref:`see docs <network-parameters>`) generated by the bootstrapper tool
* **Optional:** A webserver JAR entitled ``corda-webserver-|corda_version|.jar`` that will connect to the node via RPC
* The (deprecated) default webserver is available to you for testing and should not be used in a production environment.
* A Spring Boot alternative can be found here: https://github.com/corda/spring-webserver
The remaining files and folders described in :doc:`node-structure` will be generated at runtime.
The Cordform task
-----------------
Corda provides a gradle plugin called ``Cordform`` that allows you to automatically generate and configure a set of
nodes for testing and demos. Here is an example ``Cordform`` task called ``deployNodes`` that creates three nodes, defined
in the `Kotlin CorDapp Template <https://github.com/corda/cordapp-template-kotlin/blob/release-V|platform_version|/build.gradle#L95>`_:
.. sourcecode:: groovy
task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
directory "./build/nodes"
node {
name "O=Notary,L=London,C=GB"
// The notary will offer a validating notary service.
notary = [validating : true]
p2pPort 10002
rpcSettings {
port 10003
adminPort 10023
}
// No webport property, so no webserver will be created.
h2Port 10004
// Starts an internal SSH server providing a management shell on the node.
sshdPort 2223
// Includes the corda-finance CorDapp on our node.
cordapps = ["$corda_release_distribution:corda-finance:$corda_release_version"]
extraConfig = [
// Setting the JMX reporter type.
jmxReporterType: 'JOLOKIA',
// Setting the H2 address.
h2Settings: [ address: 'localhost:10030' ]
]
}
node {
name "O=PartyA,L=London,C=GB"
p2pPort 10005
rpcSettings {
port 10006
adminPort 10026
}
webPort 10007
h2Port 10008
cordapps = ["$corda_release_distribution:corda-finance:$corda_release_version"]
// Grants user1 all RPC permissions.
rpcUsers = [[ user: "user1", "password": "test", "permissions": ["ALL"]]]
}
node {
name "O=PartyB,L=New York,C=US"
p2pPort 10009
rpcSettings {
port 10010
adminPort 10030
}
webPort 10011
h2Port 10012
cordapps = ["$corda_release_distribution:corda-finance:$corda_release_version"]
// Grants user1 the ability to start the MyFlow flow.
rpcUsers = [[ user: "user1", "password": "test", "permissions": ["StartFlow.net.corda.flows.MyFlow"]]]
}
}
Running this task will create three nodes in the ``build/nodes`` folder:
* A ``Notary`` node that:
* Offers a validating notary service
* Will not have a webserver (since ``webPort`` is not defined)
* Is running the ``corda-finance`` CorDapp
* ``PartyA`` and ``PartyB`` nodes that:
* Are not offering any services
* Will have a webserver (since ``webPort`` is defined)
* Are running the ``corda-finance`` CorDapp
* Have an RPC user, ``user1``, that can be used to log into the node via RPC
Additionally, all three nodes will include any CorDapps defined in the project's source folders, even though these
CorDapps are not listed in each node's ``cordapps`` entry. This means that running the ``deployNodes`` task from the
template CorDapp, for example, would automatically build and add the template CorDapp to each node.
The configuration values available in ``deployNodes`` task are as follows:
Required configuration
^^^^^^^^^^^^^^^^^^^^^^
* ``name`` <string>
* The legal identity name of the Corda node. (see :ref:`myLegalName <corda_configuration_file_myLegalName>`)
* e.g.
::
name "O=PartyA,L=London,C=GB"
* ``p2pAddress`` <string> <**required if p2pPort not specified**>
* The address/port the node uses for inbound communication from other nodes. (see :ref:`p2pAddress <corda_configuration_file_p2pAddress>`)
* e.g.
::
p2pAddress "example.com:10002"
* ``p2pPort`` <integer>
* The port the node uses for inbound communication from other nodes. Assumes the address is ``localhost``. (see :ref:`p2pAddress <corda_configuration_file_p2pAddress>`)
* e.g.
::
p2pPort 10006 // "localhost:10006"
* ``rpcSettings`` <config>
* Specifies RPC settings for the node. (see :ref:`rpcSettings <corda_configuration_file_rpc_settings>`)
* e.g.
::
rpcSettings {
port 10006
adminPort 10026
}
Optional configuration
^^^^^^^^^^^^^^^^^^^^^^
* ``notary`` <config> (see :ref:`notary <corda_configuration_file_notary>`)
* Optional configuration which specifies the node is a notary.
* .. note:: <**required**> for notary nodes
* ``devMode`` <boolean>
* When true enables development mode. (see :ref:`devMode <corda_configuration_file_dev_mode>`)
* e.g.
::
devMode true
* ``webAddress`` <string>
* Configure a webserver to connect to the node via RPC. This will specify the address and port it will listen on. The node must have an RPC address configured. (see :ref:`Specifying a custom webserver<specify-custom-webserver>`)
* e.g.
::
webAddress "example.com:10011"
* ``webPort`` <integer>
* Configure a webserver to connect to the node via RPC. Defaults the address to `localhost`. The node must have an RPC address configured. (see :ref:`Specifying a custom webserver<specify-custom-webserver>`)
* e.g.
::
webPort 10011 // "localhost:10011"
* ``rpcUsers`` <list>
* Set the RPC users for this node. (see :ref:`rpcUsers <corda_configuration_file_rpc_users>`)
* e.g.
::
rpcUsers = [[ user: "user1", "password": "test", "permissions": ["StartFlow.net.corda.flows.MyFlow"]]]
* This configuration block allows arbitrary configuration. Incorrect configurations will not cause a DSL error.
* ``configFile`` <string>
* For extending configuration of nodes. (see :ref:`extended node configuration <generating_a_node_extended_config>`)
* e.g.
::
configFile = "samples/trader-demo/src/main/resources/node-b.conf"
* ``https`` <boolean>
* When true enables HTTPS communication from the node webserver.
* e.g.
::
https true
* ``sshdPort`` <integer>
* Specifies the port for sshd communication. (see :ref:`sshd <corda_configuration_file_sshd>`)
* e.g.
::
sshd {
port = 2222
}
You can extend the task ``deployNodes`` with more ``node {}`` blocks to generate as many nodes as necessary for your application.
.. warning:: When adding nodes, make sure that there are no port clashes!
.. _generating_a_node_extended_config:
To extend node configuration beyond the properties defined in the ``deployNodes`` task use the ``configFile`` property with the path (relative or absolute) set to an additional configuration file.
This file should follow the standard :doc:`corda-configuration-file` format, as per node.conf. The properties from this file will be appended to the generated node configuration. Note, if you add a property already created by the 'deployNodes' task, both properties will be present in the file.
The path to the file can also be added while running the Gradle task via the ``-PconfigFile`` command line option. However, the same file will be applied to all nodes.
Following the previous example ``PartyB`` node will have additional configuration options added from a file ``none-b.conf``:
.. sourcecode:: groovy
task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
[...]
node {
name "O=PartyB,L=New York,C=US"
[...]
// Grants user1 the ability to start the MyFlow flow.
rpcUsers = [[ user: "user1", "password": "test", "permissions": ["StartFlow.net.corda.flows.MyFlow"]]]
configFile = "samples/trader-demo/src/main/resources/node-b.conf"
}
}
Cordform parameter `drivers` of the `node` entry lists paths of the files to be copied to the `./drivers` subdirectory of the node.
To copy the same file to all nodes `ext.drivers` can be defined in the top level and reused for each node via `drivers=ext.drivers``.
.. sourcecode:: groovy
task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
ext.drivers = ['lib/my_common_jar.jar']
[...]
node {
name "O=PartyB,L=New York,C=US"
[...]
drivers = ext.drivers + ['lib/my_specific_jar.jar']
}
}
The Cordform task will automatically copy a Jolokia agent JAR into each generated node's `drivers` subdirectory. The version of this JAR
defaults to `1.6.0`. This can be changed by setting the `jolokia_version` property anywhere in your `build.gradle` file:
.. sourcecode:: groovy
ext.jolokia_version = "1.6.1"
.. _node_package_namespace_ownership:
Package namespace ownership
^^^^^^^^^^^^^^^^^^^^^^^^^^^
To specify :doc:`design/data-model-upgrades/package-namespace-ownership` configuration, the optional ``networkParameterOverrides`` and ``packageOwnership`` blocks can be used, similar to the configuration file used in :doc:`network-bootstrapper`:
.. sourcecode:: groovy
task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
[...]
networkParameterOverrides {
packageOwnership {
"com.mypackagename" {
keystore = "_teststore"
keystorePassword = "MyStorePassword"
keystoreAlias = "MyKeyAlias"
}
}
}
[...]
}
Signing CorDapp JARs
^^^^^^^^^^^^^^^^^^^^
The default behaviour of Cordform is to deploy CorDapp JARs "as built":
- prior to Corda 4 all CorDapp JARs were unsigned.
- as of Corda 4, CorDapp JARs created by the Gradle *cordapp* plugin are signed by a Corda development certificate by default.
The Cordform ``signing`` entry can be used to override and customise the signing of CorDapp JARs.
Signing the CorDapp enables its contract classes to use signature constraints instead of other types of the constraints :doc:`api-contract-constraints`.
The sign task may use an external keystore, or create a new one.
The ``signing`` entry may contain the following parameters:
* ``enabled`` the control flag to enable signing process, by default is set to ``false``, set to ``true`` to enable signing
* ``all`` if set to ``true`` (by default) all CorDapps inside *cordapp* subdirectory will be signed, otherwise if ``false`` then only the generated Cordapp will be signed
* ``options`` any relevant parameters of `SignJar ANT task <https://ant.apache.org/manual/Tasks/signjar.html>`_ and `GenKey ANT task <https://ant.apache.org/manual/Tasks/genkey.html>`_,
by default the JAR file is signed by Corda development key, the external keystore can be specified,
the minimal list of required options is shown below, for other options referer to `SignJar task <https://ant.apache.org/manual/Tasks/signjar.html>`_:
* ``keystore`` the path to the keystore file, by default *cordadevcakeys.jks* keystore is shipped with the plugin
* ``alias`` the alias to sign under, the default value is *cordaintermediateca*
* ``storepass`` the keystore password, the default value is *cordacadevpass*
* ``keypass`` the private key password if it's different than the password for the keystore, the default value is *cordacadevkeypass*
* ``storetype`` the keystore type, the default value is *JKS*
* ``dname`` the distinguished name for entity, the option is used when ``generateKeystore true`` only
* ``keyalg`` the method to use when generating name-value pair, the value defaults to *RSA* as Corda doesn't support *DSA*, the option is used when ``generateKeystore true`` only
* ``generateKeystore`` the flag to generate a keystore, it is set to ``false`` by default. If set to ``true`` then ad hock keystore is created and its key isused
instead of the default Corda development key or any external key.
The same ``options`` to specify an external keystore are used to define the newly created keystore. Additionally
``dname`` and ``keyalg`` are required. Other options are described in `GenKey task <https://ant.apache.org/manual/Tasks/genkey.html>`_.
If the existing keystore is already present the task will reuse it, however if the file is inside the *build* directory,
then it will be deleted when Gradle *clean* task is run.
The example below shows the minimal set of ``options`` needed to create a dummy keystore:
.. sourcecode:: groovy
task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
signing {
enabled true
generateKeystore true
all false
options {
keystore "./build/nodes/jarSignKeystore.p12"
alias "cordapp-signer"
storepass "secret1!"
storetype "PKCS12"
dname "OU=Dummy Cordapp Distributor, O=Corda, L=London, C=GB"
keyalg "RSA"
}
}
//...
Contracts classes from signed CorDapp JARs will be checked by signature constraints by default.
You can force them to be checked by zone constraints by adding contract class names to ``includeWhitelist`` entry,
the list will generate *include_whitelist.txt* file used internally by :doc:`network-bootstrapper` tool.
Refer to :doc:`api-contract-constraints` to understand implication of different constraint types before adding ``includeWhitelist`` to ``deployNodes`` task.
The snippet below configures contracts classes from Finance CorDapp to be verified using zone constraints instead of signature constraints:
.. sourcecode:: groovy
task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
includeWhitelist = [ "net.corda.finance.contracts.asset.Cash", "net.corda.finance.contracts.asset.CommercialPaper" ]
//...
.. _specify-custom-webserver:
Specifying a custom webserver
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
By default, any node listing a web port will use the default development webserver, which is not production-ready. You
can use your own webserver JAR instead by using the ``webserverJar`` argument in a ``Cordform`` ``node`` configuration
block:
.. sourcecode:: groovy
node {
name "O=PartyA,L=New York,C=US"
webPort 10005
webserverJar "lib/my_webserver.jar"
}
The webserver JAR will be copied into the node's ``build`` folder with the name ``corda-webserver.jar``.
.. warning:: This is an experimental feature. There is currently no support for reading the webserver's port from the
node's ``node.conf`` file.
The Dockerform task
-------------------
The ``Dockerform`` is a sister task of ``Cordform`` that provides an extra file allowing you to easily spin up nodes using ``docker-compose``. It supports the following configuration options for each node:
* ``name``
* ``notary``
* ``cordapps``
* ``rpcUsers``
* ``useTestClock``
The nodes' webservers will not be started. Instead, you should interact with each node via its shell over SSH
(see the :doc:`node configuration options <corda-configuration-file>`). You have to enable the shell by adding the
following line to each node's ``node.conf`` file:
``sshd { port = <NUMBER> }``
Where ``<NUMBER>`` is the port you want to open to SSH into the shell.
To run the Dockerform task, follow these steps:
1. Run ``./gradlew deployNodes`` to generate the node files and folder structure.
2. Open the ``build.gradle`` file and add a new ``dockerform`` task after the existing ``deployNodes`` task:
.. sourcecode:: groovy
task prepareDockerNodes(type: net.corda.plugins.Dockerform, dependsOn: ['jar']) {
nodeDefaults {
cordapp project(":contracts-java")
}
node {
name "O=Notary,L=London,C=GB"
notary = [validating : false]
p2pPort 10002
rpcSettings {
address("localhost:10003")
adminAddress("localhost:10023")
}
projectCordapp {
deploy = false
}
cordapps.clear()
}
node {
name "O=PartyA,L=London,C=GB"
p2pPort 10002
rpcSettings {
address("localhost:10003")
adminAddress("localhost:10023")
}
rpcUsers = [[user: "user1", "password": "test", "permissions": ["ALL"]]]
}
node {
name "O=PartyB,L=New York,C=US"
p2pPort 10002
rpcSettings {
address("localhost:10003")
adminAddress("localhost:10023")
}
rpcUsers = [[user: "user1", "password": "test", "permissions": ["ALL"]]]
}
}
3. Create an empty ``docker-compose.yml`` file using the following command on Mac or Linux:
``touch workflows-java/build/nodes/docker-compose.yml``
For Windows, use the following command:
``echo.> workflows-java\build\nodes\docker-compose.yml``
4. Run ``./gradlew prepareDockerNodes`` and edit the generated ``docker-compose.yml`` file to change the ports:
.. sourcecode:: groovy
version: '3'
services:
notary:
build: /Users/<USER>/Projects/json-cordapp/workflows-java/build/nodes/Notary
ports:
- "10002"
- "10003"
partya:
build: /Users/<USER>/Projects/json-cordapp/workflows-java/build/nodes/PartyA
ports:
- "10002"
- "10003"
partyb:
build: /Users/<USER>/Projects/json-cordapp/workflows-java/build/nodes/PartyB
ports:
- "10002"
- "10003"
Running the Cordform/Dockerform tasks
-------------------------------------
To create the nodes defined in our ``deployNodes`` task, run the following command in a terminal window from the root
of the project where the ``deployNodes`` task is defined:
* Linux/macOS: ``./gradlew deployNodes``
* Windows: ``gradlew.bat deployNodes``
This will create the nodes in the ``build/nodes`` folder. There will be a node folder generated for each node defined
in the ``deployNodes`` task, plus a ``runnodes`` shell script (or batch file on Windows) to run all the nodes at once
for testing and development purposes. If you make any changes to your CorDapp source or ``deployNodes`` task, you will
need to re-run the task to see the changes take effect.
If the task is a ``Dockerform`` task, running the task will also create an additional ``Dockerfile`` in each node
directory in the ``build/nodes`` directory.