mirror of
https://github.com/corda/corda.git
synced 2025-02-21 09:51:57 +00:00
docs: Address PR 513 comments
This commit is contained in:
parent
720bb55827
commit
44d1b79ef9
@ -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.
|
||||
|
||||
|
@ -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
|
@ -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 ] }
|
||||
]
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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.
|
||||
|
BIN
node/logs/archive/node-voodoo.2016-11-22-1.log.gz
Normal file
BIN
node/logs/archive/node-voodoo.2016-11-22-1.log.gz
Normal file
Binary file not shown.
BIN
node/logs/archive/node-voodoo.2016-11-23-1.log.gz
Normal file
BIN
node/logs/archive/node-voodoo.2016-11-23-1.log.gz
Normal file
Binary file not shown.
@ -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)
|
||||
|
@ -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]
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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()
|
||||
|
@ -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)))
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user