mirror of
https://github.com/corda/corda.git
synced 2024-12-19 21:17:58 +00:00
Cleaned up notary configuration by introducing a notary config option.
extraAdvertisedServiceIds is no longer used for this.
This commit is contained in:
parent
83f37417ae
commit
727cd0e55c
@ -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 = []
|
||||
}
|
||||
|
@ -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 }
|
||||
|
@ -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()));
|
||||
|
@ -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!!)
|
||||
}
|
||||
|
@ -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"));
|
||||
|
@ -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)
|
||||
)
|
||||
|
||||
|
@ -3,5 +3,7 @@ keyStorePassword : "cordacadevpass"
|
||||
trustStorePassword : "trustpass"
|
||||
p2pAddress : "localhost:10000"
|
||||
webAddress : "localhost:10001"
|
||||
extraAdvertisedServiceIds : [ "corda.notary.validating" ]
|
||||
notary : {
|
||||
validating : true
|
||||
}
|
||||
useHTTPS : false
|
||||
|
@ -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,8 +137,11 @@ 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
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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))
|
||||
|
@ -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)
|
||||
|
@ -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"]
|
||||
|
@ -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`.
|
||||
|
@ -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"]
|
||||
|
@ -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)));
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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")
|
||||
|
@ -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 }
|
||||
|
||||
}
|
@ -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 ->
|
||||
|
@ -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
|
||||
|
@ -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,20 +49,17 @@ 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.
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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() {
|
||||
|
@ -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`() {
|
||||
|
@ -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 {
|
||||
|
@ -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))
|
||||
|
@ -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()
|
||||
|
@ -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,
|
||||
val maxRetryIntervalMin: Long,
|
||||
val retryIntervalMultiplier: Double
|
||||
)
|
||||
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)
|
||||
|
||||
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,
|
||||
|
@ -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() }
|
||||
}
|
||||
|
||||
|
@ -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,36 +93,37 @@ 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(
|
||||
toPersistentEntityKey = { PersistentStateRef(it.txhash.toString(), it.index) },
|
||||
fromPersistentEntity = {
|
||||
//TODO null check will become obsolete after making DB/JPA columns not nullable
|
||||
val txId = it.id.txId ?: throw IllegalStateException("DB returned null SecureHash transactionId")
|
||||
val index = it.id.index ?: throw IllegalStateException("DB returned null SecureHash index")
|
||||
Pair(StateRef(txhash = SecureHash.parse(txId), index = index),
|
||||
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
|
||||
val txId = it.id.txId ?: throw IllegalStateException("DB returned null SecureHash transactionId")
|
||||
val index = it.id.index ?: throw IllegalStateException("DB returned null SecureHash index")
|
||||
Pair(StateRef(txhash = SecureHash.parse(txId), index = index),
|
||||
UniquenessProvider.ConsumingTx(
|
||||
id = SecureHash.parse(it.consumingTxHash),
|
||||
inputIndex = it.consumingIndex,
|
||||
requestingParty = Party(
|
||||
name = CordaX500Name.parse(it.party.name),
|
||||
owningKey = parsePublicKeyBase58(it.party.owningKey))))
|
||||
},
|
||||
toPersistentEntity = { (txHash, index) : StateRef, (id, inputIndex, requestingParty): UniquenessProvider.ConsumingTx ->
|
||||
PersistedCommittedState(
|
||||
id = PersistentStateRef(txHash.toString(), index),
|
||||
consumingTxHash = id.toString(),
|
||||
consumingIndex = inputIndex,
|
||||
party = PersistentUniquenessProvider.PersistentParty(requestingParty.name.toString(),
|
||||
requestingParty.owningKey.toBase58String())
|
||||
)
|
||||
},
|
||||
persistentEntityClass = PersistedCommittedState::class.java
|
||||
)
|
||||
},
|
||||
toPersistentEntity = { (txHash, index) : StateRef, (id, inputIndex, requestingParty): UniquenessProvider.ConsumingTx ->
|
||||
PersistedCommittedState(
|
||||
id = PersistentStateRef(txHash.toString(), index),
|
||||
consumingTxHash = id.toString(),
|
||||
consumingIndex = inputIndex,
|
||||
party = PersistentUniquenessProvider.PersistentParty(requestingParty.name.toString(),
|
||||
requestingParty.owningKey.toBase58String())
|
||||
)
|
||||
},
|
||||
persistentEntityClass = PersistedCommittedState::class.java
|
||||
)
|
||||
}
|
||||
|
||||
private class Replica(config: BFTSMaRtConfig,
|
||||
replicaId: Int,
|
||||
|
@ -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()
|
||||
|
@ -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")
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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()
|
||||
|
||||
|
@ -19,10 +19,6 @@ useHTTPS = false
|
||||
h2port = 0
|
||||
useTestClock = false
|
||||
verifierType = InMemory
|
||||
bftSMaRt = {
|
||||
replicaId = -1
|
||||
debug = false
|
||||
}
|
||||
activeMQServer = {
|
||||
bridge = {
|
||||
retryIntervalMs = 5000
|
||||
|
@ -33,7 +33,7 @@ class CordappSmokeTest {
|
||||
p2pPort = port.andIncrement,
|
||||
rpcPort = port.andIncrement,
|
||||
webPort = port.andIncrement,
|
||||
extraServices = emptyList(),
|
||||
isNotary = false,
|
||||
users = listOf(user)
|
||||
)
|
||||
|
||||
|
@ -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>(),
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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]
|
||||
|
@ -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)))
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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 = []
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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"]
|
||||
|
@ -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
|
||||
|
@ -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() }
|
||||
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
|
@ -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() }
|
||||
|
@ -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() }
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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"]
|
||||
}
|
||||
|
@ -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() }
|
||||
|
@ -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)
|
||||
|
@ -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"]
|
||||
}
|
||||
|
@ -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))
|
||||
|
@ -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))
|
||||
|
@ -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()
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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("")
|
||||
|
@ -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 ->
|
||||
|
@ -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() }
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 ->
|
||||
|
@ -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,18 +27,25 @@ class NodeConfig(
|
||||
* The configuration object depends upon the networkMap,
|
||||
* which is mutable.
|
||||
*/
|
||||
fun toFileConfig(): 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()))
|
||||
}))
|
||||
.withValue("webAddress", addressValueFor(webPort))
|
||||
.withValue("rpcAddress", addressValueFor(rpcPort))
|
||||
.withValue("rpcUsers", valueFor(users.map(User::toMap).toList()))
|
||||
.withValue("useTestClock", valueFor(true))
|
||||
//TODO Make use of Any.toConfig
|
||||
private fun toFileConfig(): Config {
|
||||
val config = empty()
|
||||
.withValue("myLegalName", valueFor(legalName.toString()))
|
||||
.withValue("p2pAddress", addressValueFor(p2pPort))
|
||||
.withFallback(optional("networkMapService", networkMap, { c, n ->
|
||||
c.withValue("address", addressValueFor(n.p2pPort))
|
||||
.withValue("legalName", valueFor(n.legalName.toString()))
|
||||
}))
|
||||
.withValue("webAddress", addressValueFor(webPort))
|
||||
.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)
|
||||
|
||||
|
@ -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,20 +42,22 @@ class NodeConfig(
|
||||
* The configuration object depends upon the networkMap,
|
||||
* which is mutable.
|
||||
*/
|
||||
fun toFileConfig(): Config = ConfigFactory.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()))
|
||||
}))
|
||||
.withValue("webAddress", addressValueFor(webPort))
|
||||
.withValue("rpcAddress", addressValueFor(rpcPort))
|
||||
.withValue("rpcUsers", valueFor(users.map(User::toMap).toList()))
|
||||
.withValue("h2port", valueFor(h2Port))
|
||||
.withValue("useTestClock", valueFor(true))
|
||||
.withValue("detectPublicIp", valueFor(false))
|
||||
fun toFileConfig(): Config {
|
||||
return ConfigFactory.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()))
|
||||
}))
|
||||
.withValue("webAddress", addressValueFor(webPort))
|
||||
.withValue("rpcAddress", addressValueFor(rpcPort))
|
||||
.withValue("rpcUsers", valueFor(users.map(User::toMap).toList()))
|
||||
.withValue("h2port", valueFor(h2Port))
|
||||
.withValue("useTestClock", valueFor(true))
|
||||
.withValue("detectPublicIp", valueFor(false))
|
||||
}
|
||||
|
||||
fun toText(): String = toFileConfig().root().render(renderOptions)
|
||||
|
||||
|
@ -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
|
||||
|
@ -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"))
|
||||
|
@ -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]
|
||||
|
Loading…
Reference in New Issue
Block a user