docs: Address PR 513 comments

This commit is contained in:
Andras Slemmer
2016-11-22 18:10:50 +00:00
parent 720bb55827
commit 44d1b79ef9
12 changed files with 91 additions and 67 deletions

View File

@ -23,27 +23,8 @@ Configuration File Examples
General node configuration file for hosting the IRSDemo services. General node configuration file for hosting the IRSDemo services.
.. code-block:: text .. literalinclude:: example-code/src/main/resources/example-node.conf
:language: cfg
basedir : "./nodea"
myLegalName : "Bank A"
nearestCity : "London"
keyStorePassword : "cordacadevpass"
trustStorePassword : "trustpass"
dataSourceProperties : {
dataSourceClassName : org.h2.jdbcx.JdbcDataSource
"dataSource.url" : "jdbc:h2:"${basedir}"/persistence"
"dataSource.user" : sa
"dataSource.password" : ""
}
artemisAddress : "localhost:31337"
webAddress : "localhost:31339"
extraAdvertisedServiceIds: "corda.interest_rates"
networkMapAddress : "localhost:12345"
useHTTPS : false
rpcUsers : [
{ user=user1, password=letmein, permissions=[ cash ] }
]
NetworkMapService plus Simple Notary configuration file. NetworkMapService plus Simple Notary configuration file.

View File

@ -0,0 +1,9 @@
basedir : "./nameserver"
myLegalName : "Notary Service"
nearestCity : "London"
keyStorePassword : "cordacadevpass"
trustStorePassword : "trustpass"
artemisAddress : "my-network-map:10000"
webAddress : "localhost:10001"
extraAdvertisedServiceIds: ""
useHTTPS : false

View File

@ -1,11 +1,19 @@
basedir : "./standalone/regular-node" basedir : "./nodea"
myLegalName : "Some Node" myLegalName : "Bank A"
nearestCity : "London" nearestCity : "London"
keyStorePassword : "cordacadevpass" keyStorePassword : "cordacadevpass"
trustStorePassword : "trustpass" trustStorePassword : "trustpass"
artemisAddress : "cordaload-node1:31337" dataSourceProperties : {
webAddress : "localhost:31339" dataSourceClassName : org.h2.jdbcx.JdbcDataSource
extraAdvertisedServiceIds: "" "dataSource.url" : "jdbc:h2:"${basedir}"/persistence"
"dataSource.user" : sa
"dataSource.password" : ""
}
artemisAddress : "my-corda-node:10002"
webAddress : "localhost:10003"
extraAdvertisedServiceIds: "corda.interest_rates"
networkMapAddress : "my-network-map:10000"
useHTTPS : false useHTTPS : false
devMode : false rpcUsers : [
networkMapAddress : "cordaload-nameserver:31337" { user=user1, password=letmein, permissions=[ StartProtocol.net.corda.protocols.CashProtocol ] }
]

View File

@ -9,15 +9,24 @@ import kotlin.reflect.declaredMemberProperties
class ExampleNodeConfTest { class ExampleNodeConfTest {
@Test @Test
fun exampleNodeConfParsesFine() { fun exampleNodeConfParsesFine() {
val configResource = ExampleNodeConfTest::class.java.classLoader.getResource("example-node.conf") val exampleNodeConfFilenames = arrayOf(
val nodeConfig = FullNodeConfiguration( "example-node.conf",
ConfigHelper.loadConfig( "example-network-map-node.conf"
baseDirectoryPath = Paths.get("some-example-base-dir"),
configFileOverride = Paths.get(configResource.toURI())
)
) )
nodeConfig.javaClass.kotlin.declaredMemberProperties.forEach { member ->
member.get(nodeConfig) exampleNodeConfFilenames.forEach {
println("Checking $it")
val configResource = ExampleNodeConfTest::class.java.classLoader.getResource(it)
val nodeConfig = FullNodeConfiguration(
ConfigHelper.loadConfig(
baseDirectoryPath = Paths.get("some-example-base-dir"),
configFileOverride = Paths.get(configResource.toURI())
)
)
// Force the config fields as they are resolved lazily
nodeConfig.javaClass.kotlin.declaredMemberProperties.forEach { member ->
member.get(nodeConfig)
}
} }
} }
} }

View File

@ -1,16 +1,15 @@
A Corda network .. _log4j2: http://logging.apache.org/log4j/2.x/
Introduction - What is a corda network? Introduction - What is a corda network?
======================================================== ========================================================
A Corda network consists of a number of machines running ``node``s, including a single node operating as the network map service. These nodes communicate using persistent protocols in order to create and validate transactions. A Corda network consists of a number of machines running nodes, including a single node operating as the network map service. These nodes communicate using persistent protocols in order to create and validate transactions.
There are four broader categories of functionality one such node may have. These pieces of functionality are provided as services, and one node may run several of them. There are four broader categories of functionality one such node may have. These pieces of functionality are provided as services, and one node may run several of them.
* Network map: The node running the network map provides a way to resolve identities to physical node addresses. * Network map: The node running the network map provides a way to resolve identities to physical node addresses and associated public keys.
* Notary: Nodes running a notary service witness state spends and have the final say in whether a transaction is a double-spend or not. * Notary: Nodes running a notary service witness state spends and have the final say in whether a transaction is a double-spend or not.
* Oracle: Nodes providing some oracle functionality like exchange rate or interest rate witnesses. * Oracle: Network services that link the ledger to the outside world by providing facts that affect the validity of transactions.
* Regular node: All nodes have a vault and may start protocols communicating with other nodes, notaries and oracles and evolve their private ledger. * Regular node: All nodes have a vault and may start protocols communicating with other nodes, notaries and oracles and evolve their private ledger.
Setting up your own network Setting up your own network
@ -19,7 +18,13 @@ Setting up your own network
Certificates Certificates
------------ ------------
All node certificates' root must be the same. Later R3 will provide the root for production use, but for testing you can use ``certSigningRequestUtility.jar`` to generate a node certificate with a fixed test root: If two nodes are to communicate successfully then both need to have
each other's root certificate in their truststores. The simplest way
to achieve this is to have all nodes sign off of a single root.
Later R3 will provide this root for production use, but for testing you
can use ``certSigningRequestUtility.jar`` to generate a node
certificate with a fixed test root:
.. sourcecode:: bash .. sourcecode:: bash
@ -31,7 +36,7 @@ All node certificates' root must be the same. Later R3 will provide the root for
Configuration Configuration
------------- -------------
A node can be configured by adding/editing ``node.conf`` in the node's directory. A node can be configured by adding/editing ``node.conf`` in the node's directory. For details see :doc:`corda-configuration-files`
An example configuration: An example configuration:
@ -40,24 +45,37 @@ An example configuration:
The most important fields regarding network configuration are: The most important fields regarding network configuration are:
* ``artemisAddress``: This specifies a host and port. Note that the address bound will **NOT** be ``cordaload-node1``, but rather ``::`` (all addresses on all interfaces). The hostname specified is the hostname *that must be externally resolvable by other nodes in the network*. In the above configuration this is the resolvable name of a node in a vpn. * ``artemisAddress``: This specifies a host and port. Note that the address bound will **NOT** be ``my-corda-node``, but rather ``::`` (all addresses on all interfaces). The hostname specified is the hostname *that must be externally resolvable by other nodes in the network*. In the above configuration this is the resolvable name of a machine in a vpn.
* ``webAddress``: The address the webserver should bind. Note that the port should be distinct from that of ``artemisAddress``. * ``webAddress``: The address the webserver should bind. Note that the port should be distinct from that of ``artemisAddress``.
* ``networkMapAddress``: The resolvable name and artemis port of the network map node. Note that if this node itself is to be the network map this field should not be specified. * ``networkMapAddress``: The resolvable name and artemis port of the network map node. Note that if this node itself is to be the network map this field should not be specified.
Starting the nodes Starting the nodes
------------------ ------------------
You may now start the nodes in any order. You should see lots of log lines about the startup. You may now start the nodes in any order. Note that the node is not fully started until it has successfully registered with the network map!
Note that the node is not fully started until it has successfully registered with the network map! A good way of determining whether a node is up is to check whether its ``webAddress`` is bound. You should see a banner, some log lines and eventually ``Node started up and registered``, indicating that the node is fully started.
.. TODO: Add a better way of polling for startup
A programmatic way of determining whether a node is up is to check whether it's ``webAddress`` is bound.
In terms of process management there is no prescribed method. You may start the jars by hand or perhaps use systemd and friends.
Logging
-------
Only a handful of important lines are printed to the console. For
details/diagnosing problems check the logs.
Logging is standard log4j2_ and may be configured accordingly. Logs
are by default redirected to files in ``NODE_DIRECTORY/logs/``.
In terms of process management there is no pre-described method, you may start the jars by hand or perhaps use systemd and friends.
Connecting to the nodes Connecting to the nodes
----------------------- -----------------------
Once a node has started up successfully you may connect to it as a client to initiate protocols/query state etc. Depending on your network setup you may need to tunnel to do this remotely. Once a node has started up successfully you may connect to it as a client to initiate protocols/query state etc. Depending on your network setup you may need to tunnel to do this remotely.
See the :doc:`tutorial-clientrpc-api` on how to establish an RPC link, or you can use the web apis as well. See the :doc:`tutorial-clientrpc-api` on how to establish an RPC link.
Sidenote: A client is always associated with a single node with a single identity, which only sees their part of the ledger. Sidenote: A client is always associated with a single node with a single identity, which only sees their part of the ledger.

Binary file not shown.

Binary file not shown.

View File

@ -120,7 +120,7 @@ class Node(override val configuration: FullNodeConfiguration, networkMapAddress:
override fun makeMessagingService(): MessagingServiceInternal { override fun makeMessagingService(): MessagingServiceInternal {
val legalIdentity = obtainLegalIdentity() val legalIdentity = obtainLegalIdentity()
val myIdentityOrNullIfNetworkMapService = if (networkMapService != null) legalIdentity.owningKey else null val myIdentityOrNullIfNetworkMapService = if (networkMapService != null) legalIdentity.owningKey else null
userService = RPCUserServiceImpl(configuration.config) userService = RPCUserServiceImpl(configuration)
val serverAddr = with(configuration) { val serverAddr = with(configuration) {
messagingServerAddress ?: { messagingServerAddress ?: {
messageBroker = ArtemisMessagingServer(this, artemisAddress, myIdentityOrNullIfNetworkMapService, services.networkMapCache, userService) messageBroker = ArtemisMessagingServer(this, artemisAddress, myIdentityOrNullIfNetworkMapService, services.networkMapCache, userService)

View File

@ -1,8 +1,7 @@
package net.corda.node.services package net.corda.node.services
import com.typesafe.config.Config
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.node.services.config.getListOrElse import net.corda.node.services.config.FullNodeConfiguration
/** /**
* Service for retrieving [User] objects representing RPC users who are authorised to use the RPC system. A [User] * Service for retrieving [User] objects representing RPC users who are authorised to use the RPC system. A [User]
@ -16,21 +15,9 @@ interface RPCUserService {
// TODO Store passwords as salted hashes // TODO Store passwords as salted hashes
// TODO Or ditch this and consider something like Apache Shiro // TODO Or ditch this and consider something like Apache Shiro
class RPCUserServiceImpl(config: Config) : RPCUserService { class RPCUserServiceImpl(config: FullNodeConfiguration) : RPCUserService {
private val _users: Map<String, User> private val _users = config.rpcUsers.associateBy(User::username)
init {
_users = config.getListOrElse<Config>("rpcUsers") { emptyList() }
.map {
val username = it.getString("user")
require(username.matches("\\w+".toRegex())) { "Username $username contains invalid characters" }
val password = it.getString("password")
val permissions = it.getListOrElse<String>("permissions") { emptyList() }.toSet()
User(username, password, permissions)
}
.associateBy(User::username)
}
override fun getUser(username: String): User? = _users[username] override fun getUser(username: String): User? = _users[username]

View File

@ -7,6 +7,7 @@ import net.corda.core.messaging.SingleMessageRecipient
import net.corda.core.node.services.ServiceInfo import net.corda.core.node.services.ServiceInfo
import net.corda.node.internal.Node import net.corda.node.internal.Node
import net.corda.node.serialization.NodeClock import net.corda.node.serialization.NodeClock
import net.corda.node.services.User
import net.corda.node.services.messaging.NodeMessagingClient import net.corda.node.services.messaging.NodeMessagingClient
import net.corda.node.services.network.NetworkMapService import net.corda.node.services.network.NetworkMapService
import net.corda.node.utilities.TestClock import net.corda.node.utilities.TestClock
@ -51,6 +52,15 @@ class FullNodeConfiguration(val config: Config) : NodeConfiguration {
val useTestClock: Boolean by config.getOrElse { false } val useTestClock: Boolean by config.getOrElse { false }
val notaryNodeAddress: HostAndPort? by config.getOrElse { null } val notaryNodeAddress: HostAndPort? by config.getOrElse { null }
val notaryClusterAddresses: List<HostAndPort> = config.getListOrElse<String>("notaryClusterAddresses") { emptyList<String>() }.map { HostAndPort.fromString(it) } val notaryClusterAddresses: List<HostAndPort> = config.getListOrElse<String>("notaryClusterAddresses") { emptyList<String>() }.map { HostAndPort.fromString(it) }
val rpcUsers: List<User> =
config.getListOrElse<Config>("rpcUsers") { emptyList() }
.map {
val username = it.getString("user")
require(username.matches("\\w+".toRegex())) { "Username $username contains invalid characters" }
val password = it.getString("password")
val permissions = it.getListOrElse<String>("permissions") { emptyList() }.toSet()
User(username, password, permissions)
}
fun createNode(): Node { fun createNode(): Node {
// This is a sanity feature do not remove. // This is a sanity feature do not remove.

View File

@ -11,6 +11,7 @@ import net.corda.core.messaging.Message
import net.corda.core.messaging.createMessage import net.corda.core.messaging.createMessage
import net.corda.core.node.services.DEFAULT_SESSION_ID import net.corda.core.node.services.DEFAULT_SESSION_ID
import net.corda.core.utilities.LogHelper import net.corda.core.utilities.LogHelper
import net.corda.node.services.config.FullNodeConfiguration
import net.corda.node.services.config.NodeConfiguration import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.messaging.ArtemisMessagingServer import net.corda.node.services.messaging.ArtemisMessagingServer
import net.corda.node.services.messaging.NodeMessagingClient import net.corda.node.services.messaging.NodeMessagingClient
@ -65,7 +66,7 @@ class ArtemisMessagingTests {
@Before @Before
fun setUp() { fun setUp() {
userService = RPCUserServiceImpl(ConfigFactory.empty()) userService = RPCUserServiceImpl(FullNodeConfiguration(ConfigFactory.empty()))
// TODO: create a base class that provides a default implementation // TODO: create a base class that provides a default implementation
config = object : NodeConfiguration { config = object : NodeConfiguration {
override val basedir: Path = temporaryFolder.newFolder().toPath() override val basedir: Path = temporaryFolder.newFolder().toPath()

View File

@ -1,6 +1,7 @@
package net.corda.node.services package net.corda.node.services
import com.typesafe.config.ConfigFactory import com.typesafe.config.ConfigFactory
import net.corda.node.services.config.FullNodeConfiguration
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatThrownBy import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.Test import org.junit.Test
@ -68,6 +69,6 @@ class RPCUserServiceImplTest {
} }
private fun loadWithContents(configString: String): RPCUserServiceImpl { private fun loadWithContents(configString: String): RPCUserServiceImpl {
return RPCUserServiceImpl(ConfigFactory.parseString(configString)) return RPCUserServiceImpl(FullNodeConfiguration(ConfigFactory.parseString(configString)))
} }
} }