Cleaned up notary configuration by introducing a notary config option.

extraAdvertisedServiceIds is no longer used for this.
This commit is contained in:
Shams Asari 2017-10-05 12:27:45 +01:00
parent 83f37417ae
commit 727cd0e55c
88 changed files with 600 additions and 716 deletions

View File

@ -233,7 +233,8 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
networkMap "O=Controller,OU=corda,L=London,C=GB"
node {
name "O=Controller,OU=corda,L=London,C=GB"
advertisedServices = ["corda.notary.validating"]
notary = [validating : true]
advertisedServices = []
p2pPort 10002
cordapps = []
}

View File

@ -27,9 +27,7 @@ import net.corda.finance.flows.CashExitFlow
import net.corda.finance.flows.CashIssueFlow
import net.corda.finance.flows.CashPaymentFlow
import net.corda.node.services.FlowPermissions.Companion.startFlowPermission
import net.corda.node.services.transactions.SimpleNotaryService
import net.corda.nodeapi.User
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.testing.*
import net.corda.testing.driver.driver
import net.corda.testing.node.DriverBasedTest
@ -59,7 +57,7 @@ class NodeMonitorModelTest : DriverBasedTest() {
startFlowPermission<CashExitFlow>())
)
val aliceNodeFuture = startNode(providedName = ALICE.name, rpcUsers = listOf(cashUser))
val notaryHandle = startNode(providedName = DUMMY_NOTARY.name, advertisedServices = setOf(ServiceInfo(SimpleNotaryService.type))).getOrThrow()
val notaryHandle = startNotaryNode(DUMMY_NOTARY.name, validating = false).getOrThrow()
val aliceNodeHandle = aliceNodeFuture.getOrThrow()
aliceNode = aliceNodeHandle.nodeInfo
newNode = { nodeName -> startNode(providedName = nodeName).getOrThrow().nodeInfo }

View File

@ -11,9 +11,7 @@ import net.corda.finance.flows.CashPaymentFlow;
import net.corda.finance.schemas.CashSchemaV1;
import net.corda.node.internal.Node;
import net.corda.node.internal.StartedNode;
import net.corda.node.services.transactions.ValidatingNotaryService;
import net.corda.nodeapi.User;
import net.corda.nodeapi.internal.ServiceInfo;
import net.corda.testing.CoreTestUtils;
import net.corda.testing.node.NodeBasedTest;
import org.junit.After;
@ -24,7 +22,6 @@ import java.io.IOException;
import java.util.*;
import java.util.concurrent.ExecutionException;
import static java.util.Collections.emptyMap;
import static java.util.Collections.singletonList;
import static java.util.Objects.requireNonNull;
import static kotlin.test.AssertionsKt.assertEquals;
@ -53,8 +50,7 @@ public class CordaRPCJavaClientTest extends NodeBasedTest {
@Before
public void setUp() throws ExecutionException, InterruptedException {
setCordappPackages("net.corda.finance.contracts");
Set<ServiceInfo> services = new HashSet<>(singletonList(new ServiceInfo(ValidatingNotaryService.Companion.getType(), null)));
CordaFuture<StartedNode<Node>> nodeFuture = startNode(getALICE().getName(), 1, services, singletonList(rpcUser), emptyMap());
CordaFuture<StartedNode<Node>> nodeFuture = startNotaryNode(getALICE().getName(), singletonList(rpcUser), true);
node = nodeFuture.get();
node.getInternals().registerCustomSchemas(Collections.singleton(CashSchemaV1.INSTANCE));
client = new CordaRPCClient(requireNonNull(node.getInternals().getConfiguration().getRpcAddress()));

View File

@ -19,9 +19,7 @@ import net.corda.finance.schemas.CashSchemaV1
import net.corda.node.internal.Node
import net.corda.node.internal.StartedNode
import net.corda.node.services.FlowPermissions.Companion.startFlowPermission
import net.corda.node.services.transactions.ValidatingNotaryService
import net.corda.nodeapi.User
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.testing.ALICE
import net.corda.testing.chooseIdentity
import net.corda.testing.node.NodeBasedTest
@ -52,7 +50,7 @@ class CordaRPCClientTest : NodeBasedTest() {
@Before
fun setUp() {
setCordappPackages("net.corda.finance.contracts")
node = startNode(ALICE.name, rpcUsers = listOf(rpcUser), advertisedServices = setOf(ServiceInfo(ValidatingNotaryService.type))).getOrThrow()
node = startNotaryNode(ALICE.name, rpcUsers = listOf(rpcUser)).getOrThrow()
node.internals.registerCustomSchemas(setOf(CashSchemaV1))
client = CordaRPCClient(node.internals.configuration.rpcAddress!!)
}

View File

@ -6,7 +6,6 @@ import net.corda.core.identity.CordaX500Name;
import net.corda.core.identity.Party;
import net.corda.core.messaging.CordaRPCOps;
import net.corda.core.messaging.FlowHandle;
import net.corda.core.node.NodeInfo;
import net.corda.core.utilities.OpaqueBytes;
import net.corda.finance.flows.AbstractCashFlow;
import net.corda.finance.flows.CashIssueFlow;
@ -41,7 +40,6 @@ public class StandaloneCordaRPCJavaClientTest {
private NodeProcess notary;
private CordaRPCOps rpcProxy;
private CordaRPCConnection connection;
private NodeInfo notaryNode;
private Party notaryNodeIdentity;
private NodeConfig notaryConfig = new NodeConfig(
@ -49,8 +47,8 @@ public class StandaloneCordaRPCJavaClientTest {
port.getAndIncrement(),
port.getAndIncrement(),
port.getAndIncrement(),
Collections.singletonList("corda.notary.validating"),
Arrays.asList(rpcUser),
true,
Collections.singletonList(rpcUser),
null
);
@ -61,7 +59,6 @@ public class StandaloneCordaRPCJavaClientTest {
notary = factory.create(notaryConfig);
connection = notary.connect();
rpcProxy = connection.getProxy();
notaryNode = fetchNotaryIdentity();
notaryNodeIdentity = rpcProxy.nodeInfo().getLegalIdentities().get(0);
}
@ -98,11 +95,6 @@ public class StandaloneCordaRPCJavaClientTest {
}
}
private NodeInfo fetchNotaryIdentity() {
List<NodeInfo> nodeDataSnapshot = rpcProxy.networkMapSnapshot();
return nodeDataSnapshot.get(0);
}
@Test
public void testCashBalances() throws NoSuchFieldException, ExecutionException, InterruptedException {
Amount<Currency> dollars123 = new Amount<>(123, Currency.getInstance("USD"));

View File

@ -64,7 +64,7 @@ class StandaloneCordaRPClientTest {
p2pPort = port.andIncrement,
rpcPort = port.andIncrement,
webPort = port.andIncrement,
extraServices = listOf("corda.notary.validating"),
isNotary = true,
users = listOf(user)
)

View File

@ -3,5 +3,7 @@ keyStorePassword : "cordacadevpass"
trustStorePassword : "trustpass"
p2pAddress : "localhost:10000"
webAddress : "localhost:10001"
extraAdvertisedServiceIds : [ "corda.notary.validating" ]
notary : {
validating : true
}
useHTTPS : false

View File

@ -13,7 +13,6 @@ import net.corda.core.node.services.NotaryService
import net.corda.core.node.services.TrustedAuthorityNotaryService
import net.corda.core.node.services.UniquenessProvider
import net.corda.core.serialization.CordaSerializable
import net.corda.core.transactions.FilteredTransaction
import net.corda.core.transactions.SignedTransaction
import net.corda.core.utilities.ProgressTracker
import net.corda.core.utilities.UntrustworthyData
@ -138,9 +137,12 @@ class NotaryFlow {
// Check if transaction is intended to be signed by this notary.
@Suspendable
protected fun checkNotary(notary: Party?) {
if (notary !in serviceHub.myInfo.legalIdentities)
// TODO This check implies that it's OK to use the node's main identity. Shouldn't it be just limited to the
// notary identities?
if (notary !in serviceHub.myInfo.legalIdentities) {
throw NotaryException(NotaryError.WrongNotary)
}
}
@Suspendable
private fun signAndSendResponse(txId: SecureHash) {

View File

@ -116,10 +116,8 @@ interface NetworkMapCache {
fun isNotary(party: Party): Boolean = party in notaryIdentities
/** Checks whether a given party is an validating notary identity. */
fun isValidatingNotary(party: Party): Boolean {
require(isNotary(party)) { "No notary found with identity $party." }
return !party.name.toString().contains("corda.notary.simple", true) // TODO This implementation will change after introducing of NetworkParameters.
}
// TODO This implementation will change after introducing of NetworkParameters.
fun isValidatingNotary(party: Party): Boolean = isNotary(party) && "validating" in party.name.commonName!!
/** Clear all network map data from local node cache. */
fun clearNetworkMapCache()

View File

@ -13,6 +13,18 @@ import org.slf4j.Logger
import java.security.PublicKey
abstract class NotaryService : SingletonSerializeAsToken() {
companion object {
const val ID_PREFIX = "corda.notary."
fun constructId(validating: Boolean, raft: Boolean = false, bft: Boolean = false): String {
require(!raft || !bft)
return StringBuffer(ID_PREFIX).apply {
append(if (validating) "validating" else "simple")
if (raft) append(".raft")
if (bft) append(".bft")
}.toString()
}
}
abstract val services: ServiceHub
abstract val notaryIdentityKey: PublicKey

View File

@ -12,7 +12,6 @@ import net.corda.core.utilities.getOrThrow
import net.corda.node.internal.StartedNode
import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.persistence.NodeAttachmentService
import net.corda.node.services.transactions.SimpleNotaryService
import net.corda.node.utilities.DatabaseTransactionManager
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.testing.ALICE
@ -117,7 +116,7 @@ class AttachmentTests {
@Test
fun `malicious response`() {
// Make a node that doesn't do sanity checking at load time.
val aliceNode = mockNet.createNode(legalName = ALICE.name, nodeFactory = object : MockNetwork.Factory<MockNetwork.MockNode> {
val aliceNode = mockNet.createNotaryNode(legalName = ALICE.name, nodeFactory = object : MockNetwork.Factory<MockNetwork.MockNode> {
override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
advertisedServices: Set<ServiceInfo>, id: Int,
notaryIdentity: Pair<ServiceInfo, KeyPair>?,
@ -126,7 +125,7 @@ class AttachmentTests {
override fun start() = super.start().apply { attachments.checkAttachmentsOnLoad = false }
}
}
}, advertisedServices = *arrayOf(ServiceInfo(SimpleNotaryService.type)))
}, validating = false)
val bobNode = mockNet.createNode(legalName = BOB.name)
// Ensure that registration was successful before progressing any further

View File

@ -20,6 +20,11 @@ UNRELEASED
either annotated with the @CordaSerializable annotation or explicitly whitelisted then a NotSerializableException is
thrown.
* ``extraAdvertisedServiceIds`` config has been removed as part of the previous work to retire the concept of advertised
services. The remaining use of this config was for notaries, the configuring of which has been cleaned up and simplified.
``notaryNodeAddress``, ``notaryClusterAddresses`` and ``bftSMaRt`` have also been removed and replaced by a single
``notary`` config object. See :doc:`corda-configuration-file` for more details.
.. _changelog_v1:
Release 1.0

View File

@ -30,7 +30,7 @@ General node configuration file for hosting the IRSDemo services.
.. literalinclude:: example-code/src/main/resources/example-node.conf
:language: javascript
NetworkMapService plus Simple Notary configuration file.
Simple Notary configuration file.
.. parsed-literal::
@ -40,7 +40,9 @@ NetworkMapService plus Simple Notary configuration file.
p2pAddress : "localhost:12345"
rpcAddress : "localhost:12346"
webAddress : "localhost:12347"
extraAdvertisedServiceIds : ["corda.notary.simple"]
notary : {
validating : false
}
useHTTPS : false
devMode : true
// Certificate signing service will be hosted by R3 in the near future.
@ -92,19 +94,25 @@ path to the node's base directory.
.. note:: The driver will not automatically create a webserver instance, but the Cordformation will. If this field
is present the web server will start.
:extraAdvertisedServiceIds: A list of ServiceType id strings to be advertised to the NetworkMapService and thus be available
when other nodes query the NetworkMapCache for supporting nodes. This can also include plugin services loaded from .jar
files in the plugins folder. Optionally, a custom advertised service name can be provided by appending it to the service
type id: ``"corda.notary.validating|Notary A"``
:notary: Optional config object which if present configures the node to run as a notary. If part of a Raft or BFT SMaRt
cluster then specify ``raft`` or ``bftSMaRt`` respectively as described below. If a single node notary then omit both.
:notaryNodeAddress: The host and port to which to bind the embedded Raft server. Required only when running a distributed
notary service. A group of Corda nodes can run a distributed notary service by each running an embedded Raft server and
joining them to the same cluster to replicate the committed state log. Note that the Raft cluster uses a separate transport
layer for communication that does not integrate with ArtemisMQ messaging services.
:validating: Boolean to determine whether the notary is a validating or non-validating one.
:notaryClusterAddresses: List of Raft cluster member addresses used to join the cluster. At least one of the specified
members must be active and be able to communicate with the cluster leader for joining. If empty, a new cluster will be
bootstrapped. Required only when running a distributed notary service.
:raft: If part of a distributed Raft cluster specify this config object, with the following settings:
:nodeAddress: The host and port to which to bind the embedded Raft server. Note that the Raft cluster uses a
separate transport layer for communication that does not integrate with ArtemisMQ messaging services.
:clusterAddresses: List of Raft cluster member addresses used to join the cluster. At least one of the specified
members must be active and be able to communicate with the cluster leader for joining. If empty, a new
cluster will be bootstrapped.
:bftSMaRt: If part of a distributed BFT SMaRt cluster specify this config object, with the following settings:
:replicaId:
:clusterAddresses:
:networkMapService: If `null`, or missing the node is declaring itself as the NetworkMapService host. Otherwise this is
a config object with the details of the network map service:

View File

@ -20,7 +20,8 @@ notary/network map node:
networkMap "O=Controller,OU=corda,L=London,C=UK"
node {
name "O=Controller,OU=corda,L=London,C=UK"
advertisedServices = ["corda.notary.validating"]
notary = [validating : true]
advertisedServices = []
p2pPort 10002
rpcPort 10003
webPort 10004

View File

@ -75,7 +75,8 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
networkMap "O=Notary Service,OU=corda,L=London,C=GB"
node {
name "O=Notary Service,OU=corda,L=London,C=GB"
advertisedServices = ["corda.notary.validating"]
notary = [validating : true]
advertisedServices = []
p2pPort 10002
rpcPort 10003
webPort 10004

View File

@ -11,8 +11,6 @@ import net.corda.finance.contracts.asset.Cash
import net.corda.finance.flows.CashIssueFlow
import net.corda.finance.flows.CashPaymentFlow
import net.corda.node.services.FlowPermissions.Companion.startFlowPermission
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.node.services.transactions.ValidatingNotaryService
import net.corda.nodeapi.User
import net.corda.testing.*
import net.corda.testing.driver.driver
@ -32,10 +30,10 @@ class IntegrationTestingTutorial {
val bobUser = User("bobUser", "testPassword2", permissions = setOf(
startFlowPermission<CashPaymentFlow>()
))
val (alice, bob, notary) = listOf(
val (alice, bob) = listOf(
startNode(providedName = ALICE.name, rpcUsers = listOf(aliceUser)),
startNode(providedName = BOB.name, rpcUsers = listOf(bobUser)),
startNode(providedName = DUMMY_NOTARY.name, advertisedServices = setOf(ServiceInfo(ValidatingNotaryService.type)))
startNotaryNode(DUMMY_NOTARY.name)
).transpose().getOrThrow()
// END 1

View File

@ -15,9 +15,7 @@ import net.corda.finance.flows.CashExitFlow
import net.corda.finance.flows.CashIssueFlow
import net.corda.finance.flows.CashPaymentFlow
import net.corda.node.services.FlowPermissions.Companion.startFlowPermission
import net.corda.node.services.transactions.ValidatingNotaryService
import net.corda.nodeapi.User
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.testing.ALICE
import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.driver.driver
@ -49,7 +47,7 @@ fun main(args: Array<String>) {
startFlowPermission<CashExitFlow>()))
driver(driverDirectory = baseDirectory, extraCordappPackagesToScan = listOf("net.corda.finance")) {
startNode(providedName = DUMMY_NOTARY.name, advertisedServices = setOf(ServiceInfo(ValidatingNotaryService.type)))
startNotaryNode(DUMMY_NOTARY.name)
val node = startNode(providedName = ALICE.name, rpcUsers = listOf(user)).get()
// END 1

View File

@ -9,8 +9,6 @@ import net.corda.finance.contracts.getCashBalances
import net.corda.finance.flows.CashIssueFlow
import net.corda.finance.schemas.CashSchemaV1
import net.corda.node.internal.StartedNode
import net.corda.node.services.transactions.ValidatingNotaryService
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.testing.*
import net.corda.testing.node.MockNetwork
import org.junit.After
@ -30,11 +28,7 @@ class CustomVaultQueryTest {
fun setup() {
setCordappPackages("net.corda.finance.contracts.asset")
mockNet = MockNetwork(threadPerNode = true)
val notaryService = ServiceInfo(ValidatingNotaryService.type)
mockNet.createNode(
legalName = DUMMY_NOTARY.name,
notaryIdentity = notaryService to DUMMY_NOTARY_KEY,
advertisedServices = *arrayOf(notaryService))
mockNet.createNotaryNode(legalName = DUMMY_NOTARY.name)
nodeA = mockNet.createPartyNode()
nodeB = mockNet.createPartyNode()

View File

@ -9,8 +9,6 @@ import net.corda.finance.contracts.getCashBalances
import net.corda.finance.flows.CashIssueFlow
import net.corda.finance.schemas.CashSchemaV1
import net.corda.node.internal.StartedNode
import net.corda.node.services.transactions.ValidatingNotaryService
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.testing.*
import net.corda.testing.node.MockNetwork
import org.junit.After
@ -28,11 +26,7 @@ class FxTransactionBuildTutorialTest {
fun setup() {
setCordappPackages("net.corda.finance.contracts.asset")
mockNet = MockNetwork(threadPerNode = true)
val notaryService = ServiceInfo(ValidatingNotaryService.type)
mockNet.createNode(
legalName = DUMMY_NOTARY.name,
notaryIdentity = notaryService to DUMMY_NOTARY_KEY,
advertisedServices = *arrayOf(notaryService))
mockNet.createNotaryNode(legalName = DUMMY_NOTARY.name)
nodeA = mockNet.createPartyNode()
nodeB = mockNet.createPartyNode()
nodeA.internals.registerCustomSchemas(setOf(CashSchemaV1))

View File

@ -9,10 +9,11 @@ import net.corda.core.node.services.vault.QueryCriteria
import net.corda.core.toFuture
import net.corda.core.utilities.getOrThrow
import net.corda.node.internal.StartedNode
import net.corda.node.services.transactions.ValidatingNotaryService
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.testing.*
import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.chooseIdentity
import net.corda.testing.node.MockNetwork
import net.corda.testing.setCordappPackages
import net.corda.testing.unsetCordappPackages
import org.junit.After
import org.junit.Before
import org.junit.Test
@ -33,11 +34,7 @@ class WorkflowTransactionBuildTutorialTest {
fun setup() {
setCordappPackages("net.corda.docs")
mockNet = MockNetwork(threadPerNode = true)
val notaryService = ServiceInfo(ValidatingNotaryService.type)
mockNet.createNode(
legalName = DUMMY_NOTARY.name,
notaryIdentity = Pair(notaryService, DUMMY_NOTARY_KEY),
advertisedServices = *arrayOf(notaryService))
mockNet.createNotaryNode(legalName = DUMMY_NOTARY.name)
nodeA = mockNet.createPartyNode()
nodeB = mockNet.createPartyNode()
nodeA.internals.registerInitiatedFlow(RecordCompletionFlow::class.java)

View File

@ -28,7 +28,8 @@ Let's take a look at the nodes we're going to deploy. Open the project's ``build
networkMap "O=Controller,L=London,C=GB"
node {
name "O=Controller,L=London,C=GB"
advertisedServices = ["corda.notary.validating"]
notary = [validating : true]
advertisedServices = []
p2pPort 10002
rpcPort 10003
cordapps = ["net.corda:corda-finance:$corda_release_version"]

View File

@ -11,20 +11,20 @@ At present we have several prototype notary implementations:
we are using the `Copycat <http://atomix.io/copycat/>`_ framework
4. ``RaftValidatingNotaryService`` (distributed) -- as above, but performs validation on the transactions received
To have a node run a notary service, you need to set appropriate configuration values before starting it
To have a node run a notary service, you need to set appropriate ``notary`` configuration before starting it
(see :doc:`corda-configuration-file` for reference).
For ``SimpleNotaryService``, simply add the following service id to the list of advertised services:
For ``SimpleNotaryService`` the config is simply:
.. parsed-literal::
extraAdvertisedServiceIds : [ "net.corda.notary.simple" ]
notary : { validating : false }
For ``ValidatingNotaryService``, it is:
.. parsed-literal::
extraAdvertisedServiceIds : [ "net.corda.notary.validating" ]
notary : { validating : true }
Setting up a Raft notary is currently slightly more involved and is not recommended for prototyping purposes. There is
work in progress to simplify it. To see it in action, however, you can try out the :ref:`notary-demo`.

View File

@ -24,9 +24,3 @@ as ``ValidatingNotaryFlow``, ``NonValidatingNotaryFlow``, or implement your own
:language: kotlin
:start-after: START 2
:end-before: END 2
To ensure the custom notary is installed and advertised by the node, specify it in the configuration file:
.. parsed-literal::
extraAdvertisedServiceIds : ["corda.notary.validating.mycustom"]

View File

@ -1,9 +1,7 @@
package net.corda.cordform;
import static java.util.Collections.emptyList;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import com.typesafe.config.ConfigValueFactory;
import com.typesafe.config.*;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@ -30,11 +28,6 @@ public class CordformNode implements NodeDefinition {
*/
public List<String> advertisedServices = emptyList();
/**
* If running a Raft notary cluster, the address of at least one node in the cluster, or leave blank to start a new cluster.
* If running a BFT notary cluster, the addresses of all nodes in the cluster.
*/
public List<String> notaryClusterAddresses = emptyList();
/**
* Set the RPC users for this node. This configuration block allows arbitrary configuration.
* The recommended current structure is:
@ -45,6 +38,12 @@ public class CordformNode implements NodeDefinition {
*/
public List<Map<String, Object>> rpcUsers = emptyList();
/**
* Apply the notary configuration if this node is a notary. The map is the config structure of
* net.corda.node.services.config.NotaryConfig
*/
public Map<String, Object> notary = null;
protected Config config = ConfigFactory.empty();
public Config getConfig() {
@ -78,20 +77,4 @@ public class CordformNode implements NodeDefinition {
public void rpcPort(Integer rpcPort) {
config = config.withValue("rpcAddress", ConfigValueFactory.fromAnyRef(DEFAULT_HOST + ':' + rpcPort));
}
/**
* Set the port which to bind the Copycat (Raft) node to.
*
* @param notaryPort The Raft port.
*/
public void notaryNodePort(Integer notaryPort) {
config = config.withValue("notaryNodeAddress", ConfigValueFactory.fromAnyRef(DEFAULT_HOST + ':' + notaryPort));
}
/**
* @param id The (0-based) BFT replica ID.
*/
public void bftReplicaId(Integer id) {
config = config.withValue("bftSMaRt", ConfigValueFactory.fromMap(Collections.singletonMap("replicaId", id)));
}
}

View File

@ -99,7 +99,7 @@ class Node extends CordformNode {
}
protected void build() {
configureRpcUsers()
configureProperties()
installCordaJar()
if (config.hasPath("webAddress")) {
installWebserverJar()
@ -118,11 +118,12 @@ class Node extends CordformNode {
return config.getString("p2pAddress")
}
/**
* Write the RPC users to the config
*/
private void configureRpcUsers() {
private void configureProperties() {
config = config.withValue("rpcUsers", ConfigValueFactory.fromIterable(rpcUsers))
if (notary) {
config = config.withValue("notary", ConfigValueFactory.fromMap(notary))
}
config = config.withValue('extraAdvertisedServiceIds', ConfigValueFactory.fromIterable(advertisedServices*.toString()))
}
/**
@ -177,11 +178,6 @@ class Node extends CordformNode {
* Installs the configuration file to this node's directory and detokenises it.
*/
private void installConfig() {
// Adding required default values
config = config.withValue('extraAdvertisedServiceIds', ConfigValueFactory.fromIterable(advertisedServices*.toString()))
if (notaryClusterAddresses.size() > 0) {
config = config.withValue('notaryClusterAddresses', ConfigValueFactory.fromIterable(notaryClusterAddresses*.toString()))
}
def configFileText = config.root().render(new ConfigRenderOptions(false, false, true, false)).split("\n").toList()
// Need to write a temporary file first to use the project.copy, which resolves directories correctly.

View File

@ -1,6 +1,7 @@
package net.corda.nodeapi
import net.corda.nodeapi.config.OldConfig
import net.corda.nodeapi.config.toConfig
data class User(
@OldConfig("user")
@ -8,9 +9,6 @@ data class User(
val password: String,
val permissions: Set<String>) {
override fun toString(): String = "${javaClass.simpleName}($username, permissions=$permissions)"
fun toMap() = mapOf(
"username" to username,
"password" to password,
"permissions" to permissions
)
@Deprecated("Use toConfig().root().unwrapped() instead")
fun toMap(): Map<String, Any> = toConfig().root().unwrapped()
}

View File

@ -2,18 +2,23 @@
package net.corda.nodeapi.config
import com.typesafe.config.Config
import com.typesafe.config.ConfigFactory
import com.typesafe.config.ConfigUtil
import com.typesafe.config.ConfigValueFactory
import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.noneOrSingle
import net.corda.core.internal.uncheckedCast
import net.corda.core.utilities.NetworkHostAndPort
import org.slf4j.LoggerFactory
import java.lang.reflect.Field
import java.lang.reflect.ParameterizedType
import java.net.Proxy
import java.net.URL
import java.nio.file.Path
import java.nio.file.Paths
import java.time.Instant
import java.time.LocalDate
import java.time.temporal.Temporal
import java.util.*
import kotlin.reflect.KClass
import kotlin.reflect.KProperty
@ -71,8 +76,8 @@ private fun Config.getSingleValue(path: String, type: KType): Any? {
NetworkHostAndPort::class -> NetworkHostAndPort.parse(getString(path))
Path::class -> Paths.get(getString(path))
URL::class -> URL(getString(path))
Properties::class -> getConfig(path).toProperties()
CordaX500Name::class -> CordaX500Name.parse(getString(path))
Properties::class -> getConfig(path).toProperties()
else -> if (typeClass.java.isEnum) {
parseEnum(typeClass.java, getString(path))
} else {
@ -126,4 +131,65 @@ private fun parseEnum(enumType: Class<*>, name: String): Enum<*> = enumBridge<Pr
private fun <T : Enum<T>> enumBridge(clazz: Class<T>, name: String): T = java.lang.Enum.valueOf(clazz, name)
/**
* Convert the receiver object into a [Config]. This does the inverse action of [parseAs].
*/
fun Any.toConfig(): Config = ConfigValueFactory.fromMap(toConfigMap()).toConfig()
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
// Reflect over the fields of the receiver and generate a value Map that can use to create Config object.
private fun Any.toConfigMap(): Map<String, Any> {
val values = HashMap<String, Any>()
for (field in javaClass.declaredFields) {
if (field.isSynthetic) continue
field.isAccessible = true
val value = field.get(this) ?: continue
val configValue = if (value is String || value is Boolean || value is Number) {
// These types are supported by Config as use as is
value
} else if (value is Temporal || value is NetworkHostAndPort || value is CordaX500Name || value is Path || value is URL) {
// These types make sense to be represented as Strings and the exact inverse parsing function for use in parseAs
value.toString()
} else if (value is Enum<*>) {
// Expicitly use the Enum's name in case the toString is overridden, which would make parsing problematic.
value.name
} else if (value is Properties) {
// For Properties we treat keys with . as nested configs
ConfigFactory.parseMap(uncheckedCast(value)).root()
} else if (value is Iterable<*>) {
value.toConfigIterable(field)
} else {
// Else this is a custom object recursed over
value.toConfigMap()
}
values[field.name] = configValue
}
return values
}
// For Iterables figure out the type parameter and apply the same logic as above on the individual elements.
private fun Iterable<*>.toConfigIterable(field: Field): Iterable<Any?> {
val elementType = (field.genericType as ParameterizedType).actualTypeArguments[0] as Class<*>
return when (elementType) {
// For the types already supported by Config we can use the Iterable as is
String::class.java -> this
Integer::class.java -> this
java.lang.Long::class.java -> this
java.lang.Double::class.java -> this
java.lang.Boolean::class.java -> this
LocalDate::class.java -> map(Any?::toString)
Instant::class.java -> map(Any?::toString)
NetworkHostAndPort::class.java -> map(Any?::toString)
Path::class.java -> map(Any?::toString)
URL::class.java -> map(Any?::toString)
CordaX500Name::class.java -> map(Any?::toString)
Properties::class.java -> map { ConfigFactory.parseMap(uncheckedCast(it)).root() }
else -> if (elementType.isEnum) {
map { (it as Enum<*>).name }
} else {
map { it?.toConfigMap() }
}
}
}
private val logger = LoggerFactory.getLogger("net.corda.nodeapi.config")

View File

@ -76,54 +76,66 @@ class ConfigParsingTest {
testPropertyType<URLData, URLListData, URL>(URL("http://localhost:1234"), URL("http://localhost:1235"), valuesToString = true)
}
@Test
fun CordaX500Name() {
testPropertyType<CordaX500NameData, CordaX500NameListData, CordaX500Name>(
CordaX500Name(organisation = "Mock Party", locality = "London", country = "GB"),
CordaX500Name(organisation = "Mock Party 2", locality = "London", country = "GB"),
valuesToString = true)
}
@Test
fun `flat Properties`() {
val config = config("value" to mapOf("key" to "prop"))
assertThat(config.parseAs<PropertiesData>().value).isEqualTo(Properties().apply { this["key"] = "prop" })
val data = PropertiesData(Properties().apply { this["key"] = "prop" })
assertThat(config.parseAs<PropertiesData>()).isEqualTo(data)
assertThat(data.toConfig()).isEqualTo(config)
}
@Test
fun `Properties key with dot`() {
val config = config("value" to mapOf("key.key2" to "prop"))
assertThat(config.parseAs<PropertiesData>().value).isEqualTo(Properties().apply { this["key.key2"] = "prop" })
val data = PropertiesData(Properties().apply { this["key.key2"] = "prop" })
assertThat(config.parseAs<PropertiesData>().value).isEqualTo(data.value)
}
@Test
fun `nested Properties`() {
val config = config("value" to mapOf("first" to mapOf("second" to "prop")))
assertThat(config.parseAs<PropertiesData>().value).isEqualTo(Properties().apply { this["first.second"] = "prop" })
val data = PropertiesData(Properties().apply { this["first.second"] = "prop" })
assertThat(config.parseAs<PropertiesData>().value).isEqualTo(data.value)
assertThat(data.toConfig()).isEqualTo(config)
}
@Test
fun `List of Properties`() {
val config = config("values" to listOf(emptyMap(), mapOf("key" to "prop")))
assertThat(config.parseAs<PropertiesListData>().values).containsExactly(
val data = PropertiesListData(listOf(
Properties(),
Properties().apply { this["key"] = "prop" })
Properties().apply { this["key"] = "prop" }))
assertThat(config.parseAs<PropertiesListData>().values).isEqualTo(data.values)
assertThat(data.toConfig()).isEqualTo(config)
}
@Test
fun `Set`() {
val config = config("values" to listOf("a", "a", "b"))
assertThat(config.parseAs<StringSetData>().values).containsOnly("a", "b")
val data = StringSetData(setOf("a", "b"))
assertThat(config("values" to listOf("a", "a", "b")).parseAs<StringSetData>()).isEqualTo(data)
assertThat(data.toConfig()).isEqualTo(config("values" to listOf("a", "b")))
assertThat(empty().parseAs<StringSetData>().values).isEmpty()
}
@Test
fun x500Name() {
testPropertyType<X500NameData, X500NameListData, CordaX500Name>(CordaX500Name(organisation = "Mock Party", locality = "London", country = "GB"), CordaX500Name(organisation = "Mock Party 2", locality = "London", country = "GB"), valuesToString = true)
}
@Test
fun `multi property data class`() {
val data = config(
val config = config(
"b" to true,
"i" to 123,
"l" to listOf("a", "b"))
.parseAs<MultiPropertyData>()
val data = config.parseAs<MultiPropertyData>()
assertThat(data.i).isEqualTo(123)
assertThat(data.b).isTrue()
assertThat(data.l).containsExactly("a", "b")
assertThat(data.toConfig()).isEqualTo(config)
}
@Test
@ -133,6 +145,7 @@ class ConfigParsingTest {
"value" to "nested"))
val data = NestedData(StringData("nested"))
assertThat(config.parseAs<NestedData>()).isEqualTo(data)
assertThat(data.toConfig()).isEqualTo(config)
}
@Test
@ -143,12 +156,14 @@ class ConfigParsingTest {
mapOf("value" to "2")))
val data = DataListData(listOf(StringData("1"), StringData("2")))
assertThat(config.parseAs<DataListData>()).isEqualTo(data)
assertThat(data.toConfig()).isEqualTo(config)
}
@Test
fun `default value property`() {
assertThat(config("a" to 3).parseAs<DefaultData>()).isEqualTo(DefaultData(3, 2))
assertThat(config("a" to 3, "defaultOfTwo" to 3).parseAs<DefaultData>()).isEqualTo(DefaultData(3, 3))
assertThat(DefaultData(3).toConfig()).isEqualTo(config("a" to 3, "defaultOfTwo" to 2))
}
@Test
@ -156,12 +171,14 @@ class ConfigParsingTest {
assertThat(empty().parseAs<NullableData>().nullable).isNull()
assertThat(config("nullable" to null).parseAs<NullableData>().nullable).isNull()
assertThat(config("nullable" to "not null").parseAs<NullableData>().nullable).isEqualTo("not null")
assertThat(NullableData(null).toConfig()).isEqualTo(empty())
}
@Test
fun `old config property`() {
assertThat(config("oldValue" to "old").parseAs<OldData>().newValue).isEqualTo("old")
assertThat(config("newValue" to "new").parseAs<OldData>().newValue).isEqualTo("new")
assertThat(OldData("old").toConfig()).isEqualTo(config("newValue" to "old"))
}
private inline fun <reified S : SingleData<V>, reified L : ListData<V>, V : Any> testPropertyType(
@ -177,6 +194,7 @@ class ConfigParsingTest {
val config = config("value" to if (valueToString) value.toString() else value)
val data = constructor.call(value)
assertThat(config.parseAs<T>().value).isEqualTo(data.value)
assertThat(data.toConfig()).isEqualTo(config)
}
private inline fun <reified T : ListData<V>, V : Any> testListProperty(value1: V, value2: V, valuesToString: Boolean) {
@ -187,6 +205,7 @@ class ConfigParsingTest {
val config = config("values" to configValues.take(n))
val data = constructor.call(rawValues.take(n))
assertThat(config.parseAs<T>().values).isEqualTo(data.values)
assertThat(data.toConfig()).isEqualTo(config)
}
assertThat(empty().parseAs<T>().values).isEmpty()
}
@ -228,8 +247,8 @@ class ConfigParsingTest {
data class PathListData(override val values: List<Path>) : ListData<Path>
data class URLData(override val value: URL) : SingleData<URL>
data class URLListData(override val values: List<URL>) : ListData<URL>
data class X500NameData(override val value: CordaX500Name) : SingleData<CordaX500Name>
data class X500NameListData(override val values: List<CordaX500Name>) : ListData<CordaX500Name>
data class CordaX500NameData(override val value: CordaX500Name) : SingleData<CordaX500Name>
data class CordaX500NameListData(override val values: List<CordaX500Name>) : ListData<CordaX500Name>
data class PropertiesData(override val value: Properties) : SingleData<Properties>
data class PropertiesListData(override val values: List<Properties>) : ListData<Properties>
data class MultiPropertyData(val i: Int, val b: Boolean, val l: List<String>)
@ -242,5 +261,4 @@ class ConfigParsingTest {
val newValue: String)
enum class TestEnum { Value1, Value2 }
}

View File

@ -7,14 +7,14 @@ import net.corda.core.flows.StartableByRPC
import net.corda.core.internal.concurrent.transpose
import net.corda.core.messaging.startFlow
import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.minutes
import net.corda.finance.DOLLARS
import net.corda.finance.flows.CashIssueFlow
import net.corda.finance.flows.CashPaymentFlow
import net.corda.node.services.FlowPermissions.Companion.startFlowPermission
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.node.services.transactions.SimpleNotaryService
import net.corda.nodeapi.User
import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.chooseIdentity
import net.corda.testing.driver.NodeHandle
import net.corda.testing.driver.driver
@ -103,10 +103,10 @@ class NodePerformanceTests {
@Test
fun `self pay rate`() {
driver(startNodesInProcess = true) {
val a = startNode(
rpcUsers = listOf(User("A", "A", setOf(startFlowPermission<CashIssueFlow>(), startFlowPermission<CashPaymentFlow>()))),
advertisedServices = setOf(ServiceInfo(SimpleNotaryService.type))
).get()
val a = startNotaryNode(
DUMMY_NOTARY.name,
rpcUsers = listOf(User("A", "A", setOf(startFlowPermission<CashIssueFlow>(), startFlowPermission<CashPaymentFlow>())))
).getOrThrow()
a as NodeHandle.InProcess
val metricRegistry = startReporter(shutdownManager, a.node.services.monitoringService.metrics)
a.rpcClientToNode().use("A", "A") { connection ->

View File

@ -18,9 +18,7 @@ import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.loggerFor
import net.corda.node.internal.cordapp.CordappLoader
import net.corda.node.internal.cordapp.CordappProviderImpl
import net.corda.node.services.transactions.SimpleNotaryService
import net.corda.nodeapi.User
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.testing.DUMMY_BANK_A
import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.TestDependencyInjectionBase
@ -120,7 +118,7 @@ class AttachmentLoadingTests : TestDependencyInjectionBase() {
val nodes = listOf(
startNode(providedName = bankAName, rpcUsers = listOf(adminUser)),
startNode(providedName = bankBName, rpcUsers = listOf(adminUser)),
startNode(providedName = notaryName, rpcUsers = listOf(adminUser), advertisedServices = setOf(ServiceInfo(SimpleNotaryService.type)))
startNotaryNode(providedName = notaryName, rpcUsers = listOf(adminUser), validating = false)
).transpose().getOrThrow() // Wait for all nodes to start up.
nodes.forEach { it.rpc.waitUntilNetworkReady().getOrThrow() }
return nodes

View File

@ -10,6 +10,7 @@ import net.corda.core.flows.NotaryException
import net.corda.core.flows.NotaryFlow
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
import net.corda.core.internal.deleteIfExists
import net.corda.core.internal.div
import net.corda.core.transactions.SignedTransaction
import net.corda.core.transactions.TransactionBuilder
@ -18,11 +19,11 @@ import net.corda.core.utilities.Try
import net.corda.core.utilities.getOrThrow
import net.corda.node.internal.StartedNode
import net.corda.node.services.config.BFTSMaRtConfiguration
import net.corda.node.services.config.NotaryConfig
import net.corda.node.services.transactions.BFTNonValidatingNotaryService
import net.corda.node.services.transactions.minClusterSize
import net.corda.node.services.transactions.minCorrectReplicas
import net.corda.node.utilities.ServiceIdentityGenerator
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.testing.chooseIdentity
import net.corda.testing.contracts.DummyContract
import net.corda.testing.dummyCommand
@ -30,14 +31,13 @@ import net.corda.testing.getDefaultNotary
import net.corda.testing.node.MockNetwork
import org.junit.After
import org.junit.Test
import java.nio.file.Files
import java.nio.file.Paths
import kotlin.test.assertEquals
import kotlin.test.assertTrue
class BFTNotaryServiceTests {
companion object {
private val serviceType = BFTNonValidatingNotaryService.type
private val clusterName = CordaX500Name(serviceType.id, "BFT", "Zurich", "CH")
private val clusterName = CordaX500Name(BFTNonValidatingNotaryService.id, "BFT", "Zurich", "CH")
}
private val mockNet = MockNetwork()
@ -49,19 +49,16 @@ class BFTNotaryServiceTests {
}
private fun bftNotaryCluster(clusterSize: Int, exposeRaces: Boolean = false) {
Files.deleteIfExists("config" / "currentView") // XXX: Make config object warn if this exists?
(Paths.get("config") / "currentView").deleteIfExists() // XXX: Make config object warn if this exists?
val replicaIds = (0 until clusterSize)
ServiceIdentityGenerator.generateToDisk(
replicaIds.map { mockNet.baseDirectory(mockNet.nextNodeId + it) },
clusterName)
val bftNotaryService = ServiceInfo(serviceType, clusterName)
val notaryClusterAddresses = replicaIds.map { NetworkHostAndPort("localhost", 11000 + it * 10) }
val clusterAddresses = replicaIds.map { NetworkHostAndPort("localhost", 11000 + it * 10) }
replicaIds.forEach { replicaId ->
mockNet.createNode(
advertisedServices = bftNotaryService,
configOverrides = {
whenever(it.bftSMaRt).thenReturn(BFTSMaRtConfiguration(replicaId, false, exposeRaces))
whenever(it.notaryClusterAddresses).thenReturn(notaryClusterAddresses)
mockNet.createNode(configOverrides = {
val notary = NotaryConfig(validating = false, bftSMaRt = BFTSMaRtConfiguration(replicaId, clusterAddresses, exposeRaces = exposeRaces))
whenever(it.notary).thenReturn(notary)
})
}
mockNet.runNetwork() // Exchange initial network map registration messages.

View File

@ -39,10 +39,9 @@ class DistributedServiceTests : DriverBasedTest() {
)
val aliceFuture = startNode(providedName = ALICE.name, rpcUsers = listOf(testUser))
val notariesFuture = startNotaryCluster(
DUMMY_NOTARY.name.copy(commonName = RaftValidatingNotaryService.type.id),
DUMMY_NOTARY.name.copy(commonName = RaftValidatingNotaryService.id),
rpcUsers = listOf(testUser),
clusterSize = clusterSize,
type = RaftValidatingNotaryService.type
clusterSize = clusterSize
)
alice = aliceFuture.get()

View File

@ -14,8 +14,6 @@ import net.corda.core.utilities.getOrThrow
import net.corda.node.internal.StartedNode
import net.corda.node.services.transactions.RaftValidatingNotaryService
import net.corda.testing.*
import net.corda.testing.DUMMY_BANK_A
import net.corda.testing.chooseIdentity
import net.corda.testing.contracts.DummyContract
import net.corda.testing.node.NodeBasedTest
import org.junit.After
@ -26,7 +24,7 @@ import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
class RaftNotaryServiceTests : NodeBasedTest() {
private val notaryName = CordaX500Name(RaftValidatingNotaryService.type.id, "RAFT Notary Service", "London", "GB")
private val notaryName = CordaX500Name(RaftValidatingNotaryService.id, "RAFT Notary Service", "London", "GB")
@Before
fun setup() {

View File

@ -17,9 +17,6 @@ import net.corda.core.utilities.seconds
import net.corda.node.internal.StartedNode
import net.corda.node.services.messaging.*
import net.corda.node.services.transactions.RaftValidatingNotaryService
import net.corda.node.services.transactions.SimpleNotaryService
import net.corda.node.utilities.ServiceIdentityGenerator
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.testing.*
import net.corda.testing.node.NodeBasedTest
import org.assertj.core.api.Assertions.assertThat
@ -32,8 +29,7 @@ import java.util.concurrent.atomic.AtomicInteger
class P2PMessagingTest : NodeBasedTest() {
private companion object {
val DISTRIBUTED_SERVICE_NAME = CordaX500Name(RaftValidatingNotaryService.type.id, "DistributedService", "London", "GB")
val SERVICE_2_NAME = CordaX500Name(organisation = "Service 2", locality = "London", country = "GB")
val DISTRIBUTED_SERVICE_NAME = CordaX500Name(RaftValidatingNotaryService.id, "DistributedService", "London", "GB")
}
@Test
@ -49,46 +45,6 @@ class P2PMessagingTest : NodeBasedTest() {
startNodes().getOrThrow(timeout = startUpDuration * 3)
}
// https://github.com/corda/corda/issues/71
@Test
fun `communicating with a service running on the network map node`() {
startNetworkMapNode(advertisedServices = setOf(ServiceInfo(SimpleNotaryService.type)))
networkMapNode.respondWith("Hello")
val alice = startNode(ALICE.name).getOrThrow()
val serviceAddress = alice.services.networkMapCache.run {
val notaryParty = notaryIdentities.randomOrNull()!!
alice.network.getAddressOfParty(getPartyInfo(notaryParty)!!)
}
val received = alice.receiveFrom(serviceAddress).getOrThrow(10.seconds)
assertThat(received).isEqualTo("Hello")
}
// TODO Use a dummy distributed service
@Test
fun `communicating with a distributed service which the network map node is part of`() {
ServiceIdentityGenerator.generateToDisk(
listOf(DUMMY_MAP.name, SERVICE_2_NAME).map { baseDirectory(it) },
DISTRIBUTED_SERVICE_NAME)
val distributedService = ServiceInfo(RaftValidatingNotaryService.type, DISTRIBUTED_SERVICE_NAME)
val notaryClusterAddress = freeLocalHostAndPort()
startNetworkMapNode(
DUMMY_MAP.name,
advertisedServices = setOf(distributedService),
configOverrides = mapOf("notaryNodeAddress" to notaryClusterAddress.toString()))
val (serviceNode2, alice) = listOf(
startNode(
SERVICE_2_NAME,
advertisedServices = setOf(distributedService),
configOverrides = mapOf(
"notaryNodeAddress" to freeLocalHostAndPort().toString(),
"notaryClusterAddresses" to listOf(notaryClusterAddress.toString()))),
startNode(ALICE.name)
).transpose().getOrThrow()
assertAllNodesAreUsed(listOf(networkMapNode, serviceNode2), DISTRIBUTED_SERVICE_NAME, alice)
}
@Ignore
@Test
fun `communicating with a distributed service which we're part of`() {

View File

@ -18,8 +18,6 @@ import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.ProgressTracker
import net.corda.core.utilities.getOrThrow
import net.corda.node.services.FlowPermissions
import net.corda.node.services.transactions.SimpleNotaryService
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.nodeapi.User
import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.chooseIdentity
@ -38,8 +36,7 @@ class NodeStatePersistenceTests {
val user = User("mark", "dadada", setOf(FlowPermissions.startFlowPermission<SendMessageFlow>()))
val message = Message("Hello world!")
driver(isDebug = true, startNodesInProcess = isQuasarAgentSpecified()) {
startNode(providedName = DUMMY_NOTARY.name, advertisedServices = setOf(ServiceInfo(SimpleNotaryService.type))).getOrThrow()
startNotaryNode(DUMMY_NOTARY.name, validating = false).getOrThrow()
var nodeHandle = startNode(rpcUsers = listOf(user)).getOrThrow()
val nodeName = nodeHandle.nodeInfo.chooseIdentity().name
nodeHandle.rpcClientToNode().start(user.username, user.password).use {

View File

@ -1,7 +1,6 @@
package net.corda.node.internal
import com.codahale.metrics.MetricRegistry
import com.google.common.collect.Lists
import com.google.common.collect.MutableClassToInstanceMap
import com.google.common.util.concurrent.MoreExecutors
import net.corda.confidential.SwapIdentitiesFlow
@ -41,7 +40,9 @@ import net.corda.node.services.ContractUpgradeHandler
import net.corda.node.services.FinalityHandler
import net.corda.node.services.NotaryChangeHandler
import net.corda.node.services.api.*
import net.corda.node.services.config.BFTSMaRtConfiguration
import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.config.NotaryConfig
import net.corda.node.services.config.configureWithDevSSLCertificate
import net.corda.node.services.events.NodeSchedulerService
import net.corda.node.services.events.ScheduledActivityObserver
@ -66,7 +67,6 @@ import net.corda.node.services.vault.VaultSoftLockManager
import net.corda.node.utilities.*
import net.corda.node.utilities.AddOrRemove.ADD
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.nodeapi.internal.ServiceType
import org.apache.activemq.artemis.utils.ReusableLatch
import org.slf4j.Logger
import rx.Observable
@ -456,7 +456,7 @@ abstract class AbstractNode(config: NodeConfiguration,
_services = ServiceHubInternalImpl(schemaService)
attachments = NodeAttachmentService(services.monitoringService.metrics)
cordappProvider.start(attachments)
legalIdentity = obtainIdentity()
legalIdentity = obtainIdentity(notaryConfig = null)
network = makeMessagingService(legalIdentity)
info = makeInfo(legalIdentity)
val networkMapCache = services.networkMapCache
@ -500,19 +500,10 @@ abstract class AbstractNode(config: NodeConfiguration,
}
/**
* A service entry contains the advertised [ServiceInfo] along with the service identity. The identity *name* is
* taken from the configuration or, if non specified, generated by combining the node's legal name and the service id.
* Used only for notary identities.
* Obtain the node's notary identity if it's configured to be one. If part of a distributed notary then this will be
* the distributed identity shared across all the nodes of the cluster.
*/
protected open fun getNotaryIdentity(): PartyAndCertificate? {
return advertisedServices.singleOrNull { it.type.isNotary() }?.let {
it.name?.let {
require(it.commonName != null) {"Common name in '$it' must not be null for notary service, use service type id as common name."}
require(ServiceType.parse(it.commonName!!).isNotary()) {"Common name for notary service in '$it' must be the notary service type id."}
}
obtainIdentity(it)
}
}
protected fun getNotaryIdentity(): PartyAndCertificate? = configuration.notary?.let { obtainIdentity(it) }
@VisibleForTesting
protected open fun acceptableLiveFiberCountOnStop(): Int = 0
@ -558,22 +549,14 @@ abstract class AbstractNode(config: NodeConfiguration,
}
private fun makeNetworkServices(network: MessagingService, networkMapCache: NetworkMapCacheInternal, tokenizableServices: MutableList<Any>) {
val serviceTypes = advertisedServices.map { it.type }
inNodeNetworkMapService = if (configuration.networkMapService == null) makeNetworkMapService(network, networkMapCache) else NullNetworkMapService
val notaryServiceType = serviceTypes.singleOrNull { it.isNotary() }
if (notaryServiceType != null) {
val service = makeCoreNotaryService(notaryServiceType)
if (service != null) {
service.apply {
tokenizableServices.add(this)
runOnStop += this::stop
start()
}
installCoreFlow(NotaryFlow.Client::class, service::createServiceFlow)
} else {
log.info("Notary type ${notaryServiceType.id} does not match any built-in notary types. " +
"It is expected to be loaded via a CorDapp")
}
configuration.notary?.let {
val notaryService = makeCoreNotaryService(it)
tokenizableServices.add(notaryService)
runOnStop += notaryService::stop
installCoreFlow(NotaryFlow.Client::class, notaryService::createServiceFlow)
log.info("Running core notary: ${notaryService.javaClass.name}")
notaryService.start()
}
}
@ -640,15 +623,33 @@ abstract class AbstractNode(config: NodeConfiguration,
abstract protected fun makeNetworkMapService(network: MessagingService, networkMapCache: NetworkMapCacheInternal): NetworkMapService
open protected fun makeCoreNotaryService(type: ServiceType): NotaryService? {
check(myNotaryIdentity != null) { "No notary identity initialized when creating a notary service" }
return when (type) {
SimpleNotaryService.type -> SimpleNotaryService(services, myNotaryIdentity!!.owningKey)
ValidatingNotaryService.type -> ValidatingNotaryService(services, myNotaryIdentity!!.owningKey)
RaftNonValidatingNotaryService.type -> RaftNonValidatingNotaryService(services, myNotaryIdentity!!.owningKey)
RaftValidatingNotaryService.type -> RaftValidatingNotaryService(services, myNotaryIdentity!!.owningKey)
BFTNonValidatingNotaryService.type -> BFTNonValidatingNotaryService(services, myNotaryIdentity!!.owningKey)
else -> null
private fun makeCoreNotaryService(notaryConfig: NotaryConfig): NotaryService {
val notaryKey = myNotaryIdentity?.owningKey ?: throw IllegalArgumentException("No notary identity initialized when creating a notary service")
return if (notaryConfig.validating) {
if (notaryConfig.raft != null) {
RaftValidatingNotaryService(services, notaryKey, notaryConfig.raft)
} else if (notaryConfig.bftSMaRt != null) {
throw IllegalArgumentException("Validating BFTSMaRt notary not supported")
} else {
ValidatingNotaryService(services, notaryKey)
}
} else {
if (notaryConfig.raft != null) {
RaftNonValidatingNotaryService(services, notaryKey, notaryConfig.raft)
} else if (notaryConfig.bftSMaRt != null) {
val cluster = makeBFTCluster(notaryKey, notaryConfig.bftSMaRt)
BFTNonValidatingNotaryService(services, notaryKey, notaryConfig.bftSMaRt, cluster)
} else {
SimpleNotaryService(services, notaryKey)
}
}
}
protected open fun makeBFTCluster(notaryKey: PublicKey, bftSMaRtConfig: BFTSMaRtConfiguration): BFTSMaRt.Cluster {
return object : BFTSMaRt.Cluster {
override fun waitUntilAllReplicasHaveInitialized() {
log.warn("A BFT replica may still be initializing, in which case the upcoming consensus change may cause it to spin.")
}
}
}
@ -691,29 +692,32 @@ abstract class AbstractNode(config: NodeConfiguration,
protected abstract fun startMessagingService(rpcOps: RPCOps)
private fun obtainIdentity(serviceInfo: ServiceInfo? = null): PartyAndCertificate {
// Load the private identity key, creating it if necessary. The identity key is a long term well known key that
// is distributed to other peers and we use it (or a key signed by it) when we need to do something
// "permissioned". The identity file is what gets distributed and contains the node's legal name along with
// the public key. Obviously in a real system this would need to be a certificate chain of some kind to ensure
// the legal name is actually validated in some way.
private fun obtainIdentity(notaryConfig: NotaryConfig?): PartyAndCertificate {
val keyStore = KeyStoreWrapper(configuration.nodeKeystore, configuration.keyStorePassword)
val (id, name) = if (serviceInfo == null) {
// Create node identity if service info = null
val (id, singleName) = if (notaryConfig == null) {
// Node's main identity
Pair("identity", myLegalName)
} else {
val name = serviceInfo.name ?: myLegalName.copy(commonName = serviceInfo.type.id)
Pair(serviceInfo.type.id, name)
val notaryId = notaryConfig.run { NotaryService.constructId(validating, raft != null, bftSMaRt != null) }
if (notaryConfig.bftSMaRt == null && notaryConfig.raft == null) {
// Node's notary identity
Pair(notaryId, myLegalName.copy(commonName = notaryId))
} else {
// The node is part of a distributed notary whose identity must already be generated beforehand
Pair(notaryId, null)
}
}
// TODO: Integrate with Key management service?
val privateKeyAlias = "$id-private-key"
if (!keyStore.containsAlias(privateKeyAlias)) {
singleName ?: throw IllegalArgumentException(
"Unable to find in the key store the identity of the distributed notary ($id) the node is part of")
// TODO: Remove use of [ServiceIdentityGenerator.generateToDisk].
log.info("$privateKeyAlias not found in key store ${configuration.nodeKeystore}, generating fresh key!")
keyStore.signAndSaveNewKeyPair(name, privateKeyAlias, generateKeyPair())
keyStore.signAndSaveNewKeyPair(singleName, privateKeyAlias, generateKeyPair())
}
val (x509Cert, keys) = keyStore.certificateAndKeyPair(privateKeyAlias)
@ -726,7 +730,7 @@ abstract class AbstractNode(config: NodeConfiguration,
// We have to create the certificate chain for the composite key manually, this is because we don't have a keystore
// provider that understand compositeKey-privateKey combo. The cert chain is created using the composite key certificate +
// the tail of the private key certificates, as they are both signed by the same certificate chain.
Lists.asList(certificate, keyStore.getCertificateChain(privateKeyAlias).drop(1).toTypedArray())
listOf(certificate) + keyStore.getCertificateChain(privateKeyAlias).drop(1)
} else {
keyStore.getCertificateChain(privateKeyAlias).let {
check(it[0].toX509CertHolder() == x509Cert) { "Certificates from key store do not line up!" }
@ -736,8 +740,11 @@ abstract class AbstractNode(config: NodeConfiguration,
val nodeCert = certificates[0] as? X509Certificate ?: throw ConfigurationException("Node certificate must be an X.509 certificate")
val subject = CordaX500Name.build(nodeCert.subjectX500Principal)
if (subject != name)
throw ConfigurationException("The name '$name' for $id doesn't match what's in the key store: $subject")
// TODO Include the name of the distributed notary, which the node is part of, in the notary config so that we
// can cross-check the identity we get from the key store
if (singleName != null && subject != singleName) {
throw ConfigurationException("The name '$singleName' for $id doesn't match what's in the key store: $subject")
}
partyKeys += keys
return PartyAndCertificate(CertificateFactory.getInstance("X509").generateCertPath(certificates))

View File

@ -99,7 +99,7 @@ open class NodeStartup(val args: Array<String>) {
return
}
val startedNode = node.start()
printPluginsAndServices(startedNode.internals)
Node.printBasicNodeInfo("Loaded CorDapps", startedNode.internals.cordappProvider.cordapps.joinToString { it.name })
startedNode.internals.nodeReadyFuture.thenMatch({
val elapsed = (System.currentTimeMillis() - startTime) / 10 / 100.0
val name = startedNode.info.legalIdentitiesAndCerts.first().name.organisation
@ -165,7 +165,7 @@ open class NodeStartup(val args: Array<String>) {
}
open protected fun banJavaSerialisation(conf: FullNodeConfiguration) {
SerialFilter.install(if (conf.bftSMaRt.isValid()) ::bftSMaRtSerialFilter else ::defaultSerialFilter)
SerialFilter.install(if (conf.notary?.bftSMaRt != null) ::bftSMaRtSerialFilter else ::defaultSerialFilter)
}
open protected fun getVersionInfo(): VersionInfo {
@ -263,13 +263,6 @@ open class NodeStartup(val args: Array<String>) {
}
}
private fun printPluginsAndServices(node: Node) {
node.configuration.extraAdvertisedServiceIds.filter { it.startsWith("corda.notary.") }.let {
if (it.isNotEmpty()) Node.printBasicNodeInfo("Providing additional services", it.joinToString())
}
Node.printBasicNodeInfo("Loaded CorDapps", node.cordappProvider.cordapps.joinToString { it.name })
}
open fun drawBanner(versionInfo: VersionInfo) {
// This line makes sure ANSI escapes work on Windows, where they aren't supported out of the box.
AnsiConsole.systemInstall()

View File

@ -6,17 +6,11 @@ import net.corda.node.internal.NetworkMapInfo
import net.corda.node.services.messaging.CertificateChainCheckPolicy
import net.corda.nodeapi.User
import net.corda.nodeapi.config.NodeSSLConfiguration
import net.corda.nodeapi.config.OldConfig
import net.corda.nodeapi.internal.ServiceInfo
import java.net.URL
import java.nio.file.Path
import java.util.*
/** @param exposeRaces for testing only, so its default is not in reference.conf but here. */
data class BFTSMaRtConfiguration(val replicaId: Int, val debug: Boolean, val exposeRaces: Boolean = false) {
fun isValid() = replicaId >= 0
}
interface NodeConfiguration : NodeSSLConfiguration {
// myLegalName should be only used in the initial network registration, we should use the name from the certificate instead of this.
// TODO: Remove this so we don't accidentally use this identity in the code?
@ -37,17 +31,31 @@ interface NodeConfiguration : NodeSSLConfiguration {
val certificateChainCheckPolicies: List<CertChainPolicyConfig>
val verifierType: VerifierType
val messageRedeliveryDelaySeconds: Int
val bftSMaRt: BFTSMaRtConfiguration
val notaryNodeAddress: NetworkHostAndPort?
val notaryClusterAddresses: List<NetworkHostAndPort>
val notary: NotaryConfig?
val activeMQServer: ActiveMqServerConfiguration
}
data class BridgeConfiguration(
val retryIntervalMs: Long,
data class NotaryConfig(val validating: Boolean, val raft: RaftConfig? = null, val bftSMaRt: BFTSMaRtConfiguration? = null) {
init {
require(raft == null || bftSMaRt == null) { "raft and bftSMaRt configs cannot be specified together" }
}
}
data class RaftConfig(val nodeAddress: NetworkHostAndPort, val clusterAddresses: List<NetworkHostAndPort>)
/** @param exposeRaces for testing only, so its default is not in reference.conf but here. */
data class BFTSMaRtConfiguration constructor(val replicaId: Int,
val clusterAddresses: List<NetworkHostAndPort>,
val debug: Boolean = false,
val exposeRaces: Boolean = false) {
init {
require(replicaId >= 0) { "replicaId cannot be negative" }
}
}
data class BridgeConfiguration(val retryIntervalMs: Long,
val maxRetryIntervalMin: Long,
val retryIntervalMultiplier: Double
)
val retryIntervalMultiplier: Double)
data class ActiveMqServerConfiguration(val bridge: BridgeConfiguration)
@ -67,16 +75,13 @@ data class FullNodeConfiguration(
override val verifierType: VerifierType,
override val messageRedeliveryDelaySeconds: Int = 30,
val useHTTPS: Boolean,
@OldConfig("artemisAddress")
val p2pAddress: NetworkHostAndPort,
val rpcAddress: NetworkHostAndPort?,
// TODO This field is slightly redundant as p2pAddress is sufficient to hold the address of the node's MQ broker.
// Instead this should be a Boolean indicating whether that broker is an internal one started by the node or an external one
val messagingServerAddress: NetworkHostAndPort?,
val extraAdvertisedServiceIds: List<String>,
override val bftSMaRt: BFTSMaRtConfiguration,
override val notaryNodeAddress: NetworkHostAndPort?,
override val notaryClusterAddresses: List<NetworkHostAndPort>,
override val notary: NotaryConfig?,
override val certificateChainCheckPolicies: List<CertChainPolicyConfig>,
override val devMode: Boolean = false,
val useTestClock: Boolean = false,

View File

@ -13,6 +13,7 @@ import net.corda.core.messaging.DataFeed
import net.corda.core.messaging.SingleMessageRecipient
import net.corda.core.node.NodeInfo
import net.corda.core.node.services.NetworkMapCache.MapChange
import net.corda.core.node.services.NotaryService
import net.corda.core.node.services.PartyInfo
import net.corda.core.schemas.NodeInfoSchemaV1
import net.corda.core.serialization.SingletonSerializeAsToken
@ -81,10 +82,8 @@ open class PersistentNetworkMapCache(private val serviceHub: ServiceHubInternal)
// Notary certificates have to be signed by the doorman directly
it.legalIdentities
}
.filter {
it.name.toString().contains("corda.notary", true)
}
.distinct() // Distinct, because of distributed service nodes
.filter { it.name.commonName?.startsWith(NotaryService.ID_PREFIX) ?: false }
.toSet() // Distinct, because of distributed service nodes
.sortedBy { it.name.toString() }
}

View File

@ -20,10 +20,12 @@ import net.corda.core.serialization.serialize
import net.corda.core.transactions.FilteredTransaction
import net.corda.core.utilities.*
import net.corda.node.services.api.ServiceHubInternal
import net.corda.node.services.config.BFTSMaRtConfiguration
import net.corda.node.utilities.AppendOnlyPersistentMap
import net.corda.node.utilities.NODE_DATABASE_PREFIX
import java.security.PublicKey
import javax.persistence.Entity
import javax.persistence.Table
import kotlin.concurrent.thread
/**
@ -33,24 +35,19 @@ import kotlin.concurrent.thread
*/
class BFTNonValidatingNotaryService(override val services: ServiceHubInternal,
override val notaryIdentityKey: PublicKey,
cluster: BFTSMaRt.Cluster = distributedCluster) : NotaryService() {
private val bftSMaRtConfig: BFTSMaRtConfiguration,
cluster: BFTSMaRt.Cluster) : NotaryService() {
companion object {
val type = SimpleNotaryService.type.getSubType("bft")
val id = constructId(validating = false, bft = true)
private val log = loggerFor<BFTNonValidatingNotaryService>()
private val distributedCluster = object : BFTSMaRt.Cluster {
override fun waitUntilAllReplicasHaveInitialized() {
log.warn("A replica may still be initializing, in which case the upcoming consensus change may cause it to spin.")
}
}
}
private val client: BFTSMaRt.Client
private val replicaHolder = SettableFuture.create<Replica>()
init {
require(services.configuration.bftSMaRt.isValid()) { "bftSMaRt replicaId must be specified in the configuration" }
client = BFTSMaRtConfig(services.configuration.notaryClusterAddresses, services.configuration.bftSMaRt.debug, services.configuration.bftSMaRt.exposeRaces).use {
val replicaId = services.configuration.bftSMaRt.replicaId
client = BFTSMaRtConfig(bftSMaRtConfig.clusterAddresses, bftSMaRtConfig.debug, bftSMaRtConfig.exposeRaces).use {
val replicaId = bftSMaRtConfig.replicaId
val configHandle = it.handle()
// Replica startup must be in parallel with other replicas, otherwise the constructor may not return:
thread(name = "BFT SMaRt replica $replicaId init", isDaemon = true) {
@ -66,7 +63,7 @@ class BFTNonValidatingNotaryService(override val services: ServiceHubInternal,
}
fun waitUntilReplicaHasInitialized() {
log.debug { "Waiting for replica ${services.configuration.bftSMaRt.replicaId} to initialize." }
log.debug { "Waiting for replica ${bftSMaRtConfig.replicaId} to initialize." }
replicaHolder.getOrThrow() // It's enough to wait for the ServiceReplica constructor to return.
}
@ -96,12 +93,12 @@ class BFTNonValidatingNotaryService(override val services: ServiceHubInternal,
}
@Entity
@javax.persistence.Table(name = "${NODE_DATABASE_PREFIX}bft_smart_notary_committed_states")
@Table(name = "${NODE_DATABASE_PREFIX}bft_smart_notary_committed_states")
class PersistedCommittedState(id: PersistentStateRef, consumingTxHash: String, consumingIndex: Int, party: PersistentUniquenessProvider.PersistentParty)
: PersistentUniquenessProvider.PersistentUniqueness(id, consumingTxHash, consumingIndex, party)
fun createMap(): AppendOnlyPersistentMap<StateRef, UniquenessProvider.ConsumingTx, PersistedCommittedState, PersistentStateRef> =
AppendOnlyPersistentMap(
private fun createMap(): AppendOnlyPersistentMap<StateRef, UniquenessProvider.ConsumingTx, PersistedCommittedState, PersistentStateRef> {
return AppendOnlyPersistentMap(
toPersistentEntityKey = { PersistentStateRef(it.txhash.toString(), it.index) },
fromPersistentEntity = {
//TODO null check will become obsolete after making DB/JPA columns not nullable
@ -126,6 +123,7 @@ class BFTNonValidatingNotaryService(override val services: ServiceHubInternal,
},
persistentEntityClass = PersistedCommittedState::class.java
)
}
private class Replica(config: BFTSMaRtConfig,
replicaId: Int,

View File

@ -5,18 +5,23 @@ import net.corda.core.flows.NotaryFlow
import net.corda.core.node.services.TimeWindowChecker
import net.corda.core.node.services.TrustedAuthorityNotaryService
import net.corda.node.services.api.ServiceHubInternal
import net.corda.node.services.config.RaftConfig
import java.security.PublicKey
/** A non-validating notary service operated by a group of mutually trusting parties, uses the Raft algorithm to achieve consensus. */
class RaftNonValidatingNotaryService(override val services: ServiceHubInternal, override val notaryIdentityKey: PublicKey) : TrustedAuthorityNotaryService() {
class RaftNonValidatingNotaryService(override val services: ServiceHubInternal,
override val notaryIdentityKey: PublicKey,
raftConfig: RaftConfig) : TrustedAuthorityNotaryService() {
companion object {
val type = SimpleNotaryService.type.getSubType("raft")
val id = constructId(validating = false, raft = true)
}
override val timeWindowChecker: TimeWindowChecker = TimeWindowChecker(services.clock)
override val uniquenessProvider: RaftUniquenessProvider = RaftUniquenessProvider(services)
override val uniquenessProvider: RaftUniquenessProvider = RaftUniquenessProvider(services, raftConfig)
override fun createServiceFlow(otherPartySession: FlowSession): NotaryFlow.Service = NonValidatingNotaryFlow(otherPartySession, this)
override fun createServiceFlow(otherPartySession: FlowSession): NotaryFlow.Service {
return NonValidatingNotaryFlow(otherPartySession, this)
}
override fun start() {
uniquenessProvider.start()

View File

@ -26,16 +26,14 @@ import net.corda.core.serialization.deserialize
import net.corda.core.serialization.serialize
import net.corda.core.utilities.loggerFor
import net.corda.node.services.api.ServiceHubInternal
import net.corda.node.services.config.RaftConfig
import net.corda.node.utilities.AppendOnlyPersistentMap
import net.corda.node.utilities.CordaPersistence
import net.corda.nodeapi.config.SSLConfiguration
import java.nio.file.Path
import java.util.concurrent.CompletableFuture
import javax.annotation.concurrent.ThreadSafe
import javax.persistence.Column
import javax.persistence.Entity
import javax.persistence.Id
import javax.persistence.Lob
import javax.persistence.*
/**
* A uniqueness provider that records committed input states in a distributed collection replicated and
@ -46,7 +44,7 @@ import javax.persistence.Lob
* to the cluster leader to be actioned.
*/
@ThreadSafe
class RaftUniquenessProvider(private val services: ServiceHubInternal) : UniquenessProvider, SingletonSerializeAsToken() {
class RaftUniquenessProvider(private val services: ServiceHubInternal, private val raftConfig: RaftConfig) : UniquenessProvider, SingletonSerializeAsToken() {
companion object {
private val log = loggerFor<RaftUniquenessProvider>()
@ -67,7 +65,7 @@ class RaftUniquenessProvider(private val services: ServiceHubInternal) : Uniquen
}
@Entity
@javax.persistence.Table(name = "notary_committed_states")
@Table(name = "notary_committed_states")
class RaftState(
@Id
@Column
@ -81,13 +79,6 @@ class RaftUniquenessProvider(private val services: ServiceHubInternal) : Uniquen
/** Directory storing the Raft log and state machine snapshots */
private val storagePath: Path = services.configuration.baseDirectory
/** Address of the Copycat node run by this Corda node */
private val myAddress = services.configuration.notaryNodeAddress
?: throw IllegalArgumentException("notaryNodeAddress must be specified in configuration")
/**
* List of node addresses in the existing Copycat cluster. At least one active node must be
* provided to join the cluster. If empty, a new cluster will be bootstrapped.
*/
private val clusterAddresses = services.configuration.notaryClusterAddresses
/** The database to store the state machine state in */
private val db: CordaPersistence = services.database
/** SSL configuration */
@ -96,7 +87,6 @@ class RaftUniquenessProvider(private val services: ServiceHubInternal) : Uniquen
private lateinit var _clientFuture: CompletableFuture<CopycatClient>
private lateinit var server: CopycatServer
/**
* Copycat clients are responsible for connecting to the cluster and submitting commands and queries that operate
* on the cluster's replicated state machine.
@ -108,7 +98,7 @@ class RaftUniquenessProvider(private val services: ServiceHubInternal) : Uniquen
log.info("Creating Copycat server, log stored in: ${storagePath.toFile()}")
val stateMachineFactory = {
DistributedImmutableMap(db, RaftUniquenessProvider.Companion::createMap) }
val address = Address(myAddress.host, myAddress.port)
val address = raftConfig.nodeAddress.let { Address(it.host, it.port) }
val storage = buildStorage(storagePath)
val transport = buildTransport(transportConfiguration)
val serializer = Serializer().apply {
@ -142,9 +132,9 @@ class RaftUniquenessProvider(private val services: ServiceHubInternal) : Uniquen
.withSerializer(serializer)
.build()
val serverFuture = if (clusterAddresses.isNotEmpty()) {
log.info("Joining an existing Copycat cluster at $clusterAddresses")
val cluster = clusterAddresses.map { Address(it.host, it.port) }
val serverFuture = if (raftConfig.clusterAddresses.isNotEmpty()) {
log.info("Joining an existing Copycat cluster at ${raftConfig.clusterAddresses}")
val cluster = raftConfig.clusterAddresses.map { Address(it.host, it.port) }
server.join(cluster)
} else {
log.info("Bootstrapping a Copycat cluster at $address")

View File

@ -5,18 +5,23 @@ import net.corda.core.flows.NotaryFlow
import net.corda.core.node.services.TimeWindowChecker
import net.corda.core.node.services.TrustedAuthorityNotaryService
import net.corda.node.services.api.ServiceHubInternal
import net.corda.node.services.config.RaftConfig
import java.security.PublicKey
/** A validating notary service operated by a group of mutually trusting parties, uses the Raft algorithm to achieve consensus. */
class RaftValidatingNotaryService(override val services: ServiceHubInternal, override val notaryIdentityKey: PublicKey) : TrustedAuthorityNotaryService() {
class RaftValidatingNotaryService(override val services: ServiceHubInternal,
override val notaryIdentityKey: PublicKey,
raftConfig: RaftConfig) : TrustedAuthorityNotaryService() {
companion object {
val type = ValidatingNotaryService.type.getSubType("raft")
val id = constructId(validating = true, raft = true)
}
override val timeWindowChecker: TimeWindowChecker = TimeWindowChecker(services.clock)
override val uniquenessProvider: RaftUniquenessProvider = RaftUniquenessProvider(services)
override val uniquenessProvider: RaftUniquenessProvider = RaftUniquenessProvider(services, raftConfig)
override fun createServiceFlow(otherPartySession: FlowSession): NotaryFlow.Service = ValidatingNotaryFlow(otherPartySession, this)
override fun createServiceFlow(otherPartySession: FlowSession): NotaryFlow.Service {
return ValidatingNotaryFlow(otherPartySession, this)
}
override fun start() {
uniquenessProvider.start()

View File

@ -4,16 +4,11 @@ import net.corda.core.flows.FlowSession
import net.corda.core.flows.NotaryFlow
import net.corda.core.node.services.TimeWindowChecker
import net.corda.core.node.services.TrustedAuthorityNotaryService
import net.corda.nodeapi.internal.ServiceType
import net.corda.node.services.api.ServiceHubInternal
import java.security.PublicKey
/** A simple Notary service that does not perform transaction validation */
class SimpleNotaryService(override val services: ServiceHubInternal, override val notaryIdentityKey: PublicKey) : TrustedAuthorityNotaryService() {
companion object {
val type = ServiceType.notary.getSubType("simple")
}
override val timeWindowChecker = TimeWindowChecker(services.clock)
override val uniquenessProvider = PersistentUniquenessProvider()

View File

@ -4,16 +4,14 @@ import net.corda.core.flows.FlowSession
import net.corda.core.flows.NotaryFlow
import net.corda.core.node.services.TimeWindowChecker
import net.corda.core.node.services.TrustedAuthorityNotaryService
import net.corda.nodeapi.internal.ServiceType
import net.corda.node.services.api.ServiceHubInternal
import java.security.PublicKey
/** A Notary service that validates the transaction chain of the submitted transaction before committing it */
class ValidatingNotaryService(override val services: ServiceHubInternal, override val notaryIdentityKey: PublicKey) : TrustedAuthorityNotaryService() {
companion object {
val type = ServiceType.notary.getSubType("validating")
val id = constructId(validating = true)
}
override val timeWindowChecker = TimeWindowChecker(services.clock)
override val uniquenessProvider = PersistentUniquenessProvider()

View File

@ -19,10 +19,6 @@ useHTTPS = false
h2port = 0
useTestClock = false
verifierType = InMemory
bftSMaRt = {
replicaId = -1
debug = false
}
activeMQServer = {
bridge = {
retryIntervalMs = 5000

View File

@ -33,7 +33,7 @@ class CordappSmokeTest {
p2pPort = port.andIncrement,
rpcPort = port.andIncrement,
webPort = port.andIncrement,
extraServices = emptyList(),
isNotary = false,
users = listOf(user)
)

View File

@ -28,9 +28,7 @@ import net.corda.node.internal.StartedNode
import net.corda.node.services.FlowPermissions.Companion.startFlowPermission
import net.corda.node.services.messaging.CURRENT_RPC_CONTEXT
import net.corda.node.services.messaging.RpcContext
import net.corda.node.services.transactions.SimpleNotaryService
import net.corda.nodeapi.User
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.testing.*
import net.corda.testing.node.MockNetwork
import net.corda.testing.node.MockNetwork.MockNode
@ -68,7 +66,7 @@ class CordaRPCOpsImplTest {
mockNet = MockNetwork()
aliceNode = mockNet.createNode()
notaryNode = mockNet.createNode(advertisedServices = ServiceInfo(SimpleNotaryService.type))
notaryNode = mockNet.createNotaryNode(validating = false)
rpc = CordaRPCOpsImpl(aliceNode.services, aliceNode.smm, aliceNode.database)
CURRENT_RPC_CONTEXT.set(RpcContext(User("user", "pwd", permissions = setOf(
startFlowPermission<CashIssueFlow>(),

View File

@ -13,8 +13,6 @@ import net.corda.core.utilities.ProgressTracker
import net.corda.finance.DOLLARS
import net.corda.finance.flows.CashIssueFlow
import net.corda.node.internal.cordapp.DummyRPCFlow
import net.corda.node.services.transactions.ValidatingNotaryService
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.node.MockNetwork
import net.corda.testing.setCordappPackages
@ -23,7 +21,10 @@ import org.junit.After
import org.junit.Before
import org.junit.Test
import java.util.concurrent.atomic.AtomicInteger
import kotlin.test.*
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import kotlin.test.assertNotEquals
import kotlin.test.assertTrue
@StartableByService
class DummyServiceFlow : FlowLogic<FlowInitiator>() {
@ -86,9 +87,7 @@ class CordaServiceTest {
fun start() {
setCordappPackages("net.corda.node.internal","net.corda.finance")
mockNet = MockNetwork(threadPerNode = true)
notaryNode = mockNet.createNode(
legalName = DUMMY_NOTARY.name,
advertisedServices = *arrayOf(ServiceInfo(ValidatingNotaryService.type)))
notaryNode = mockNet.createNotaryNode(legalName = DUMMY_NOTARY.name, validating = true)
nodeA = mockNet.createNode()
mockNet.startNodes()
}

View File

@ -12,8 +12,6 @@ import net.corda.core.transactions.WireTransaction
import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.seconds
import net.corda.node.internal.StartedNode
import net.corda.node.services.transactions.ValidatingNotaryService
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.testing.*
import net.corda.testing.contracts.DummyContract
import net.corda.testing.node.MockNetwork
@ -39,12 +37,10 @@ class NotaryChangeTests {
fun setUp() {
setCordappPackages("net.corda.testing.contracts")
mockNet = MockNetwork()
oldNotaryNode = mockNet.createNode(
legalName = DUMMY_NOTARY.name,
advertisedServices = *arrayOf(ServiceInfo(ValidatingNotaryService.type)))
oldNotaryNode = mockNet.createNotaryNode(legalName = DUMMY_NOTARY.name)
clientNodeA = mockNet.createNode()
clientNodeB = mockNet.createNode()
newNotaryNode = mockNet.createNode(advertisedServices = ServiceInfo(ValidatingNotaryService.type))
newNotaryNode = mockNet.createNotaryNode()
mockNet.runNetwork() // Clear network map registration messages
oldNotaryNode.internals.ensureRegistered()
newNotaryParty = newNotaryNode.info.legalIdentities[1]

View File

@ -30,9 +30,7 @@ class FullNodeConfigurationTest {
rpcAddress = NetworkHostAndPort("localhost", 1),
messagingServerAddress = null,
extraAdvertisedServiceIds = emptyList(),
bftSMaRt = BFTSMaRtConfiguration(-1, false),
notaryNodeAddress = null,
notaryClusterAddresses = emptyList(),
notary = null,
certificateChainCheckPolicies = emptyList(),
devMode = true,
activeMQServer = ActiveMqServerConfiguration(BridgeConfiguration(0, 0, 0.0)))

View File

@ -16,8 +16,6 @@ import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.getOrThrow
import net.corda.node.internal.StartedNode
import net.corda.node.services.statemachine.StateMachineManager
import net.corda.node.services.transactions.ValidatingNotaryService
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.testing.*
import net.corda.testing.contracts.DummyContract
import net.corda.testing.node.MockNetwork
@ -95,9 +93,7 @@ class ScheduledFlowTests {
fun setup() {
setCordappPackages("net.corda.testing.contracts")
mockNet = MockNetwork(threadPerNode = true)
notaryNode = mockNet.createNode(
legalName = DUMMY_NOTARY.name,
advertisedServices = *arrayOf(ServiceInfo(ValidatingNotaryService.type)))
notaryNode = mockNet.createNotaryNode(legalName = DUMMY_NOTARY.name)
val a = mockNet.createUnstartedNode()
val b = mockNet.createUnstartedNode()

View File

@ -6,10 +6,8 @@ import co.paralleluniverse.strands.concurrent.Semaphore
import net.corda.core.concurrent.CordaFuture
import net.corda.core.contracts.ContractState
import net.corda.core.contracts.StateAndRef
import net.corda.core.crypto.generateKeyPair
import net.corda.core.crypto.random63BitValue
import net.corda.core.flows.*
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
import net.corda.core.internal.concurrent.flatMap
import net.corda.core.internal.concurrent.map
@ -21,23 +19,16 @@ import net.corda.core.serialization.serialize
import net.corda.core.toFuture
import net.corda.core.transactions.SignedTransaction
import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.ProgressTracker
import net.corda.core.utilities.ProgressTracker.Change
import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.unwrap
import net.corda.finance.DOLLARS
import net.corda.finance.flows.CashIssueFlow
import net.corda.finance.flows.CashPaymentFlow
import net.corda.node.internal.InitiatedFlowFactory
import net.corda.node.internal.StartedNode
import net.corda.node.services.persistence.checkpoints
import net.corda.node.services.transactions.ValidatingNotaryService
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.testing.*
import net.corda.testing.contracts.DummyContract
import net.corda.testing.contracts.DummyState
import net.corda.testing.node.InMemoryMessagingNetwork
import net.corda.testing.node.InMemoryMessagingNetwork.MessageTransfer
import net.corda.testing.node.InMemoryMessagingNetwork.ServicePeerAllocationStrategy.RoundRobin
import net.corda.testing.node.MockNetwork
@ -69,10 +60,8 @@ class FlowFrameworkTests {
private val receivedSessionMessages = ArrayList<SessionTransfer>()
private lateinit var node1: StartedNode<MockNode>
private lateinit var node2: StartedNode<MockNode>
private lateinit var notary1: StartedNode<MockNode>
private lateinit var notary2: StartedNode<MockNode>
private lateinit var notary1Identity: Party
private lateinit var notary2Identity: Party
private lateinit var notary: StartedNode<MockNode>
private lateinit var notaryIdentity: Party
@Before
fun start() {
@ -85,19 +74,13 @@ class FlowFrameworkTests {
node1.internals.ensureRegistered()
// We intentionally create our own notary and ignore the one provided by the network
val notaryKeyPair = generateKeyPair()
val notaryService = ServiceInfo(ValidatingNotaryService.type, CordaX500Name(commonName = ValidatingNotaryService.type.id, organisation = "Notary service 2000", locality = "London", country = "GB"))
val notaryIdentityOverride = Pair(notaryService, notaryKeyPair)
// Note that these notaries don't operate correctly as they don't share their state. They are only used for testing
// service addressing.
notary1 = mockNet.createNotaryNode(notaryIdentity = notaryIdentityOverride, serviceName = notaryService.name)
notary2 = mockNet.createNotaryNode(notaryIdentity = notaryIdentityOverride, serviceName = notaryService.name)
notary = mockNet.createNotaryNode()
receivedSessionMessagesObservable().forEach { receivedSessionMessages += it }
mockNet.runNetwork()
notary1Identity = notary1.services.myInfo.legalIdentities[1]
notary2Identity = notary2.services.myInfo.legalIdentities[1]
notaryIdentity = notary.services.myInfo.legalIdentities[1]
}
@After
@ -335,62 +318,6 @@ class FlowFrameworkTests {
)
}
@Test
fun `different notaries are picked when addressing shared notary identity`() {
assertEquals(notary1Identity, notary2Identity)
assertThat(node1.services.networkMapCache.notaryIdentities.size == 1)
node1.services.startFlow(CashIssueFlow(
2000.DOLLARS,
OpaqueBytes.of(0x01),
notary1Identity)).resultFuture.getOrThrow()
// We pay a couple of times, the notary picking should go round robin
for (i in 1..3) {
val flow = node1.services.startFlow(CashPaymentFlow(500.DOLLARS, node2.info.chooseIdentity()))
mockNet.runNetwork()
flow.resultFuture.getOrThrow()
}
val endpoint = mockNet.messagingNetwork.endpoint(notary1.network.myAddress as InMemoryMessagingNetwork.PeerHandle)!!
val party1Info = notary1.services.networkMapCache.getPartyInfo(notary1Identity)!!
assertTrue(party1Info is PartyInfo.DistributedNode)
val notary1Address: MessageRecipients = endpoint.getAddressOfParty(notary1.services.networkMapCache.getPartyInfo(notary1Identity)!!)
assertThat(notary1Address).isInstanceOf(InMemoryMessagingNetwork.ServiceHandle::class.java)
assertEquals(notary1Address, endpoint.getAddressOfParty(notary2.services.networkMapCache.getPartyInfo(notary2Identity)!!))
receivedSessionMessages.expectEvents(isStrict = false) {
sequence(
// First Pay
expect(match = { it.message is SessionInit && it.message.initiatingFlowClass == NotaryFlow.Client::class.java.name }) {
it.message as SessionInit
assertEquals(node1.internals.id, it.from)
assertEquals(notary1Address, it.to)
},
expect(match = { it.message is SessionConfirm }) {
it.message as SessionConfirm
assertEquals(notary1.internals.id, it.from)
},
// Second pay
expect(match = { it.message is SessionInit && it.message.initiatingFlowClass == NotaryFlow.Client::class.java.name }) {
it.message as SessionInit
assertEquals(node1.internals.id, it.from)
assertEquals(notary1Address, it.to)
},
expect(match = { it.message is SessionConfirm }) {
it.message as SessionConfirm
assertEquals(notary2.internals.id, it.from)
},
// Third pay
expect(match = { it.message is SessionInit && it.message.initiatingFlowClass == NotaryFlow.Client::class.java.name }) {
it.message as SessionInit
assertEquals(node1.internals.id, it.from)
assertEquals(notary1Address, it.to)
},
expect(match = { it.message is SessionConfirm }) {
it.message as SessionConfirm
assertEquals(it.from, notary1.internals.id)
}
)
}
}
@Test
fun `other side ends before doing expected send`() {
node2.registerFlowFactory(ReceiveFlow::class) { NoOpFlow() }
@ -604,7 +531,7 @@ class FlowFrameworkTests {
@Test
fun `wait for transaction`() {
val ptx = TransactionBuilder(notary = notary1Identity)
val ptx = TransactionBuilder(notary = notaryIdentity)
.addOutputState(DummyState(), DummyContract.PROGRAM_ID)
.addCommand(dummyCommand(node1.info.chooseIdentity().owningKey))
val stx = node1.services.signInitialTransaction(ptx)
@ -619,7 +546,7 @@ class FlowFrameworkTests {
@Test
fun `committer throws exception before calling the finality flow`() {
val ptx = TransactionBuilder(notary = notary1Identity)
val ptx = TransactionBuilder(notary = notaryIdentity)
.addOutputState(DummyState(), DummyContract.PROGRAM_ID)
.addCommand(dummyCommand())
val stx = node1.services.signInitialTransaction(ptx)
@ -636,7 +563,7 @@ class FlowFrameworkTests {
@Test
fun `verify vault query service is tokenizable by force checkpointing within a flow`() {
val ptx = TransactionBuilder(notary = notary1Identity)
val ptx = TransactionBuilder(notary = notaryIdentity)
.addOutputState(DummyState(), DummyContract.PROGRAM_ID)
.addCommand(dummyCommand(node1.info.chooseIdentity().owningKey))
val stx = node1.services.signInitialTransaction(ptx)

View File

@ -13,7 +13,6 @@ import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.seconds
import net.corda.node.internal.StartedNode
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.testing.*
import net.corda.testing.contracts.DummyContract
import net.corda.testing.node.MockNetwork
@ -36,9 +35,7 @@ class NotaryServiceTests {
fun setup() {
setCordappPackages("net.corda.testing.contracts")
mockNet = MockNetwork()
notaryNode = mockNet.createNode(
legalName = DUMMY_NOTARY.name,
advertisedServices = *arrayOf(ServiceInfo(SimpleNotaryService.type)))
notaryNode = mockNet.createNotaryNode(legalName = DUMMY_NOTARY.name, validating = false)
clientNode = mockNet.createNode()
mockNet.runNetwork() // Clear network map registration messages
notaryNode.internals.ensureRegistered()

View File

@ -14,7 +14,6 @@ import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.getOrThrow
import net.corda.node.internal.StartedNode
import net.corda.node.services.issueInvalidState
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.testing.*
import net.corda.testing.contracts.DummyContract
import net.corda.testing.node.MockNetwork
@ -36,10 +35,7 @@ class ValidatingNotaryServiceTests {
fun setup() {
setCordappPackages("net.corda.testing.contracts")
mockNet = MockNetwork()
notaryNode = mockNet.createNode(
legalName = DUMMY_NOTARY.name,
advertisedServices = *arrayOf(ServiceInfo(ValidatingNotaryService.type))
)
notaryNode = mockNet.createNotaryNode(legalName = DUMMY_NOTARY.name)
clientNode = mockNet.createNode()
mockNet.runNetwork() // Clear network map registration messages
notaryNode.internals.ensureRegistered()

View File

@ -40,7 +40,8 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
networkMap "O=Notary Service,L=Zurich,C=CH"
node {
name "O=Notary Service,L=Zurich,C=CH"
advertisedServices["corda.notary.validating"]
notary = [validating : true]
advertisedServices = []
p2pPort 10002
rpcPort 10003
cordapps = []

View File

@ -2,9 +2,7 @@ package net.corda.attachmentdemo
import net.corda.core.utilities.getOrThrow
import net.corda.node.services.FlowPermissions.Companion.startFlowPermission
import net.corda.node.services.transactions.SimpleNotaryService
import net.corda.nodeapi.User
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.testing.DUMMY_BANK_A
import net.corda.testing.DUMMY_BANK_B
import net.corda.testing.DUMMY_NOTARY
@ -22,7 +20,7 @@ class AttachmentDemoTest {
val (nodeA, nodeB) = listOf(
startNode(providedName = DUMMY_BANK_A.name, rpcUsers = demoUser, maximumHeapSize = "1g"),
startNode(providedName = DUMMY_BANK_B.name, rpcUsers = demoUser, maximumHeapSize = "1g"),
startNode(providedName = DUMMY_NOTARY.name, advertisedServices = setOf(ServiceInfo(SimpleNotaryService.type))))
startNotaryNode(DUMMY_NOTARY.name, validating = false))
.map { it.getOrThrow() }
startWebserver(nodeB).getOrThrow()

View File

@ -1,12 +1,10 @@
package net.corda.attachmentdemo
import net.corda.core.internal.div
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.nodeapi.User
import net.corda.testing.DUMMY_BANK_A
import net.corda.testing.DUMMY_BANK_B
import net.corda.testing.DUMMY_NOTARY
import net.corda.node.services.transactions.SimpleNotaryService
import net.corda.nodeapi.User
import net.corda.testing.driver.driver
/**
@ -16,7 +14,7 @@ import net.corda.testing.driver.driver
fun main(args: Array<String>) {
val demoUser = listOf(User("demo", "demo", setOf("StartFlow.net.corda.flows.FinalityFlow")))
driver(isDebug = true, driverDirectory = "build" / "attachment-demo-nodes") {
startNode(providedName = DUMMY_NOTARY.name, advertisedServices = setOf(ServiceInfo(SimpleNotaryService.type)))
startNotaryNode(DUMMY_NOTARY.name, validating = false)
startNode(providedName = DUMMY_BANK_A.name, rpcUsers = demoUser)
startNode(providedName = DUMMY_BANK_B.name, rpcUsers = demoUser)
waitForAllNodesToFinish()

View File

@ -53,7 +53,8 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
networkMap "O=Notary Service,L=Zurich,C=CH"
node {
name "O=Notary Service,L=Zurich,C=CH"
advertisedServices = ["corda.notary.validating"]
notary = [validating : true]
advertisedServices = []
p2pPort 10002
rpcPort 10003
cordapps = ["net.corda:finance:$corda_release_version"]

View File

@ -3,8 +3,6 @@ package net.corda.bank
import net.corda.bank.api.BankOfCordaClientApi
import net.corda.bank.api.BankOfCordaWebApi.IssueRequestParams
import net.corda.core.utilities.getOrThrow
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.node.services.transactions.SimpleNotaryService
import net.corda.testing.BOC
import net.corda.testing.driver.driver
import net.corda.testing.notary
@ -16,7 +14,7 @@ class BankOfCordaHttpAPITest {
fun `issuer flow via Http`() {
driver(extraCordappPackagesToScan = listOf("net.corda.finance"), dsl = {
val bigCorpNodeFuture = startNode(providedName = BIGCORP_LEGAL_NAME)
val nodeBankOfCordaFuture = startNode(providedName = BOC.name, advertisedServices = setOf(ServiceInfo(SimpleNotaryService.type)))
val nodeBankOfCordaFuture = startNotaryNode(BOC.name, validating = false)
val (nodeBankOfCorda) = listOf(nodeBankOfCordaFuture, bigCorpNodeFuture).map { it.getOrThrow() }
val nodeBankOfCordaApiAddr = startWebserver(nodeBankOfCorda).getOrThrow().listenAddress
val notaryName = notary().node.nodeInfo.legalIdentities[1].name

View File

@ -8,8 +8,6 @@ import net.corda.finance.DOLLARS
import net.corda.finance.contracts.asset.Cash
import net.corda.finance.flows.CashIssueAndPaymentFlow
import net.corda.node.services.FlowPermissions.Companion.startFlowPermission
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.node.services.transactions.SimpleNotaryService
import net.corda.nodeapi.User
import net.corda.testing.*
import net.corda.testing.driver.driver
@ -22,7 +20,7 @@ class BankOfCordaRPCClientTest {
val bocManager = User("bocManager", "password1", permissions = setOf(
startFlowPermission<CashIssueAndPaymentFlow>()))
val bigCorpCFO = User("bigCorpCFO", "password2", permissions = emptySet())
val nodeBankOfCordaFuture = startNode(providedName = BOC.name, advertisedServices = setOf(ServiceInfo(SimpleNotaryService.type)), rpcUsers = listOf(bocManager))
val nodeBankOfCordaFuture = startNotaryNode(BOC.name, rpcUsers = listOf(bocManager), validating = false)
val nodeBigCorporationFuture = startNode(providedName = BIGCORP_LEGAL_NAME, rpcUsers = listOf(bigCorpCFO))
val (nodeBankOfCorda, nodeBigCorporation) = listOf(nodeBankOfCordaFuture, nodeBigCorporationFuture).map { it.getOrThrow() }

View File

@ -9,8 +9,7 @@ import net.corda.finance.flows.CashExitFlow
import net.corda.finance.flows.CashIssueAndPaymentFlow
import net.corda.finance.flows.CashPaymentFlow
import net.corda.node.services.FlowPermissions.Companion.startFlowPermission
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.node.services.transactions.SimpleNotaryService
import net.corda.node.services.transactions.ValidatingNotaryService
import net.corda.nodeapi.User
import net.corda.testing.BOC
import net.corda.testing.DUMMY_NOTARY
@ -55,7 +54,7 @@ private class BankOfCordaDriver {
val role = options.valueOf(roleArg)!!
val requestParams = IssueRequestParams(options.valueOf(quantity), options.valueOf(currency), BIGCORP_LEGAL_NAME,
"1", BOC.name, DUMMY_NOTARY.name.copy(commonName = "corda.notary.validating"))
"1", BOC.name, DUMMY_NOTARY.name.copy(commonName = ValidatingNotaryService.id))
try {
when (role) {
@ -70,8 +69,7 @@ private class BankOfCordaDriver {
val bigCorpUser = User(BIGCORP_USERNAME, "test",
permissions = setOf(
startFlowPermission<CashPaymentFlow>()))
startNode(providedName = DUMMY_NOTARY.name,
advertisedServices = setOf(ServiceInfo(SimpleNotaryService.type)))
startNotaryNode(DUMMY_NOTARY.name, validating = false)
val bankOfCorda = startNode(
providedName = BOC.name,
rpcUsers = listOf(bankUser))

View File

@ -53,7 +53,8 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
networkMap "O=Notary Service,L=Zurich,C=CH"
node {
name "O=Notary Service,L=Zurich,C=CH"
advertisedServices = ["corda.notary.validating", "corda.interest_rates"]
notary = [validating : true]
advertisedServices = ["corda.interest_rates"]
p2pPort 10002
rpcPort 10003
webPort 10004

View File

@ -21,9 +21,7 @@ import net.corda.finance.plugin.registerFinanceJSONMappers
import net.corda.irs.contract.InterestRateSwap
import net.corda.irs.utilities.uploadFile
import net.corda.node.services.config.FullNodeConfiguration
import net.corda.node.services.transactions.SimpleNotaryService
import net.corda.nodeapi.User
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.testing.*
import net.corda.testing.driver.driver
import net.corda.testing.http.HttpApi
@ -50,9 +48,7 @@ class IRSDemoTest : IntegrationTestCategory {
fun `runs IRS demo`() {
driver(useTestClock = true, isDebug = true) {
val (controller, nodeA, nodeB) = listOf(
startNode(
providedName = DUMMY_NOTARY.name,
advertisedServices = setOf(ServiceInfo(SimpleNotaryService.type))),
startNotaryNode(DUMMY_NOTARY.name, validating = false),
startNode(providedName = DUMMY_BANK_A.name, rpcUsers = listOf(rpcUser)),
startNode(providedName = DUMMY_BANK_B.name))
.map { it.getOrThrow() }

View File

@ -1,8 +1,6 @@
package net.corda.irs
import net.corda.core.utilities.getOrThrow
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.node.services.transactions.SimpleNotaryService
import net.corda.testing.DUMMY_BANK_A
import net.corda.testing.DUMMY_BANK_B
import net.corda.testing.DUMMY_NOTARY
@ -15,9 +13,7 @@ import net.corda.testing.driver.driver
fun main(args: Array<String>) {
driver(dsl = {
val (controller, nodeA, nodeB) = listOf(
startNode(
providedName = DUMMY_NOTARY.name,
advertisedServices = setOf(ServiceInfo(SimpleNotaryService.type))),
startNotaryNode(DUMMY_NOTARY.name, validating = false),
startNode(providedName = DUMMY_BANK_A.name),
startNode(providedName = DUMMY_BANK_B.name))
.map { it.getOrThrow() }

View File

@ -11,18 +11,13 @@ import net.corda.irs.api.NodeInterestRates
import net.corda.node.internal.StartedNode
import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.statemachine.StateMachineManager
import net.corda.node.services.transactions.SimpleNotaryService
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.nodeapi.internal.ServiceType
import net.corda.testing.DUMMY_MAP
import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.DUMMY_REGULATOR
import net.corda.testing.*
import net.corda.testing.node.InMemoryMessagingNetwork
import net.corda.testing.node.MockNetwork
import net.corda.testing.node.TestClock
import net.corda.testing.node.setTo
import net.corda.testing.setCordappPackages
import net.corda.testing.testNodeConfiguration
import rx.Observable
import rx.subjects.PublishSubject
import java.math.BigInteger
@ -103,10 +98,11 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
advertisedServices: Set<ServiceInfo>, id: Int, notaryIdentity: Pair<ServiceInfo, KeyPair>?,
entropyRoot: BigInteger): SimulatedNode {
require(advertisedServices.containsType(SimpleNotaryService.type))
requireNotNull(config.notary)
val cfg = testNodeConfiguration(
baseDirectory = config.baseDirectory,
myLegalName = DUMMY_NOTARY.name)
myLegalName = DUMMY_NOTARY.name,
notaryConfig = config.notary)
return SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, notaryIdentity, entropyRoot)
}
}
@ -153,7 +149,7 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
val mockNet = MockNetwork(networkSendManuallyPumped, runAsync)
// This one must come first.
val networkMap = mockNet.startNetworkMapNode(nodeFactory = NetworkMapNodeFactory)
val notary = mockNet.createNode(nodeFactory = NotaryNodeFactory, advertisedServices = ServiceInfo(SimpleNotaryService.type))
val notary = mockNet.createNotaryNode(validating = false, nodeFactory = NotaryNodeFactory)
val regulators = listOf(mockNet.createUnstartedNode(nodeFactory = RegulatorFactory))
val ratesOracle = mockNet.createUnstartedNode(nodeFactory = RatesOracleFactory)

View File

@ -5,10 +5,9 @@ import net.corda.cordform.CordformDefinition
import net.corda.cordform.CordformNode
import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.div
import net.corda.core.internal.stream
import net.corda.core.internal.toTypedArray
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.node.services.config.BFTSMaRtConfiguration
import net.corda.node.services.config.NotaryConfig
import net.corda.node.services.transactions.BFTNonValidatingNotaryService
import net.corda.node.services.transactions.minCorrectReplicas
import net.corda.node.utilities.ServiceIdentityGenerator
@ -24,9 +23,7 @@ private val notaryNames = createNotaryNames(clusterSize)
// This is not the intended final design for how to use CordformDefinition, please treat this as experimental and DO
// NOT use this as a design to copy.
object BFTNotaryCordform : CordformDefinition("build" / "notary-demo-nodes", notaryNames[0].toString()) {
private val serviceType = BFTNonValidatingNotaryService.type
private val clusterName = CordaX500Name(serviceType.id, "BFT", "Zurich", "CH")
private val advertisedService = ServiceInfo(serviceType, clusterName)
private val clusterName = CordaX500Name(BFTNonValidatingNotaryService.id, "BFT", "Zurich", "CH")
init {
node {
@ -40,12 +37,10 @@ object BFTNotaryCordform : CordformDefinition("build" / "notary-demo-nodes", not
p2pPort(10005)
rpcPort(10006)
}
val clusterAddresses = (0 until clusterSize).stream().mapToObj { NetworkHostAndPort("localhost", 11000 + it * 10) }.toTypedArray()
val clusterAddresses = (0 until clusterSize).map { NetworkHostAndPort("localhost", 11000 + it * 10) }
fun notaryNode(replicaId: Int, configure: CordformNode.() -> Unit) = node {
name(notaryNames[replicaId])
advertisedServices(advertisedService)
notaryClusterAddresses(*clusterAddresses)
bftReplicaId(replicaId)
notary(NotaryConfig(validating = false, bftSMaRt = BFTSMaRtConfiguration(replicaId, clusterAddresses)))
configure()
}
notaryNode(0) {

View File

@ -6,7 +6,8 @@ import net.corda.cordform.CordformNode
import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.div
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.node.services.config.NotaryConfig
import net.corda.node.services.config.RaftConfig
import net.corda.node.services.transactions.RaftValidatingNotaryService
import net.corda.node.utilities.ServiceIdentityGenerator
import net.corda.testing.ALICE
@ -22,9 +23,7 @@ private val notaryNames = createNotaryNames(3)
// This is not the intended final design for how to use CordformDefinition, please treat this as experimental and DO
// NOT use this as a design to copy.
object RaftNotaryCordform : CordformDefinition("build" / "notary-demo-nodes", notaryNames[0].toString()) {
private val serviceType = RaftValidatingNotaryService.type
private val clusterName = CordaX500Name(serviceType.id, "Raft", "Zurich", "CH")
private val advertisedService = ServiceInfo(serviceType, clusterName)
private val clusterName = CordaX500Name(RaftValidatingNotaryService.id, "Raft", "Zurich", "CH")
init {
node {
@ -38,28 +37,23 @@ object RaftNotaryCordform : CordformDefinition("build" / "notary-demo-nodes", no
p2pPort(10005)
rpcPort(10006)
}
fun notaryNode(index: Int, configure: CordformNode.() -> Unit) = node {
fun notaryNode(index: Int, nodePort: Int, clusterPort: Int? = null, configure: CordformNode.() -> Unit) = node {
name(notaryNames[index])
advertisedServices(advertisedService)
val clusterAddresses = if (clusterPort != null ) listOf(NetworkHostAndPort("localhost", clusterPort)) else emptyList()
notary(NotaryConfig(validating = true, raft = RaftConfig(NetworkHostAndPort("localhost", nodePort), clusterAddresses)))
configure()
}
notaryNode(0) {
notaryNodePort(10008)
notaryNode(0, 10008) {
p2pPort(10009)
rpcPort(10010)
}
val clusterAddress = NetworkHostAndPort("localhost", 10008) // Otherwise each notary forms its own cluster.
notaryNode(1) {
notaryNodePort(10012)
notaryNode(1, 10012, 10008) {
p2pPort(10013)
rpcPort(10014)
notaryClusterAddresses(clusterAddress)
}
notaryNode(2) {
notaryNodePort(10016)
notaryNode(2, 10016, 10008) {
p2pPort(10017)
rpcPort(10018)
notaryClusterAddresses(clusterAddress)
}
}

View File

@ -1,17 +1,16 @@
package net.corda.notarydemo
import net.corda.cordform.CordformContext
import net.corda.cordform.CordformDefinition
import net.corda.core.internal.div
import net.corda.testing.ALICE
import net.corda.testing.BOB
import net.corda.testing.DUMMY_NOTARY
import net.corda.node.services.FlowPermissions.Companion.startFlowPermission
import net.corda.node.services.transactions.ValidatingNotaryService
import net.corda.node.services.config.NotaryConfig
import net.corda.nodeapi.User
import net.corda.notarydemo.flows.DummyIssueAndMove
import net.corda.notarydemo.flows.RPCStartableNotaryFlowClient
import net.corda.cordform.CordformDefinition
import net.corda.cordform.CordformContext
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.testing.ALICE
import net.corda.testing.BOB
import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.internal.demorun.*
fun main(args: Array<String>) = SingleNotaryCordform.runNodes()
@ -37,7 +36,7 @@ object SingleNotaryCordform : CordformDefinition("build" / "notary-demo-nodes",
name(DUMMY_NOTARY.name)
p2pPort(10009)
rpcPort(10010)
advertisedServices(ServiceInfo(ValidatingNotaryService.type))
notary(NotaryConfig(validating = true))
}
}

View File

@ -1,5 +1,3 @@
import org.apache.tools.ant.filters.FixCrLfFilter
buildscript {
ext.strata_version = '1.1.2'
}
@ -68,7 +66,8 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
networkMap "O=Notary Service,L=Zurich,C=CH"
node {
name "O=Notary Service,L=Zurich,C=CH"
advertisedServices = ["corda.notary.validating"]
notary = [validating : true]
advertisedServices = []
p2pPort 10002
cordapps = ["net.corda:finance:$corda_release_version"]
}

View File

@ -3,16 +3,9 @@ package net.corda.vega
import com.opengamma.strata.product.common.BuySell
import net.corda.core.identity.CordaX500Name
import net.corda.core.utilities.getOrThrow
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.node.services.transactions.SimpleNotaryService
import net.corda.testing.DUMMY_BANK_A
import net.corda.testing.DUMMY_BANK_B
import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.IntegrationTestCategory
import net.corda.testing.*
import net.corda.testing.driver.driver
import net.corda.testing.http.HttpApi
import net.corda.testing.setCordappPackages
import net.corda.testing.unsetCordappPackages
import net.corda.vega.api.PortfolioApi
import net.corda.vega.api.PortfolioApiUtils
import net.corda.vega.api.SwapDataModel
@ -46,7 +39,7 @@ class SimmValuationTest : IntegrationTestCategory {
@Test
fun `runs SIMM valuation demo`() {
driver(isDebug = true) {
startNode(providedName = DUMMY_NOTARY.name, advertisedServices = setOf(ServiceInfo(SimpleNotaryService.type))).getOrThrow()
startNotaryNode(DUMMY_NOTARY.name, validating = false).getOrThrow()
val nodeAFuture = startNode(providedName = nodeALegalName)
val nodeBFuture = startNode(providedName = nodeBLegalName)
val (nodeA, nodeB) = listOf(nodeAFuture, nodeBFuture).map { it.getOrThrow() }

View File

@ -1,12 +1,10 @@
package net.corda.vega
import net.corda.core.utilities.getOrThrow
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.testing.DUMMY_BANK_A
import net.corda.testing.DUMMY_BANK_B
import net.corda.testing.DUMMY_BANK_C
import net.corda.testing.DUMMY_NOTARY
import net.corda.node.services.transactions.SimpleNotaryService
import net.corda.testing.driver.driver
/**
@ -16,7 +14,7 @@ import net.corda.testing.driver.driver
*/
fun main(args: Array<String>) {
driver(dsl = {
val notaryFuture = startNode(providedName = DUMMY_NOTARY.name, advertisedServices = setOf(ServiceInfo(SimpleNotaryService.type)))
val notaryFuture = startNotaryNode(DUMMY_NOTARY.name, validating = false)
val nodeAFuture = startNode(providedName = DUMMY_BANK_A.name)
val nodeBFuture = startNode(providedName = DUMMY_BANK_B.name)
val nodeCFuture = startNode(providedName = DUMMY_BANK_C.name)

View File

@ -54,7 +54,8 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
networkMap "O=Notary Service,L=Zurich,C=CH"
node {
name "O=Notary Service,L=Zurich,C=CH"
advertisedServices = ["corda.notary.validating"]
notary = [validating : true]
advertisedServices = []
p2pPort 10002
cordapps = ["net.corda:finance:$corda_release_version"]
}

View File

@ -9,9 +9,7 @@ import net.corda.finance.flows.CashPaymentFlow
import net.corda.finance.schemas.CashSchemaV1
import net.corda.finance.schemas.CommercialPaperSchemaV1
import net.corda.node.services.FlowPermissions.Companion.startFlowPermission
import net.corda.node.services.transactions.SimpleNotaryService
import net.corda.nodeapi.User
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.testing.*
import net.corda.testing.driver.poll
import net.corda.testing.node.NodeBasedTest
@ -43,7 +41,7 @@ class TraderDemoTest : NodeBasedTest() {
startFlowPermission<CashIssueFlow>(),
startFlowPermission<CashPaymentFlow>(),
startFlowPermission<CommercialPaperIssueFlow>()))
val notaryFuture = startNode(DUMMY_NOTARY.name, advertisedServices = setOf(ServiceInfo(SimpleNotaryService.type)))
val notaryFuture = startNotaryNode(DUMMY_NOTARY.name, validating = false)
val nodeAFuture = startNode(DUMMY_BANK_A.name, rpcUsers = listOf(demoUser))
val nodeBFuture = startNode(DUMMY_BANK_B.name, rpcUsers = listOf(demoUser))
val bankNodeFuture = startNode(BOC.name, rpcUsers = listOf(bankUser))

View File

@ -3,8 +3,6 @@ package net.corda.traderdemo
import net.corda.core.internal.div
import net.corda.finance.flows.CashIssueFlow
import net.corda.node.services.FlowPermissions.Companion.startFlowPermission
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.node.services.transactions.SimpleNotaryService
import net.corda.nodeapi.User
import net.corda.testing.BOC
import net.corda.testing.DUMMY_BANK_A
@ -27,7 +25,7 @@ fun main(args: Array<String>) {
val user = User("user1", "test", permissions = setOf(startFlowPermission<CashIssueFlow>(),
startFlowPermission<CommercialPaperIssueFlow>(),
startFlowPermission<SellerFlow>()))
startNode(providedName = DUMMY_NOTARY.name, advertisedServices = setOf(ServiceInfo(SimpleNotaryService.type)))
startNotaryNode(DUMMY_NOTARY.name, validating = false)
startNode(providedName = DUMMY_BANK_A.name, rpcUsers = demoUser)
startNode(providedName = DUMMY_BANK_B.name, rpcUsers = demoUser)
startNode(providedName = BOC.name, rpcUsers = listOf(user))

View File

@ -9,9 +9,7 @@ import net.corda.core.internal.read
import net.corda.core.messaging.startFlow
import net.corda.core.serialization.CordaSerializable
import net.corda.node.services.FlowPermissions.Companion.startFlowPermission
import net.corda.node.services.transactions.ValidatingNotaryService
import net.corda.nodeapi.User
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.testing.driver.driver
import net.corda.testing.node.MockNetwork
import org.junit.Ignore
@ -292,11 +290,7 @@ class FlowStackSnapshotTest {
@Test
fun `flowStackSnapshot object is serializable`() {
val mockNet = MockNetwork(threadPerNode = true)
val notaryService = ServiceInfo(ValidatingNotaryService.type)
val notaryNode = mockNet.createNode(
legalName = DUMMY_NOTARY.name,
notaryIdentity = notaryService to DUMMY_NOTARY_KEY,
advertisedServices = *arrayOf(notaryService))
mockNet.createNotaryNode(legalName = DUMMY_NOTARY.name)
val node = mockNet.createPartyNode()
node.internals.registerInitiatedFlow(DummyFlow::class.java)
node.services.startFlow(FlowStackSnapshotSerializationTestingFlow()).resultFuture.get()

View File

@ -5,12 +5,10 @@ import net.corda.core.internal.div
import net.corda.core.internal.list
import net.corda.core.internal.readLines
import net.corda.core.utilities.getOrThrow
import net.corda.node.internal.NodeStartup
import net.corda.testing.DUMMY_BANK_A
import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.DUMMY_REGULATOR
import net.corda.node.internal.NodeStartup
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.node.services.transactions.SimpleNotaryService
import net.corda.testing.ProjectStructure.projectRootDir
import org.assertj.core.api.Assertions.assertThat
import org.junit.Test
@ -40,7 +38,7 @@ class DriverTests {
@Test
fun `simple node startup and shutdown`() {
val handles = driver {
val notary = startNode(providedName = DUMMY_NOTARY.name, advertisedServices = setOf(ServiceInfo(SimpleNotaryService.type)))
val notary = startNotaryNode(DUMMY_NOTARY.name, validating = false)
val regulator = startNode(providedName = DUMMY_REGULATOR.name)
listOf(nodeMustBeUp(notary), nodeMustBeUp(regulator))
}

View File

@ -5,8 +5,6 @@ package net.corda.testing
import net.corda.core.identity.Party
import net.corda.core.internal.concurrent.transpose
import net.corda.core.messaging.CordaRPCOps
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.node.services.transactions.ValidatingNotaryService
import net.corda.nodeapi.User
import net.corda.testing.driver.DriverDSLExposedInterface
@ -19,9 +17,15 @@ import net.corda.testing.driver.DriverDSLExposedInterface
* node construction won't start until you access the members. You can get one of these from the
* [alice], [bob] and [aliceBobAndNotary] functions.
*/
class PredefinedTestNode internal constructor(party: Party, driver: DriverDSLExposedInterface, services: Set<ServiceInfo>) {
class PredefinedTestNode internal constructor(party: Party, driver: DriverDSLExposedInterface, ifNotaryIsValidating: Boolean?) {
val rpcUsers = listOf(User("admin", "admin", setOf("ALL"))) // TODO: Randomize?
val nodeFuture by lazy { driver.startNode(providedName = party.name, rpcUsers = rpcUsers, advertisedServices = services) }
val nodeFuture by lazy {
if (ifNotaryIsValidating != null) {
driver.startNotaryNode(providedName = party.name, rpcUsers = rpcUsers, validating = ifNotaryIsValidating)
} else {
driver.startNode(providedName = party.name, rpcUsers = rpcUsers)
}
}
val node by lazy { nodeFuture.get()!! }
val rpc by lazy { node.rpcClientToNode() }
@ -34,17 +38,17 @@ class PredefinedTestNode internal constructor(party: Party, driver: DriverDSLExp
* Returns a plain, entirely stock node pre-configured with the [ALICE] identity. Note that a random key will be generated
* for it: you won't have [ALICE_KEY].
*/
fun DriverDSLExposedInterface.alice(): PredefinedTestNode = PredefinedTestNode(ALICE, this, emptySet())
fun DriverDSLExposedInterface.alice(): PredefinedTestNode = PredefinedTestNode(ALICE, this, null)
/**
* Returns a plain, entirely stock node pre-configured with the [BOB] identity. Note that a random key will be generated
* for it: you won't have [BOB_KEY].
*/
fun DriverDSLExposedInterface.bob(): PredefinedTestNode = PredefinedTestNode(BOB, this, emptySet())
fun DriverDSLExposedInterface.bob(): PredefinedTestNode = PredefinedTestNode(BOB, this, null)
/**
* Returns a plain single node notary pre-configured with the [DUMMY_NOTARY] identity. Note that a random key will be generated
* for it: you won't have [DUMMY_NOTARY_KEY].
*/
fun DriverDSLExposedInterface.notary(): PredefinedTestNode = PredefinedTestNode(DUMMY_NOTARY, this, setOf(ServiceInfo(ValidatingNotaryService.type)))
fun DriverDSLExposedInterface.notary(): PredefinedTestNode = PredefinedTestNode(DUMMY_NOTARY, this, true)
/**
* Returns plain, entirely stock nodes pre-configured with the [ALICE], [BOB] and [DUMMY_NOTARY] X.500 names in that

View File

@ -8,8 +8,8 @@ import net.corda.core.identity.CordaX500Name
import net.corda.core.node.ServiceHub
import net.corda.core.transactions.TransactionBuilder
import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.config.NotaryConfig
import net.corda.node.services.config.VerifierType
import net.corda.testing.node.MockCordappProvider
import net.corda.testing.node.MockServices
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
import net.corda.testing.node.MockServices.Companion.makeTestDatabaseProperties
@ -51,7 +51,8 @@ import java.nio.file.Path
fun testNodeConfiguration(
baseDirectory: Path,
myLegalName: CordaX500Name): NodeConfiguration {
myLegalName: CordaX500Name,
notaryConfig: NotaryConfig? = null): NodeConfiguration {
abstract class MockableNodeConfiguration : NodeConfiguration // Otherwise Mockito is defeated by val getters.
val nc = spy<MockableNodeConfiguration>()
whenever(nc.baseDirectory).thenReturn(baseDirectory)
@ -60,6 +61,7 @@ fun testNodeConfiguration(
whenever(nc.keyStorePassword).thenReturn("cordacadevpass")
whenever(nc.trustStorePassword).thenReturn("trustpass")
whenever(nc.rpcUsers).thenReturn(emptyList())
whenever(nc.notary).thenReturn(notaryConfig)
whenever(nc.dataSourceProperties).thenReturn(makeTestDataSourceProperties(myLegalName.organisation))
whenever(nc.database).thenReturn(makeTestDatabaseProperties())
whenever(nc.emailAddress).thenReturn("")

View File

@ -26,12 +26,11 @@ import net.corda.node.internal.NodeStartup
import net.corda.node.internal.StartedNode
import net.corda.node.services.config.*
import net.corda.node.services.network.NetworkMapService
import net.corda.node.services.transactions.RaftValidatingNotaryService
import net.corda.node.utilities.ServiceIdentityGenerator
import net.corda.nodeapi.User
import net.corda.nodeapi.config.parseAs
import net.corda.nodeapi.config.toConfig
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.nodeapi.internal.ServiceType
import net.corda.nodeapi.internal.addShutdownHook
import net.corda.testing.*
import net.corda.testing.node.MockServices.Companion.MOCK_VERSION_INFO
@ -96,6 +95,14 @@ interface DriverDSLExposedInterface : CordformContext {
startInSameProcess: Boolean? = defaultParameters.startInSameProcess,
maximumHeapSize: String = defaultParameters.maximumHeapSize): CordaFuture<NodeHandle>
// TODO This method has been added temporarily, to be deleted once the set of notaries is defined at the network level.
fun startNotaryNode(providedName: CordaX500Name,
rpcUsers: List<User> = emptyList(),
verifierType: VerifierType = VerifierType.InMemory,
customOverrides: Map<String, Any?> = emptyMap(),
//TODO Switch the default value
validating: Boolean = true): CordaFuture<NodeHandle>
/**
* Helper function for starting a [node] with custom parameters from Java.
*
@ -118,7 +125,6 @@ interface DriverDSLExposedInterface : CordformContext {
*
* @param notaryName The legal name of the advertised distributed notary service.
* @param clusterSize Number of nodes to create for the cluster.
* @param type The advertised notary service type. Currently the only supported type is [RaftValidatingNotaryService.type].
* @param verifierType The type of transaction verifier to use. See: [VerifierType]
* @param rpcUsers List of users who are authorised to use the RPC system. Defaults to empty list.
* @param startInSameProcess Determines if the node should be started inside the same process the Driver is running
@ -128,7 +134,6 @@ interface DriverDSLExposedInterface : CordformContext {
fun startNotaryCluster(
notaryName: CordaX500Name,
clusterSize: Int = 3,
type: ServiceType = RaftValidatingNotaryService.type,
verifierType: VerifierType = VerifierType.InMemory,
rpcUsers: List<User> = emptyList(),
startInSameProcess: Boolean? = null): CordaFuture<Pair<Party, List<NodeHandle>>>
@ -668,9 +673,9 @@ class DriverDSL(
}
}
is NetworkMapStartStrategy.Nominated -> {
serviceConfig(networkMapCandidates.filter {
serviceConfig(networkMapCandidates.single {
it.name == legalName.toString()
}.single().config.getString("p2pAddress").let(NetworkHostAndPort.Companion::parse)).let {
}.config.getString("p2pAddress").let(NetworkHostAndPort.Companion::parse)).let {
{ nodeName: CordaX500Name -> if (nodeName == legalName) null else it }
}
}
@ -715,6 +720,15 @@ class DriverDSL(
return startNodeInternal(config, webAddress, startInSameProcess, maximumHeapSize)
}
override fun startNotaryNode(providedName: CordaX500Name,
rpcUsers: List<User>,
verifierType: VerifierType,
customOverrides: Map<String, Any?>,
validating: Boolean): CordaFuture<NodeHandle> {
val config = customOverrides + NotaryConfig(validating).toConfigMap()
return startNode(providedName = providedName, rpcUsers = rpcUsers, verifierType = verifierType, customOverrides = config)
}
override fun startNodes(nodes: List<CordformNode>, startInSameProcess: Boolean?, maximumHeapSize: String): List<CordaFuture<NodeHandle>> {
val networkMapServiceConfigLookup = networkMapServiceConfigLookup(nodes)
return nodes.map { node ->
@ -722,50 +736,62 @@ class DriverDSL(
val webAddress = portAllocation.nextHostAndPort()
val name = CordaX500Name.parse(node.name)
val rpcUsers = node.rpcUsers
val notary = if (node.notary != null) mapOf("notary" to node.notary) else emptyMap()
val config = ConfigHelper.loadConfig(
baseDirectory = baseDirectory(name),
allowMissingConfig = true,
configOverrides = node.config + mapOf(
configOverrides = node.config + notary + mapOf(
"extraAdvertisedServiceIds" to node.advertisedServices,
"networkMapService" to networkMapServiceConfigLookup(name),
"rpcUsers" to if (rpcUsers.isEmpty()) defaultRpcUserList else rpcUsers,
"notaryClusterAddresses" to node.notaryClusterAddresses
"rpcUsers" to if (rpcUsers.isEmpty()) defaultRpcUserList else rpcUsers
)
)
startNodeInternal(config, webAddress, startInSameProcess, maximumHeapSize)
}
}
// TODO This mapping is done is several plaecs including the gradle plugin. In general we need a better way of
// generating the configs for the nodes, probably making use of Any.toConfig()
private fun NotaryConfig.toConfigMap(): Map<String, Any> = mapOf("notary" to toConfig().root().unwrapped())
override fun startNotaryCluster(
notaryName: CordaX500Name,
clusterSize: Int,
type: ServiceType,
verifierType: VerifierType,
rpcUsers: List<User>,
startInSameProcess: Boolean?
): CordaFuture<Pair<Party, List<NodeHandle>>> {
fun notaryConfig(nodeAddress: NetworkHostAndPort, clusterAddress: NetworkHostAndPort? = null): Map<String, Any> {
val clusterAddresses = if (clusterAddress != null) listOf(clusterAddress) else emptyList()
val config = NotaryConfig(validating = true, raft = RaftConfig(nodeAddress = nodeAddress, clusterAddresses = clusterAddresses))
return config.toConfigMap()
}
val nodeNames = (0 until clusterSize).map { CordaX500Name("Notary Service $it", "Zurich", "CH") }
val paths = nodeNames.map { baseDirectory(it) }
ServiceIdentityGenerator.generateToDisk(paths, notaryName)
val advertisedServices = setOf(ServiceInfo(type, notaryName))
val notaryClusterAddress = portAllocation.nextHostAndPort()
val clusterAddress = portAllocation.nextHostAndPort()
// Start the first node that will bootstrap the cluster
val firstNotaryFuture = startNode(
providedName = nodeNames.first(),
advertisedServices = advertisedServices,
rpcUsers = rpcUsers,
verifierType = verifierType,
customOverrides = mapOf("notaryNodeAddress" to notaryClusterAddress.toString(),
"database.serverNameTablePrefix" to if (nodeNames.isNotEmpty()) nodeNames.first().toString().replace(Regex("[^0-9A-Za-z]+"), "") else ""),
customOverrides = notaryConfig(clusterAddress) + mapOf(
"database.serverNameTablePrefix" to if (nodeNames.isNotEmpty()) nodeNames.first().toString().replace(Regex("[^0-9A-Za-z]+"), "") else ""
),
startInSameProcess = startInSameProcess
)
// All other nodes will join the cluster
val restNotaryFutures = nodeNames.drop(1).map {
val nodeAddress = portAllocation.nextHostAndPort()
val configOverride = mapOf("notaryNodeAddress" to nodeAddress.toString(), "notaryClusterAddresses" to listOf(notaryClusterAddress.toString()),
"database.serverNameTablePrefix" to it.toString().replace(Regex("[^0-9A-Za-z]+"), ""))
startNode(providedName = it, advertisedServices = advertisedServices, rpcUsers = rpcUsers, verifierType = verifierType, customOverrides = configOverride)
startNode(
providedName = it,
rpcUsers = rpcUsers,
verifierType = verifierType,
customOverrides = notaryConfig(nodeAddress, clusterAddress) + mapOf(
"database.serverNameTablePrefix" to it.toString().replace(Regex("[^0-9A-Za-z]+"), "")
))
}
return firstNotaryFuture.flatMap { firstNotary ->

View File

@ -5,9 +5,10 @@ package net.corda.testing.internal.demorun
import net.corda.cordform.CordformDefinition
import net.corda.cordform.CordformNode
import net.corda.core.identity.CordaX500Name
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.node.services.config.NotaryConfig
import net.corda.nodeapi.User
import net.corda.nodeapi.config.toConfig
import net.corda.nodeapi.internal.ServiceInfo
fun CordformDefinition.node(configure: CordformNode.() -> Unit) {
addNode { cordformNode -> cordformNode.configure() }
@ -19,10 +20,10 @@ fun CordformNode.rpcUsers(vararg users: User) {
rpcUsers = users.map { it.toMap() }
}
fun CordformNode.notary(notaryConfig: NotaryConfig) {
notary = notaryConfig.toConfig().root().unwrapped()
}
fun CordformNode.advertisedServices(vararg services: ServiceInfo) {
advertisedServices = services.map { it.toString() }
}
fun CordformNode.notaryClusterAddresses(vararg addresses: NetworkHostAndPort) {
notaryClusterAddresses = addresses.map { it.toString() }
}

View File

@ -19,7 +19,6 @@ import net.corda.core.messaging.SingleMessageRecipient
import net.corda.core.node.services.IdentityService
import net.corda.core.node.services.KeyManagementService
import net.corda.core.node.services.NetworkMapCache
import net.corda.core.node.services.NotaryService
import net.corda.core.serialization.SerializationWhitelist
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.getOrThrow
@ -28,10 +27,10 @@ import net.corda.finance.utils.WorldMapLocation
import net.corda.node.internal.AbstractNode
import net.corda.node.internal.StartedNode
import net.corda.node.services.api.NetworkMapCacheInternal
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.nodeapi.internal.ServiceType
import net.corda.node.services.api.SchemaService
import net.corda.node.services.config.BFTSMaRtConfiguration
import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.config.NotaryConfig
import net.corda.node.services.identity.PersistentIdentityService
import net.corda.node.services.keys.E2ETestKeyManagementService
import net.corda.node.services.messaging.MessagingService
@ -40,18 +39,22 @@ import net.corda.node.services.network.NetworkMapService
import net.corda.node.services.transactions.BFTNonValidatingNotaryService
import net.corda.node.services.transactions.BFTSMaRt
import net.corda.node.services.transactions.InMemoryTransactionVerifierService
import net.corda.node.services.transactions.ValidatingNotaryService
import net.corda.node.utilities.AffinityExecutor
import net.corda.node.utilities.AffinityExecutor.ServiceAffinityExecutor
import net.corda.node.utilities.CertificateAndKeyPair
import net.corda.testing.*
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.testing.DUMMY_KEY_1
import net.corda.testing.initialiseTestSerialization
import net.corda.testing.node.MockServices.Companion.MOCK_VERSION_INFO
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
import net.corda.testing.resetTestSerialization
import net.corda.testing.testNodeConfiguration
import org.apache.activemq.artemis.utils.ReusableLatch
import org.slf4j.Logger
import java.math.BigInteger
import java.nio.file.Path
import java.security.KeyPair
import java.security.PublicKey
import java.security.cert.X509Certificate
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicInteger
@ -220,17 +223,6 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
return InMemoryNetworkMapService(network, networkMapCache, 1)
}
override fun getNotaryIdentity(): PartyAndCertificate? {
val defaultIdentity = super.getNotaryIdentity()
return if (notaryIdentity == null || !notaryIdentity.first.type.isNotary() || defaultIdentity == null)
defaultIdentity
else {
// Ensure that we always have notary in name and type of it. TODO It is temporary solution until we will have proper handling of NetworkParameters
myNotaryIdentity = getTestPartyAndCertificate(defaultIdentity.name, notaryIdentity.second.public)
myNotaryIdentity
}
}
// This is not thread safe, but node construction is done on a single thread, so that should always be fine
override fun generateKeyPair(): KeyPair {
counter = counter.add(BigInteger.ONE)
@ -277,12 +269,11 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
override fun acceptableLiveFiberCountOnStop(): Int = acceptableLiveFiberCountOnStop
override fun makeCoreNotaryService(type: ServiceType): NotaryService? {
if (type != BFTNonValidatingNotaryService.type) return super.makeCoreNotaryService(type)
return BFTNonValidatingNotaryService(services, myNotaryIdentity!!.owningKey, object : BFTSMaRt.Cluster {
override fun makeBFTCluster(notaryKey: PublicKey, bftSMaRtConfig: BFTSMaRtConfiguration): BFTSMaRt.Cluster {
return object : BFTSMaRt.Cluster {
override fun waitUntilAllReplicasHaveInitialized() {
val clusterNodes = mockNet.nodes.filter { myNotaryIdentity!!.owningKey in it.started!!.info.legalIdentities.map { it.owningKey } }
if (clusterNodes.size != configuration.notaryClusterAddresses.size) {
val clusterNodes = mockNet.nodes.filter { notaryKey in it.started!!.info.legalIdentities.map { it.owningKey } }
if (clusterNodes.size != bftSMaRtConfig.clusterAddresses.size) {
throw IllegalStateException("Unable to enumerate all nodes in BFT cluster.")
}
clusterNodes.forEach {
@ -290,7 +281,7 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
notaryService.waitUntilReplicaHasInitialized()
}
}
})
}
}
/**
@ -406,16 +397,19 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
}
}
/**
* Construct a default notary node.
*/
fun createNotaryNode() = createNotaryNode(DUMMY_NOTARY.name, null, null)
@JvmOverloads
fun createNotaryNode(legalName: CordaX500Name? = null, validating: Boolean = true): StartedNode<MockNode> {
return createNode(legalName = legalName, configOverrides = {
whenever(it.notary).thenReturn(NotaryConfig(validating))
})
}
fun createNotaryNode(legalName: CordaX500Name? = null,
notaryIdentity: Pair<ServiceInfo, KeyPair>? = null,
serviceName: CordaX500Name? = null): StartedNode<MockNode> {
return createNode(legalName = legalName, notaryIdentity = notaryIdentity,
advertisedServices = *arrayOf(ServiceInfo(ValidatingNotaryService.type, serviceName)))
fun <N : MockNode> createNotaryNode(legalName: CordaX500Name? = null,
validating: Boolean = true,
nodeFactory: Factory<N>): StartedNode<N> {
return createNode(legalName = legalName, nodeFactory = nodeFactory, configOverrides = {
whenever(it.notary).thenReturn(NotaryConfig(validating))
})
}
@JvmOverloads

View File

@ -5,19 +5,16 @@ import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.concurrent.*
import net.corda.core.internal.createDirectories
import net.corda.core.internal.div
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.getOrThrow
import net.corda.node.internal.Node
import net.corda.node.internal.StartedNode
import net.corda.node.services.config.ConfigHelper
import net.corda.node.services.config.FullNodeConfiguration
import net.corda.node.services.config.configOf
import net.corda.node.services.config.plus
import net.corda.node.services.transactions.RaftValidatingNotaryService
import net.corda.node.services.config.*
import net.corda.node.utilities.ServiceIdentityGenerator
import net.corda.nodeapi.User
import net.corda.nodeapi.config.parseAs
import net.corda.nodeapi.config.toConfig
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.nodeapi.internal.ServiceType
import net.corda.testing.DUMMY_MAP
import net.corda.testing.TestDependencyInjectionBase
import net.corda.testing.driver.addressMustNotBeBoundFuture
@ -129,30 +126,44 @@ abstract class NodeBasedTest : TestDependencyInjectionBase() {
return if (waitForConnection) node.internals.nodeReadyFuture.map { node } else doneFuture(node)
}
fun startNotaryCluster(notaryName: CordaX500Name,
clusterSize: Int,
serviceType: ServiceType = RaftValidatingNotaryService.type): CordaFuture<List<StartedNode<Node>>> {
// TODO This method has been added temporarily, to be deleted once the set of notaries is defined at the network level.
fun startNotaryNode(name: CordaX500Name,
rpcUsers: List<User> = emptyList(),
validating: Boolean = true): CordaFuture<StartedNode<Node>> {
return startNode(name, rpcUsers = rpcUsers, configOverrides = mapOf("notary" to mapOf("validating" to validating)))
}
fun startNotaryCluster(notaryName: CordaX500Name, clusterSize: Int): CordaFuture<List<StartedNode<Node>>> {
fun notaryConfig(nodeAddress: NetworkHostAndPort, clusterAddress: NetworkHostAndPort? = null): Map<String, Any> {
val clusterAddresses = if (clusterAddress != null) listOf(clusterAddress) else emptyList()
val config = NotaryConfig(validating = true, raft = RaftConfig(nodeAddress = nodeAddress, clusterAddresses = clusterAddresses))
return mapOf("notary" to config.toConfig().root().unwrapped())
}
ServiceIdentityGenerator.generateToDisk(
(0 until clusterSize).map { baseDirectory(notaryName.copy(organisation = "${notaryName.organisation}-$it")) },
notaryName)
val serviceInfo = ServiceInfo(serviceType, notaryName)
val nodeAddresses = getFreeLocalPorts("localhost", clusterSize).map { it.toString() }
val nodeAddresses = getFreeLocalPorts("localhost", clusterSize)
val masterNodeFuture = startNode(
CordaX500Name(organisation = "${notaryName.organisation}-0", locality = notaryName.locality, country = notaryName.country),
advertisedServices = setOf(serviceInfo),
configOverrides = mapOf("notaryNodeAddress" to nodeAddresses[0],
"database" to mapOf("serverNameTablePrefix" to if (clusterSize > 1) "${notaryName.organisation}0".replace(Regex("[^0-9A-Za-z]+"), "") else "")))
configOverrides = notaryConfig(nodeAddresses[0]) + mapOf(
"database" to mapOf(
"serverNameTablePrefix" to if (clusterSize > 1) "${notaryName.organisation}0".replace(Regex("[^0-9A-Za-z]+"), "") else ""
)
)
)
val remainingNodesFutures = (1 until clusterSize).map {
startNode(
CordaX500Name(organisation = "${notaryName.organisation}-$it", locality = notaryName.locality, country = notaryName.country),
advertisedServices = setOf(serviceInfo),
configOverrides = mapOf(
"notaryNodeAddress" to nodeAddresses[it],
"notaryClusterAddresses" to listOf(nodeAddresses[0]),
"database" to mapOf("serverNameTablePrefix" to "${notaryName.organisation}$it".replace(Regex("[^0-9A-Za-z]+"), ""))))
configOverrides = notaryConfig(nodeAddresses[it], nodeAddresses[0]) + mapOf(
"database" to mapOf(
"serverNameTablePrefix" to "${notaryName.organisation}$it".replace(Regex("[^0-9A-Za-z]+"), "")
)
)
)
}
return remainingNodesFutures.transpose().flatMap { remainingNodes ->

View File

@ -13,7 +13,7 @@ class NodeConfig(
val p2pPort: Int,
val rpcPort: Int,
val webPort: Int,
val extraServices: List<String>,
val isNotary: Boolean,
val users: List<User>,
var networkMap: NodeConfig? = null
) {
@ -27,10 +27,11 @@ class NodeConfig(
* The configuration object depends upon the networkMap,
* which is mutable.
*/
fun toFileConfig(): Config = empty()
//TODO Make use of Any.toConfig
private fun toFileConfig(): Config {
val config = empty()
.withValue("myLegalName", valueFor(legalName.toString()))
.withValue("p2pAddress", addressValueFor(p2pPort))
.withValue("extraAdvertisedServiceIds", valueFor(extraServices))
.withFallback(optional("networkMapService", networkMap, { c, n ->
c.withValue("address", addressValueFor(n.p2pPort))
.withValue("legalName", valueFor(n.legalName.toString()))
@ -39,6 +40,12 @@ class NodeConfig(
.withValue("rpcAddress", addressValueFor(rpcPort))
.withValue("rpcUsers", valueFor(users.map(User::toMap).toList()))
.withValue("useTestClock", valueFor(true))
return if (isNotary) {
config.withValue("notary", ConfigValueFactory.fromMap(mapOf("validating" to true)))
} else {
config
}
}
fun toText(): String = toFileConfig().root().render(renderOptions)

View File

@ -8,7 +8,7 @@ import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.StandardCopyOption
class NodeConfig(
class NodeConfig constructor(
baseDir: Path,
legalName: CordaX500Name,
p2pPort: Int,
@ -42,7 +42,8 @@ class NodeConfig(
* The configuration object depends upon the networkMap,
* which is mutable.
*/
fun toFileConfig(): Config = ConfigFactory.empty()
fun toFileConfig(): Config {
return ConfigFactory.empty()
.withValue("myLegalName", valueFor(legalName.toString()))
.withValue("p2pAddress", addressValueFor(p2pPort))
.withValue("extraAdvertisedServiceIds", valueFor(extraServices))
@ -56,6 +57,7 @@ class NodeConfig(
.withValue("h2port", valueFor(h2Port))
.withValue("useTestClock", valueFor(true))
.withValue("detectPublicIp", valueFor(false))
}
fun toText(): String = toFileConfig().root().render(renderOptions)

View File

@ -11,7 +11,7 @@ class UserTest {
val user = toUser(emptyMap())
assertEquals("none", user.username)
assertEquals("none", user.password)
assertEquals(emptySet<String>(), user.permissions)
assertEquals(emptySet(), user.permissions)
}
@Test
@ -33,7 +33,7 @@ class UserTest {
val map = user.toMap()
assertEquals("MyName", map["username"])
assertEquals("MyPassword", map["password"])
assertEquals(setOf("Flow.MyFlow"), map["permissions"])
assertEquals(listOf("Flow.MyFlow"), map["permissions"])
}
@Test

View File

@ -21,10 +21,9 @@ import net.corda.finance.flows.*
import net.corda.finance.flows.CashExitFlow.ExitRequest
import net.corda.finance.flows.CashIssueAndPaymentFlow.IssueAndPaymentRequest
import net.corda.node.services.FlowPermissions.Companion.startFlowPermission
import net.corda.node.services.transactions.SimpleNotaryService
import net.corda.nodeapi.User
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.nodeapi.internal.ServiceType
import net.corda.nodeapi.User
import net.corda.testing.ALICE
import net.corda.testing.BOB
import net.corda.testing.DUMMY_NOTARY
@ -70,8 +69,7 @@ class ExplorerSimulation(val options: OptionSet) {
val portAllocation = PortAllocation.Incremental(20000)
driver(portAllocation = portAllocation, extraCordappPackagesToScan = listOf("net.corda.finance")) {
// TODO : Supported flow should be exposed somehow from the node instead of set of ServiceInfo.
val notary = startNode(providedName = DUMMY_NOTARY.name, advertisedServices = setOf(ServiceInfo(SimpleNotaryService.type)),
customOverrides = mapOf("nearestCity" to "Zurich"))
val notary = startNotaryNode(DUMMY_NOTARY.name, customOverrides = mapOf("nearestCity" to "Zurich"), validating = false)
val alice = startNode(providedName = ALICE.name, rpcUsers = arrayListOf(user),
advertisedServices = setOf(ServiceInfo(ServiceType.corda.getSubType("cash"))),
customOverrides = mapOf("nearestCity" to "Milan"))

View File

@ -10,12 +10,10 @@ import net.corda.finance.DOLLARS
import net.corda.finance.flows.CashIssueFlow
import net.corda.finance.flows.CashPaymentFlow
import net.corda.node.services.config.VerifierType
import net.corda.node.services.transactions.ValidatingNotaryService
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.testing.ALICE
import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.driver.NetworkMapStartStrategy
import net.corda.testing.chooseIdentity
import net.corda.testing.driver.NetworkMapStartStrategy
import org.junit.Test
import java.util.*
import java.util.concurrent.atomic.AtomicInteger
@ -117,7 +115,7 @@ class VerifierTests {
extraCordappPackagesToScan = listOf("net.corda.finance.contracts")
) {
val aliceFuture = startNode(providedName = ALICE.name)
val notaryFuture = startNode(providedName = DUMMY_NOTARY.name, advertisedServices = setOf(ServiceInfo(ValidatingNotaryService.type)), verifierType = VerifierType.OutOfProcess)
val notaryFuture = startNotaryNode(DUMMY_NOTARY.name, verifierType = VerifierType.OutOfProcess)
val alice = aliceFuture.get()
val notary = notaryFuture.get()
val notaryIdentity = notary.nodeInfo.legalIdentities[1]