diff --git a/node/src/integration-test/kotlin/net/corda/node/NodeStartupPerformanceTests.kt b/node/src/integration-test/kotlin/net/corda/node/NodeStartupPerformanceTests.kt index f6d75d6f6a..0d2e1081c4 100644 --- a/node/src/integration-test/kotlin/net/corda/node/NodeStartupPerformanceTests.kt +++ b/node/src/integration-test/kotlin/net/corda/node/NodeStartupPerformanceTests.kt @@ -1,6 +1,7 @@ package net.corda.node import com.google.common.base.Stopwatch +import net.corda.node.driver.FalseNetworkMap import net.corda.node.driver.driver import org.junit.Ignore import org.junit.Test @@ -12,7 +13,7 @@ class NodeStartupPerformanceTests { // Measure the startup time of nodes. Note that this includes an RPC roundtrip, which causes e.g. Kryo initialisation. @Test fun `single node startup time`() { - driver(automaticallyStartNetworkMap = false) { + driver(networkMapStrategy = FalseNetworkMap) { startNetworkMapService().get() val times = ArrayList<Long>() for (i in 1 .. 10) { diff --git a/node/src/main/kotlin/net/corda/node/driver/Driver.kt b/node/src/main/kotlin/net/corda/node/driver/Driver.kt index e5cfc40980..7c411a9325 100644 --- a/node/src/main/kotlin/net/corda/node/driver/Driver.kt +++ b/node/src/main/kotlin/net/corda/node/driver/Driver.kt @@ -102,7 +102,7 @@ interface DriverDSLExposedInterface { /** * Starts a network map service node. Note that only a single one should ever be running, so you will probably want - * to set automaticallyStartNetworkMap to false in your [driver] call. + * to set networkMapStrategy to FalseNetworkMap in your [driver] call. */ fun startNetworkMapService(): ListenableFuture<Unit> @@ -201,7 +201,7 @@ fun <A> driver( debugPortAllocation: PortAllocation = PortAllocation.Incremental(5005), systemProperties: Map<String, String> = emptyMap(), useTestClock: Boolean = false, - automaticallyStartNetworkMap: Boolean = true, + networkMapStrategy: NetworkMapStrategy = DedicatedNetworkMap, dsl: DriverDSLExposedInterface.() -> A ) = genericDriver( driverDsl = DriverDSL( @@ -210,7 +210,7 @@ fun <A> driver( systemProperties = systemProperties, driverDirectory = driverDirectory.toAbsolutePath(), useTestClock = useTestClock, - automaticallyStartNetworkMap = automaticallyStartNetworkMap, + networkMapStrategy = networkMapStrategy, isDebug = isDebug ), coerce = { it }, @@ -412,10 +412,9 @@ class DriverDSL( val driverDirectory: Path, val useTestClock: Boolean, val isDebug: Boolean, - val automaticallyStartNetworkMap: Boolean + val networkMapStrategy: NetworkMapStrategy ) : DriverDSLInternalInterface { - private val networkMapLegalName = DUMMY_MAP.name - private val networkMapAddress = portAllocation.nextHostAndPort() + private val dedicatedNetworkMapAddress = portAllocation.nextHostAndPort() val executorService: ListeningScheduledExecutorService = MoreExecutors.listeningDecorator( Executors.newScheduledThreadPool(2, ThreadFactoryBuilder().setNameFormat("driver-pool-thread-%d").build()) ) @@ -488,10 +487,7 @@ class DriverDSL( "rpcAddress" to rpcAddress.toString(), "webAddress" to webAddress.toString(), "extraAdvertisedServiceIds" to advertisedServices.map { it.toString() }, - "networkMapService" to mapOf( - "address" to networkMapAddress.toString(), - "legalName" to networkMapLegalName.toString() - ), + "networkMapService" to networkMapStrategy.serviceConfig(dedicatedNetworkMapAddress, name, p2pAddress), "useTestClock" to useTestClock, "rpcUsers" to rpcUsers.map { mapOf( @@ -578,7 +574,7 @@ class DriverDSL( } override fun start() { - if (automaticallyStartNetworkMap) { + if (networkMapStrategy.startDedicated) { startNetworkMapService() } } @@ -586,6 +582,7 @@ class DriverDSL( override fun startNetworkMapService(): ListenableFuture<Unit> { val debugPort = if (isDebug) debugPortAllocation.nextPort() else null val apiAddress = portAllocation.nextHostAndPort().toString() + val networkMapLegalName = networkMapStrategy.legalName val baseDirectory = driverDirectory / networkMapLegalName.commonName val config = ConfigHelper.loadConfig( baseDirectory = baseDirectory, @@ -595,7 +592,7 @@ class DriverDSL( // TODO: remove the webAddress as NMS doesn't need to run a web server. This will cause all // node port numbers to be shifted, so all demos and docs need to be updated accordingly. "webAddress" to apiAddress, - "p2pAddress" to networkMapAddress.toString(), + "p2pAddress" to dedicatedNetworkMapAddress.toString(), "useTestClock" to useTestClock ) ) @@ -603,7 +600,7 @@ class DriverDSL( log.info("Starting network-map-service") val startNode = startNode(executorService, config.parseAs<FullNodeConfiguration>(), config, quasarJarPath, debugPort, systemProperties) registerProcess(startNode) - return startNode.flatMap { addressMustBeBound(executorService, networkMapAddress, it) } + return startNode.flatMap { addressMustBeBound(executorService, dedicatedNetworkMapAddress, it) } } override fun <A> pollUntilNonNull(pollName: String, pollInterval: Duration, warnCount: Int, check: () -> A?): ListenableFuture<A> { diff --git a/node/src/main/kotlin/net/corda/node/driver/NetworkMapStrategy.kt b/node/src/main/kotlin/net/corda/node/driver/NetworkMapStrategy.kt new file mode 100644 index 0000000000..4926782785 --- /dev/null +++ b/node/src/main/kotlin/net/corda/node/driver/NetworkMapStrategy.kt @@ -0,0 +1,47 @@ +package net.corda.node.driver + +import com.google.common.net.HostAndPort +import net.corda.core.utilities.DUMMY_MAP +import org.bouncycastle.asn1.x500.X500Name + +/** + * Instruct the driver how to set up the network map, if at all. + * @see FalseNetworkMap + * @see DedicatedNetworkMap + * @see NominatedNetworkMap + */ +abstract class NetworkMapStrategy(internal val startDedicated: Boolean, internal val legalName: X500Name) { + internal abstract fun serviceConfig(dedicatedAddress: HostAndPort, nodeName: X500Name, p2pAddress: HostAndPort): Map<String, String>? +} + +private fun toServiceConfig(address: HostAndPort, legalName: X500Name) = mapOf( + "address" to address.toString(), + "legalName" to legalName.toString() +) + +abstract class AbstractDedicatedNetworkMap(start: Boolean) : NetworkMapStrategy(start, DUMMY_MAP.name) { + override fun serviceConfig(dedicatedAddress: HostAndPort, nodeName: X500Name, p2pAddress: HostAndPort) = toServiceConfig(dedicatedAddress, legalName) +} + +/** + * Do not start a network map. + */ +object FalseNetworkMap : AbstractDedicatedNetworkMap(false) + +/** + * Start a dedicated node to host the network map. + */ +object DedicatedNetworkMap : AbstractDedicatedNetworkMap(true) + +/** + * As in gradle-based demos, nominate a node to host the network map, so that there is one fewer node in total than in the [DedicatedNetworkMap] case. + * Will fail if the port you pass in does not match the P2P port the driver assigns to the named node. + */ +class NominatedNetworkMap(legalName: X500Name, private val address: HostAndPort) : NetworkMapStrategy(false, legalName) { + override fun serviceConfig(dedicatedAddress: HostAndPort, nodeName: X500Name, p2pAddress: HostAndPort) = if (nodeName != legalName) { + toServiceConfig(address, legalName) + } else { + p2pAddress == address || throw IllegalArgumentException("Passed-in address $address of nominated network map $legalName is wrong, it should be: $p2pAddress") + null + } +} diff --git a/samples/raft-notary-demo/build.gradle b/samples/raft-notary-demo/build.gradle index 6dd5a66d82..b2348d8940 100644 --- a/samples/raft-notary-demo/build.gradle +++ b/samples/raft-notary-demo/build.gradle @@ -7,7 +7,7 @@ apply plugin: 'net.corda.plugins.cordformation' apply plugin: 'maven-publish' ext { - deployTo = "./build/nodes" + deployTo = "build/nodes" notaryType = "corda.notary.validating.raft" notaryName = "CN=Raft,O=R3,OU=corda,L=Zurich,C=CH" advertisedNotary = "$notaryType|$notaryName" @@ -53,7 +53,13 @@ publishing { } } -task generateNotaryIdentity(type: JavaExec) { +task cleanNodes { + doLast { + delete deployTo + } +} + +task generateNotaryIdentity(type: JavaExec, dependsOn: 'cleanNodes') { classpath = sourceSets.main.runtimeClasspath main = "net.corda.node.utilities.ServiceIdentityGeneratorKt" def nodeDirs = ["$deployTo/Notary1", @@ -66,7 +72,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', 'generateN directory deployTo networkMap "CN=Notary 1,O=R3,OU=corda,L=London,C=UK" node { - name "CN=Party,O=R3,OU=corda,L=London,C=UK" + name "CN=Alice Corp,O=Alice Corp,L=London,C=UK" nearestCity "London" advertisedServices = [] p2pPort 10002 @@ -78,7 +84,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', 'generateN ]]] } node { - name "CN=Counterparty,O=R3,OU=corda,L=London,C=UK" + name "CN=Bob Plc,O=Bob Plc,L=London,C=UK" nearestCity "New York" advertisedServices = [] p2pPort 10005 @@ -89,30 +95,30 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', 'generateN name "CN=Notary 1,O=R3,OU=corda,L=London,C=UK" nearestCity "London" advertisedServices = [advertisedNotary] - p2pPort 10008 - rpcPort 10009 + p2pPort 10009 + rpcPort 10010 cordapps = [] - notaryNodePort 11002 + notaryNodePort 10008 } node { name "CN=Notary 2,O=R3,OU=corda,L=London,C=UK" nearestCity "London" advertisedServices = [advertisedNotary] - p2pPort 10011 - rpcPort 10012 + p2pPort 10013 + rpcPort 10014 cordapps = [] - notaryNodePort 11004 - notaryClusterAddresses = ["localhost:11002"] + notaryNodePort 10012 + notaryClusterAddresses = ["localhost:10008"] } node { name "CN=Notary 3,O=R3,OU=corda,L=London,C=UK" nearestCity "London" advertisedServices = [advertisedNotary] - p2pPort 10014 - rpcPort 10015 + p2pPort 10017 + rpcPort 10018 cordapps = [] - notaryNodePort 11006 - notaryClusterAddresses = ["localhost:11002"] + notaryNodePort 10016 + notaryClusterAddresses = ["localhost:10008"] } } diff --git a/samples/raft-notary-demo/src/main/kotlin/net/corda/notarydemo/Main.kt b/samples/raft-notary-demo/src/main/kotlin/net/corda/notarydemo/Main.kt index 83329aee23..052c5d065e 100644 --- a/samples/raft-notary-demo/src/main/kotlin/net/corda/notarydemo/Main.kt +++ b/samples/raft-notary-demo/src/main/kotlin/net/corda/notarydemo/Main.kt @@ -1,22 +1,30 @@ package net.corda.notarydemo +import com.google.common.net.HostAndPort +import net.corda.core.crypto.appendToCommonName import net.corda.core.div import net.corda.core.utilities.ALICE import net.corda.core.utilities.BOB import net.corda.core.utilities.DUMMY_NOTARY +import net.corda.flows.NotaryFlow +import net.corda.node.driver.NominatedNetworkMap +import net.corda.node.driver.PortAllocation import net.corda.node.driver.driver +import net.corda.node.services.startFlowPermission import net.corda.node.services.transactions.RaftValidatingNotaryService import net.corda.nodeapi.User +import net.corda.notarydemo.flows.DummyIssueAndMove import org.bouncycastle.asn1.x500.X500Name import java.nio.file.Paths /** Creates and starts all nodes required for the demo. */ fun main(args: Array<String>) { - val demoUser = listOf(User("demo", "demo", setOf("StartFlow.net.corda.notarydemo.flows.DummyIssueAndMove", "StartFlow.net.corda.flows.NotaryFlow\$Client"))) - driver(isDebug = true, driverDirectory = Paths.get("build") / "notary-demo-nodes") { + val demoUser = listOf(User("demo", "demo", setOf(startFlowPermission<DummyIssueAndMove>(), startFlowPermission<NotaryFlow.Client>()))) + val networkMap = NominatedNetworkMap(DUMMY_NOTARY.name.appendToCommonName("1"), HostAndPort.fromParts("localhost", 10009)) + driver(isDebug = true, driverDirectory = Paths.get("build") / "notary-demo-nodes", networkMapStrategy = networkMap, portAllocation = PortAllocation.Incremental(10001)) { startNode(ALICE.name, rpcUsers = demoUser) startNode(BOB.name) - startNotaryCluster(DUMMY_NOTARY.name, clusterSize = 3, type = RaftValidatingNotaryService.type) + startNotaryCluster(X500Name("CN=Raft,O=R3,OU=corda,L=Zurich,C=CH"), clusterSize = 3, type = RaftValidatingNotaryService.type) waitForAllNodesToFinish() } } diff --git a/samples/raft-notary-demo/src/main/kotlin/net/corda/notarydemo/NotaryDemo.kt b/samples/raft-notary-demo/src/main/kotlin/net/corda/notarydemo/NotaryDemo.kt index 12d84b1d4a..7136c0685a 100644 --- a/samples/raft-notary-demo/src/main/kotlin/net/corda/notarydemo/NotaryDemo.kt +++ b/samples/raft-notary-demo/src/main/kotlin/net/corda/notarydemo/NotaryDemo.kt @@ -11,6 +11,7 @@ import net.corda.core.getOrThrow import net.corda.core.messaging.CordaRPCOps import net.corda.core.messaging.startFlow import net.corda.core.transactions.SignedTransaction +import net.corda.core.utilities.BOB import net.corda.flows.NotaryFlow import net.corda.nodeapi.config.SSLConfiguration import net.corda.notarydemo.flows.DummyIssueAndMove @@ -39,7 +40,7 @@ private class NotaryDemoClientApi(val rpc: CordaRPCOps) { private val counterpartyNode by lazy { val (parties, partyUpdates) = rpc.networkMapUpdates() partyUpdates.notUsed() - parties.first { it.legalIdentity.name == X500Name("CN=Counterparty,O=R3,OU=corda,L=London,C=UK") } + parties.first { it.legalIdentity.name == BOB.name } } private companion object { diff --git a/samples/simm-valuation-demo/build.gradle b/samples/simm-valuation-demo/build.gradle index cd6cd786ff..59bd02d389 100644 --- a/samples/simm-valuation-demo/build.gradle +++ b/samples/simm-valuation-demo/build.gradle @@ -108,9 +108,11 @@ task npmInstall(type: Exec) { outputs.upToDateWhen { file('src/main/web/node_modules').exists() } } -task cleanWeb() << { - delete 'src/main/resources/simmvaluationweb' - delete 'src/main/web/dist' +task cleanWeb() { + doLast { + delete 'src/main/resources/simmvaluationweb' + delete 'src/main/web/dist' + } } task buildWeb(type: Exec, dependsOn: [cleanWeb, npmInstall]) { diff --git a/test-utils/src/main/kotlin/net/corda/testing/RPCDriver.kt b/test-utils/src/main/kotlin/net/corda/testing/RPCDriver.kt index 2b7c4932ab..ff68c13892 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/RPCDriver.kt +++ b/test-utils/src/main/kotlin/net/corda/testing/RPCDriver.kt @@ -194,7 +194,7 @@ fun <A> rpcDriver( debugPortAllocation: PortAllocation = globalDebugPortAllocation, systemProperties: Map<String, String> = emptyMap(), useTestClock: Boolean = false, - automaticallyStartNetworkMap: Boolean = false, + networkMapStrategy: NetworkMapStrategy = FalseNetworkMap, dsl: RPCDriverExposedDSLInterface.() -> A ) = genericDriver( driverDsl = RPCDriverDSL( @@ -204,7 +204,7 @@ fun <A> rpcDriver( systemProperties = systemProperties, driverDirectory = driverDirectory.toAbsolutePath(), useTestClock = useTestClock, - automaticallyStartNetworkMap = automaticallyStartNetworkMap, + networkMapStrategy = networkMapStrategy, isDebug = isDebug ) ), diff --git a/verifier/src/integration-test/kotlin/net/corda/verifier/VerifierDriver.kt b/verifier/src/integration-test/kotlin/net/corda/verifier/VerifierDriver.kt index d9e5fd3dd2..7d72a466e8 100644 --- a/verifier/src/integration-test/kotlin/net/corda/verifier/VerifierDriver.kt +++ b/verifier/src/integration-test/kotlin/net/corda/verifier/VerifierDriver.kt @@ -78,7 +78,7 @@ fun <A> verifierDriver( debugPortAllocation: PortAllocation = PortAllocation.Incremental(5005), systemProperties: Map<String, String> = emptyMap(), useTestClock: Boolean = false, - automaticallyStartNetworkMap: Boolean = true, + networkMapStrategy: NetworkMapStrategy = DedicatedNetworkMap, dsl: VerifierExposedDSLInterface.() -> A ) = genericDriver( driverDsl = VerifierDriverDSL( @@ -88,7 +88,7 @@ fun <A> verifierDriver( systemProperties = systemProperties, driverDirectory = driverDirectory.toAbsolutePath(), useTestClock = useTestClock, - automaticallyStartNetworkMap = automaticallyStartNetworkMap, + networkMapStrategy = networkMapStrategy, isDebug = isDebug ) ), diff --git a/verifier/src/integration-test/kotlin/net/corda/verifier/VerifierTests.kt b/verifier/src/integration-test/kotlin/net/corda/verifier/VerifierTests.kt index 8531e2f53d..098125bb06 100644 --- a/verifier/src/integration-test/kotlin/net/corda/verifier/VerifierTests.kt +++ b/verifier/src/integration-test/kotlin/net/corda/verifier/VerifierTests.kt @@ -13,6 +13,7 @@ import net.corda.core.utilities.ALICE import net.corda.core.utilities.DUMMY_NOTARY import net.corda.flows.CashIssueFlow import net.corda.flows.CashPaymentFlow +import net.corda.node.driver.FalseNetworkMap import net.corda.node.services.config.VerifierType import net.corda.node.services.transactions.ValidatingNotaryService import org.junit.Test @@ -34,7 +35,7 @@ class VerifierTests { @Test fun `single verifier works with requestor`() { - verifierDriver(automaticallyStartNetworkMap = false) { + verifierDriver(networkMapStrategy = FalseNetworkMap) { val aliceFuture = startVerificationRequestor(ALICE.name) val transactions = generateTransactions(100) val alice = aliceFuture.get() @@ -51,7 +52,7 @@ class VerifierTests { @Test fun `multiple verifiers work with requestor`() { - verifierDriver(automaticallyStartNetworkMap = false) { + verifierDriver(networkMapStrategy = FalseNetworkMap) { val aliceFuture = startVerificationRequestor(ALICE.name) val transactions = generateTransactions(100) val alice = aliceFuture.get() @@ -71,7 +72,7 @@ class VerifierTests { @Test fun `verification redistributes on verifier death`() { - verifierDriver(automaticallyStartNetworkMap = false) { + verifierDriver(networkMapStrategy = FalseNetworkMap) { val aliceFuture = startVerificationRequestor(ALICE.name) val numberOfTransactions = 100 val transactions = generateTransactions(numberOfTransactions) @@ -99,7 +100,7 @@ class VerifierTests { @Test fun `verification request waits until verifier comes online`() { - verifierDriver(automaticallyStartNetworkMap = false) { + verifierDriver(networkMapStrategy = FalseNetworkMap) { val aliceFuture = startVerificationRequestor(ALICE.name) val transactions = generateTransactions(100) val alice = aliceFuture.get()