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.
.. code-block:: text
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 ] }
]
.. literalinclude:: example-code/src/main/resources/example-node.conf
:language: cfg
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"
myLegalName : "Some Node"
basedir : "./nodea"
myLegalName : "Bank A"
nearestCity : "London"
keyStorePassword : "cordacadevpass"
trustStorePassword : "trustpass"
artemisAddress : "cordaload-node1:31337"
webAddress : "localhost:31339"
extraAdvertisedServiceIds: ""
dataSourceProperties : {
dataSourceClassName : org.h2.jdbcx.JdbcDataSource
"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
devMode : false
networkMapAddress : "cordaload-nameserver:31337"
rpcUsers : [
{ user=user1, password=letmein, permissions=[ StartProtocol.net.corda.protocols.CashProtocol ] }
]

View File

@ -9,15 +9,24 @@ import kotlin.reflect.declaredMemberProperties
class ExampleNodeConfTest {
@Test
fun exampleNodeConfParsesFine() {
val configResource = ExampleNodeConfTest::class.java.classLoader.getResource("example-node.conf")
val nodeConfig = FullNodeConfiguration(
ConfigHelper.loadConfig(
baseDirectoryPath = Paths.get("some-example-base-dir"),
configFileOverride = Paths.get(configResource.toURI())
)
val exampleNodeConfFilenames = arrayOf(
"example-node.conf",
"example-network-map-node.conf"
)
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?
========================================================
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.
* 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.
* 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.
Setting up your own network
@ -19,7 +18,13 @@ Setting up your own network
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
@ -31,7 +36,7 @@ All node certificates' root must be the same. Later R3 will provide the root for
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:
@ -40,24 +45,37 @@ An example configuration:
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``.
* ``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
------------------
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
-----------------------
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.

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 {
val legalIdentity = obtainLegalIdentity()
val myIdentityOrNullIfNetworkMapService = if (networkMapService != null) legalIdentity.owningKey else null
userService = RPCUserServiceImpl(configuration.config)
userService = RPCUserServiceImpl(configuration)
val serverAddr = with(configuration) {
messagingServerAddress ?: {
messageBroker = ArtemisMessagingServer(this, artemisAddress, myIdentityOrNullIfNetworkMapService, services.networkMapCache, userService)

View File

@ -1,8 +1,7 @@
package net.corda.node.services
import com.typesafe.config.Config
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]
@ -16,21 +15,9 @@ interface RPCUserService {
// TODO Store passwords as salted hashes
// 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>
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)
}
private val _users = config.rpcUsers.associateBy(User::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.node.internal.Node
import net.corda.node.serialization.NodeClock
import net.corda.node.services.User
import net.corda.node.services.messaging.NodeMessagingClient
import net.corda.node.services.network.NetworkMapService
import net.corda.node.utilities.TestClock
@ -51,6 +52,15 @@ class FullNodeConfiguration(val config: Config) : NodeConfiguration {
val useTestClock: Boolean by config.getOrElse { false }
val notaryNodeAddress: HostAndPort? by config.getOrElse { null }
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 {
// 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.node.services.DEFAULT_SESSION_ID
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.messaging.ArtemisMessagingServer
import net.corda.node.services.messaging.NodeMessagingClient
@ -65,7 +66,7 @@ class ArtemisMessagingTests {
@Before
fun setUp() {
userService = RPCUserServiceImpl(ConfigFactory.empty())
userService = RPCUserServiceImpl(FullNodeConfiguration(ConfigFactory.empty()))
// TODO: create a base class that provides a default implementation
config = object : NodeConfiguration {
override val basedir: Path = temporaryFolder.newFolder().toPath()

View File

@ -1,6 +1,7 @@
package net.corda.node.services
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.assertThatThrownBy
import org.junit.Test
@ -68,6 +69,6 @@ class RPCUserServiceImplTest {
}
private fun loadWithContents(configString: String): RPCUserServiceImpl {
return RPCUserServiceImpl(ConfigFactory.parseString(configString))
return RPCUserServiceImpl(FullNodeConfiguration(ConfigFactory.parseString(configString)))
}
}