From bd53a22efaf4d7a05d260e6fd859a2be28952198 Mon Sep 17 00:00:00 2001 From: Shams Asari Date: Mon, 9 Oct 2017 18:57:09 +0100 Subject: [PATCH] Removed extraAdvertisedServiceIds config The remaining use for it was the finance CorDapp for permissioning CCY issuers. Instead this is now taken from a custom config in node.conf. --- .idea/compiler.xml | 1 + build.gradle | 3 - config/dev/generalnodea.conf | 1 - config/dev/generalnodeb.conf | 1 - constants.properties | 2 +- .../net/corda/core/flows/AttachmentTests.kt | 5 +- .../AttachmentSerializationTest.kt | 5 +- docs/source/deploying-a-node.rst | 4 - docs/source/example-code/build.gradle | 2 - .../resources/example-network-map-node.conf | 1 - .../src/main/resources/example-node.conf | 1 - docs/source/hello-world-running.rst | 3 - docs/source/node-services.rst | 8 +- finance/build.gradle | 20 ++ .../finance/flows/CashConfigDataFlowTest.kt | 20 ++ .../corda/finance/flows/CashConfigDataFlow.kt | 53 +++-- .../AbstractStateReplacementFlowTest.java | 22 -- .../java/net/corda/cordform/CordformNode.java | 7 +- .../main/groovy/net/corda/plugins/Node.groovy | 4 +- .../corda/nodeapi/config/ConfigUtilities.kt | 3 +- .../corda/nodeapi/config/ConfigParsingTest.kt | 11 + .../kotlin/net/corda/node/BootTests.kt | 10 +- .../net/corda/node/internal/AbstractNode.kt | 2 - .../kotlin/net/corda/node/internal/Node.kt | 6 +- .../net/corda/node/internal/NodeStartup.kt | 8 +- .../node/services/config/NodeConfiguration.kt | 9 - .../statemachine/FlowStateMachineImpl.kt | 17 +- .../node/messaging/TwoPartyTradeFlowTests.kt | 26 +-- .../config/FullNodeConfigurationTest.kt | 1 - .../network/AbstractNetworkMapServiceTest.kt | 5 +- .../PersistentNetworkMapServiceTest.kt | 6 +- .../statemachine/FlowFrameworkTests.kt | 10 +- samples/attachment-demo/build.gradle | 3 - samples/bank-of-corda-demo/build.gradle | 4 +- samples/irs-demo/build.gradle | 3 - .../net/corda/netmap/simulation/Simulation.kt | 29 +-- samples/simm-valuation-demo/build.gradle | 4 - samples/trader-demo/build.gradle | 4 - .../kotlin/net/corda/testing/driver/Driver.kt | 10 +- .../testing/internal/demorun/CordformUtils.kt | 5 - .../kotlin/net/corda/testing/node/MockNode.kt | 29 +-- .../net/corda/testing/node/NodeBasedTest.kt | 12 +- tools/demobench/README.md | 3 - tools/demobench/build.gradle | 1 + .../net/corda/demobench/explorer/Explorer.kt | 32 +-- .../corda/demobench/model/InstallFactory.kt | 64 ++--- .../corda/demobench/model/NetworkMapConfig.kt | 10 - .../net/corda/demobench/model/NodeConfig.kt | 124 +++++----- .../corda/demobench/model/NodeController.kt | 113 +++++---- .../net/corda/demobench/model/NodeData.kt | 10 +- .../demobench/model/ServiceController.kt | 44 ---- .../kotlin/net/corda/demobench/model/User.kt | 15 -- .../demobench/plugin/PluginController.kt | 10 +- .../demobench/profile/ProfileController.kt | 6 +- .../kotlin/net/corda/demobench/rpc/NodeRPC.kt | 11 +- .../net/corda/demobench/views/NodeTabView.kt | 31 ++- .../corda/demobench/views/NodeTerminalView.kt | 29 +-- .../net/corda/demobench/web/WebServer.kt | 19 +- .../src/main/resources/services.conf | 6 - .../net/corda/demobench/LoggingTestSuite.kt | 2 - .../demobench/model/NetworkMapConfigTest.kt | 22 -- .../corda/demobench/model/NodeConfigTest.kt | 221 +++--------------- .../demobench/model/NodeControllerTest.kt | 57 +++-- .../demobench/model/ServiceControllerTest.kt | 44 ---- .../net/corda/demobench/model/UserTest.kt | 47 ---- .../test/resources/duplicate-services.conf | 3 - .../src/test/resources/empty-services.conf | 0 .../src/test/resources/notary-services.conf | 2 - .../net/corda/explorer/ExplorerSimulation.kt | 14 +- .../corda/explorer/model/IssuerModelTest.kt | 27 --- 70 files changed, 441 insertions(+), 906 deletions(-) create mode 100644 finance/src/integration-test/kotlin/net/corda/finance/flows/CashConfigDataFlowTest.kt delete mode 100644 finance/src/test/java/net/corda/finance/flows/AbstractStateReplacementFlowTest.java delete mode 100644 tools/demobench/src/main/kotlin/net/corda/demobench/model/NetworkMapConfig.kt delete mode 100644 tools/demobench/src/main/kotlin/net/corda/demobench/model/ServiceController.kt delete mode 100644 tools/demobench/src/main/kotlin/net/corda/demobench/model/User.kt delete mode 100644 tools/demobench/src/main/resources/services.conf delete mode 100644 tools/demobench/src/test/kotlin/net/corda/demobench/model/NetworkMapConfigTest.kt delete mode 100644 tools/demobench/src/test/kotlin/net/corda/demobench/model/ServiceControllerTest.kt delete mode 100644 tools/demobench/src/test/kotlin/net/corda/demobench/model/UserTest.kt delete mode 100644 tools/demobench/src/test/resources/duplicate-services.conf delete mode 100644 tools/demobench/src/test/resources/empty-services.conf delete mode 100644 tools/demobench/src/test/resources/notary-services.conf delete mode 100644 tools/explorer/src/test/kotlin/net/corda/explorer/model/IssuerModelTest.kt diff --git a/.idea/compiler.xml b/.idea/compiler.xml index 3516efcb93..5df761b918 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -43,6 +43,7 @@ + diff --git a/build.gradle b/build.gradle index 9b19ced795..f8a21b7789 100644 --- a/build.gradle +++ b/build.gradle @@ -235,13 +235,11 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { node { name "O=Controller,OU=corda,L=London,C=GB" notary = [validating : true] - advertisedServices = [] p2pPort 10002 cordapps = [] } node { name "O=Bank A,OU=corda,L=London,C=GB" - advertisedServices = [] p2pPort 10012 rpcPort 10013 webPort 10014 @@ -249,7 +247,6 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { } node { name "O=Bank B,OU=corda,L=London,C=GB" - advertisedServices = [] p2pPort 10007 rpcPort 10008 webPort 10009 diff --git a/config/dev/generalnodea.conf b/config/dev/generalnodea.conf index 16eb90f526..0089d1cb24 100644 --- a/config/dev/generalnodea.conf +++ b/config/dev/generalnodea.conf @@ -4,7 +4,6 @@ trustStorePassword : "trustpass" p2pAddress : "localhost:10002" rpcAddress : "localhost:10003" webAddress : "localhost:10004" -extraAdvertisedServiceIds : [ "corda.interest_rates" ] networkMapService : { address : "localhost:10000" legalName : "O=Network Map Service,OU=corda,L=London,C=GB" diff --git a/config/dev/generalnodeb.conf b/config/dev/generalnodeb.conf index 1eb839aece..af4e26cc27 100644 --- a/config/dev/generalnodeb.conf +++ b/config/dev/generalnodeb.conf @@ -4,7 +4,6 @@ trustStorePassword : "trustpass" p2pAddress : "localhost:10005" rpcAddress : "localhost:10006" webAddress : "localhost:10007" -extraAdvertisedServiceIds : [ "corda.interest_rates" ] networkMapService : { address : "localhost:10000" legalName : "O=Network Map Service,OU=corda,L=London,C=GB" diff --git a/constants.properties b/constants.properties index 165810dcd2..4591e03dea 100644 --- a/constants.properties +++ b/constants.properties @@ -1,4 +1,4 @@ -gradlePluginsVersion=2.0.0 +gradlePluginsVersion=2.0.1 kotlinVersion=1.1.50 guavaVersion=21.0 bouncycastleVersion=1.57 diff --git a/core/src/test/kotlin/net/corda/core/flows/AttachmentTests.kt b/core/src/test/kotlin/net/corda/core/flows/AttachmentTests.kt index 034c28c834..6a2bf1ef8b 100644 --- a/core/src/test/kotlin/net/corda/core/flows/AttachmentTests.kt +++ b/core/src/test/kotlin/net/corda/core/flows/AttachmentTests.kt @@ -118,10 +118,9 @@ class AttachmentTests { // Make a node that doesn't do sanity checking at load time. val aliceNode = mockNet.createNotaryNode(legalName = ALICE.name, nodeFactory = object : MockNetwork.Factory { override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?, - advertisedServices: Set, id: Int, - notaryIdentity: Pair?, + id: Int, notaryIdentity: Pair?, entropyRoot: BigInteger): MockNetwork.MockNode { - return object : MockNetwork.MockNode(config, network, networkMapAddr, advertisedServices, id, notaryIdentity, entropyRoot) { + return object : MockNetwork.MockNode(config, network, networkMapAddr, id, notaryIdentity, entropyRoot) { override fun start() = super.start().apply { attachments.checkAttachmentsOnLoad = false } } } diff --git a/core/src/test/kotlin/net/corda/core/serialization/AttachmentSerializationTest.kt b/core/src/test/kotlin/net/corda/core/serialization/AttachmentSerializationTest.kt index 4b14705669..89bc81dad9 100644 --- a/core/src/test/kotlin/net/corda/core/serialization/AttachmentSerializationTest.kt +++ b/core/src/test/kotlin/net/corda/core/serialization/AttachmentSerializationTest.kt @@ -162,9 +162,8 @@ class AttachmentSerializationTest { client.dispose() client = mockNet.createNode(client.internals.id, object : MockNetwork.Factory { override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?, - advertisedServices: Set, id: Int, notaryIdentity: Pair?, - entropyRoot: BigInteger): MockNetwork.MockNode { - return object : MockNetwork.MockNode(config, network, networkMapAddr, advertisedServices, id, notaryIdentity, entropyRoot) { + id: Int, notaryIdentity: Pair?, entropyRoot: BigInteger): MockNetwork.MockNode { + return object : MockNetwork.MockNode(config, network, networkMapAddr, id, notaryIdentity, entropyRoot) { override fun start() = super.start().apply { attachments.checkAttachmentsOnLoad = checkAttachmentsOnLoad } } } diff --git a/docs/source/deploying-a-node.rst b/docs/source/deploying-a-node.rst index ec15b75d8b..4457b7d38c 100644 --- a/docs/source/deploying-a-node.rst +++ b/docs/source/deploying-a-node.rst @@ -21,7 +21,6 @@ notary/network map node: node { name "O=Controller,OU=corda,L=London,C=UK" notary = [validating : true] - advertisedServices = [] p2pPort 10002 rpcPort 10003 webPort 10004 @@ -29,7 +28,6 @@ notary/network map node: } node { name "CN=NodeA,O=NodeA,L=London,C=UK" - advertisedServices = [] p2pPort 10005 rpcPort 10006 webPort 10007 @@ -38,7 +36,6 @@ notary/network map node: } node { name "CN=NodeB,O=NodeB,L=New York,C=US" - advertisedServices = [] p2pPort 10008 rpcPort 10009 webPort 10010 @@ -47,7 +44,6 @@ notary/network map node: } node { name "CN=NodeC,O=NodeC,L=Paris,C=FR" - advertisedServices = [] p2pPort 10011 rpcPort 10012 webPort 10013 diff --git a/docs/source/example-code/build.gradle b/docs/source/example-code/build.gradle index ae0b57fc34..a3ea77f4d8 100644 --- a/docs/source/example-code/build.gradle +++ b/docs/source/example-code/build.gradle @@ -77,7 +77,6 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { node { name "O=Notary Service,OU=corda,L=London,C=GB" notary = [validating : true] - advertisedServices = [] p2pPort 10002 rpcPort 10003 webPort 10004 @@ -85,7 +84,6 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { } node { name "O=Alice Corp,L=London,C=GB" - advertisedServices = [] p2pPort 10005 rpcPort 10006 webPort 10007 diff --git a/docs/source/example-code/src/main/resources/example-network-map-node.conf b/docs/source/example-code/src/main/resources/example-network-map-node.conf index fe00d9aa38..e75807bbc7 100644 --- a/docs/source/example-code/src/main/resources/example-network-map-node.conf +++ b/docs/source/example-code/src/main/resources/example-network-map-node.conf @@ -4,5 +4,4 @@ trustStorePassword : "trustpass" p2pAddress : "my-network-map:10000" webAddress : "localhost:10001" sshdAddress : "localhost:10002" -extraAdvertisedServiceIds : [] useHTTPS : false diff --git a/docs/source/example-code/src/main/resources/example-node.conf b/docs/source/example-code/src/main/resources/example-node.conf index d12273c18a..c9bad1eb5b 100644 --- a/docs/source/example-code/src/main/resources/example-node.conf +++ b/docs/source/example-code/src/main/resources/example-node.conf @@ -10,7 +10,6 @@ dataSourceProperties : { p2pAddress : "my-corda-node:10002" rpcAddress : "my-corda-node:10003" webAddress : "localhost:10004" -extraAdvertisedServiceIds : [ "corda.interest_rates" ] networkMapService : { address : "my-network-map:10000" legalName : "O=Network Map Service,OU=corda,L=London,C=GB" diff --git a/docs/source/hello-world-running.rst b/docs/source/hello-world-running.rst index ae91fe0907..ae1592fa82 100644 --- a/docs/source/hello-world-running.rst +++ b/docs/source/hello-world-running.rst @@ -29,14 +29,12 @@ Let's take a look at the nodes we're going to deploy. Open the project's ``build node { name "O=Controller,L=London,C=GB" notary = [validating : true] - advertisedServices = [] p2pPort 10002 rpcPort 10003 cordapps = ["net.corda:corda-finance:$corda_release_version"] } node { name "O=PartyA,L=London,C=GB" - advertisedServices = [] p2pPort 10005 rpcPort 10006 webPort 10007 @@ -45,7 +43,6 @@ Let's take a look at the nodes we're going to deploy. Open the project's ``build } node { name "O=PartyB,L=New York,C=US" - advertisedServices = [] p2pPort 10008 rpcPort 10009 webPort 10010 diff --git a/docs/source/node-services.rst b/docs/source/node-services.rst index 8e25eb6115..3ab92255b6 100644 --- a/docs/source/node-services.rst +++ b/docs/source/node-services.rst @@ -295,12 +295,8 @@ NotaryService (SimpleNotaryService, ValidatingNotaryService, RaftValidatingNotar The ``NotaryService`` is an abstract base class for the various concrete implementations of the Notary server flow. By default, a node does -not run any ``NotaryService`` server component. However, the appropriate -implementation service is automatically started if the relevant -``ServiceType`` id is included in the node's -``extraAdvertisedServiceIds`` configuration property. The node will then -advertise itself as a Notary via the ``NetworkMapService`` and may then -participate in controlling state uniqueness when contacted by nodes +not run any ``NotaryService`` server component. For that you need to specify the ``notary`` config. +The node may then participate in controlling state uniqueness when contacted by nodes using the ``NotaryFlow.Client`` ``subFlow``. The ``SimpleNotaryService`` only offers protection against double spend, but does no further verification. The ``ValidatingNotaryService`` checks diff --git a/finance/build.gradle b/finance/build.gradle index 3386d94b40..c642969785 100644 --- a/finance/build.gradle +++ b/finance/build.gradle @@ -10,12 +10,25 @@ apply plugin: 'com.jfrog.artifactory' description 'Corda finance modules' +sourceSets { + integrationTest { + kotlin { + compileClasspath += main.output + test.output + runtimeClasspath += main.output + test.output + srcDir file('src/integration-test/kotlin') + } + } +} + dependencies { // Note the :finance module is a CorDapp in its own right // and CorDapps using :finance features should use 'cordapp' not 'compile' linkage. cordaCompile project(':core') cordaCompile project(':confidential-identities') + // TODO Remove this once we have app configs + compile "com.typesafe:config:$typesafe_config_version" + testCompile project(':test-utils') testCompile project(path: ':core', configuration: 'testArtifacts') testCompile "junit:junit:$junit_version" @@ -23,6 +36,8 @@ dependencies { configurations { testArtifacts.extendsFrom testRuntime + integrationTestCompile.extendsFrom testCompile + integrationTestRuntime.extendsFrom testRuntime } task testJar(type: Jar) { @@ -30,6 +45,11 @@ task testJar(type: Jar) { from sourceSets.test.output } +task integrationTest(type: Test, dependsOn: []) { + testClassesDirs = sourceSets.integrationTest.output.classesDirs + classpath = sourceSets.integrationTest.runtimeClasspath +} + artifacts { testArtifacts testJar } diff --git a/finance/src/integration-test/kotlin/net/corda/finance/flows/CashConfigDataFlowTest.kt b/finance/src/integration-test/kotlin/net/corda/finance/flows/CashConfigDataFlowTest.kt new file mode 100644 index 0000000000..49351f1e13 --- /dev/null +++ b/finance/src/integration-test/kotlin/net/corda/finance/flows/CashConfigDataFlowTest.kt @@ -0,0 +1,20 @@ +package net.corda.finance.flows + +import net.corda.core.messaging.startFlow +import net.corda.core.utilities.getOrThrow +import net.corda.finance.EUR +import net.corda.finance.USD +import net.corda.testing.driver.driver +import org.assertj.core.api.Assertions.assertThat +import org.junit.Test + +class CashConfigDataFlowTest { + @Test + fun `issuable currencies are read in from node config`() { + driver { + val node = startNode(customOverrides = mapOf("issuableCurrencies" to listOf("EUR", "USD"))).getOrThrow() + val config = node.rpc.startFlow(::CashConfigDataFlow).returnValue.getOrThrow() + assertThat(config.issuableCurrencies).containsExactly(EUR, USD) + } + } +} \ No newline at end of file diff --git a/finance/src/main/kotlin/net/corda/finance/flows/CashConfigDataFlow.kt b/finance/src/main/kotlin/net/corda/finance/flows/CashConfigDataFlow.kt index 59d50403ca..c202d5633c 100644 --- a/finance/src/main/kotlin/net/corda/finance/flows/CashConfigDataFlow.kt +++ b/finance/src/main/kotlin/net/corda/finance/flows/CashConfigDataFlow.kt @@ -1,38 +1,59 @@ package net.corda.finance.flows import co.paralleluniverse.fibers.Suspendable -import net.corda.core.flows.FlowException +import com.typesafe.config.ConfigFactory import net.corda.core.flows.FlowLogic import net.corda.core.flows.StartableByRPC +import net.corda.core.internal.declaredField +import net.corda.core.internal.div +import net.corda.core.internal.read +import net.corda.core.node.AppServiceHub +import net.corda.core.node.services.CordaService import net.corda.core.serialization.CordaSerializable +import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.finance.CHF import net.corda.finance.EUR import net.corda.finance.GBP import net.corda.finance.USD +import net.corda.finance.flows.ConfigHolder.Companion.supportedCurrencies +import java.nio.file.Path import java.util.* +// TODO Until apps have access to their own config, we'll hack things by first getting the baseDirectory, read the node.conf +// again to get our config and store it here for access by our flow +@CordaService +class ConfigHolder(services: AppServiceHub) : SingletonSerializeAsToken() { + companion object { + val supportedCurrencies = listOf(USD, GBP, CHF, EUR) + } + + val issuableCurrencies: List + + init { + // Warning!! You are about to see a major hack! + val baseDirectory = services.declaredField("serviceHub").value + .let { it.javaClass.getMethod("getConfiguration").apply { isAccessible = true }.invoke(it) } + .declaredField("baseDirectory").value + val config = (baseDirectory / "node.conf").read { ConfigFactory.parseReader(it.reader()) } + if (config.hasPath("issuableCurrencies")) { + issuableCurrencies = config.getStringList("issuableCurrencies").map { Currency.getInstance(it) } + require(supportedCurrencies.containsAll(issuableCurrencies)) + } else { + issuableCurrencies = emptyList() + } + } +} + + /** * Flow to obtain cash cordapp app configuration. */ @StartableByRPC class CashConfigDataFlow : FlowLogic() { - companion object { - private val supportedCurrencies = listOf(USD, GBP, CHF, EUR) - } - @Suspendable override fun call(): CashConfiguration { - val issuableCurrencies = supportedCurrencies.mapNotNull { - try { - // Currently it uses checkFlowPermission to determine the list of issuable currency as a temporary hack. - // TODO: get the config from proper configuration source. - checkFlowPermission("corda.issuer.$it", emptyMap()) - it - } catch (e: FlowException) { - null - } - } - return CashConfiguration(issuableCurrencies, supportedCurrencies) + val configHolder = serviceHub.cordaService(ConfigHolder::class.java) + return CashConfiguration(configHolder.issuableCurrencies, supportedCurrencies) } } diff --git a/finance/src/test/java/net/corda/finance/flows/AbstractStateReplacementFlowTest.java b/finance/src/test/java/net/corda/finance/flows/AbstractStateReplacementFlowTest.java deleted file mode 100644 index b753141ac5..0000000000 --- a/finance/src/test/java/net/corda/finance/flows/AbstractStateReplacementFlowTest.java +++ /dev/null @@ -1,22 +0,0 @@ -package net.corda.finance.flows; - -import net.corda.core.flows.AbstractStateReplacementFlow; -import net.corda.core.flows.FlowSession; -import net.corda.core.transactions.SignedTransaction; -import net.corda.core.utilities.ProgressTracker; -import org.jetbrains.annotations.NotNull; - -@SuppressWarnings("unused") -public class AbstractStateReplacementFlowTest { - - // Acceptor used to have a type parameter of Unit which prevented Java code from subclassing it (https://youtrack.jetbrains.com/issue/KT-15964). - private static class TestAcceptorCanBeInheritedInJava extends AbstractStateReplacementFlow.Acceptor { - public TestAcceptorCanBeInheritedInJava(@NotNull FlowSession otherSideSession, @NotNull ProgressTracker progressTracker) { - super(otherSideSession, progressTracker); - } - - @Override - protected void verifyProposal(@NotNull SignedTransaction stx, @NotNull AbstractStateReplacementFlow.Proposal proposal) { - } - } -} diff --git a/gradle-plugins/cordform-common/src/main/java/net/corda/cordform/CordformNode.java b/gradle-plugins/cordform-common/src/main/java/net/corda/cordform/CordformNode.java index 7ecaa9fce9..bca75347d8 100644 --- a/gradle-plugins/cordform-common/src/main/java/net/corda/cordform/CordformNode.java +++ b/gradle-plugins/cordform-common/src/main/java/net/corda/cordform/CordformNode.java @@ -23,11 +23,6 @@ public class CordformNode implements NodeDefinition { return name; } - /** - * A list of advertised services ID strings. - */ - public List advertisedServices = emptyList(); - /** * Set the RPC users for this node. This configuration block allows arbitrary configuration. * The recommended current structure is: @@ -44,6 +39,8 @@ public class CordformNode implements NodeDefinition { */ public Map notary = null; + public Map extraConfig = null; + protected Config config = ConfigFactory.empty(); public Config getConfig() { diff --git a/gradle-plugins/cordformation/src/main/groovy/net/corda/plugins/Node.groovy b/gradle-plugins/cordformation/src/main/groovy/net/corda/plugins/Node.groovy index 262f4df38c..f4169bf456 100644 --- a/gradle-plugins/cordformation/src/main/groovy/net/corda/plugins/Node.groovy +++ b/gradle-plugins/cordformation/src/main/groovy/net/corda/plugins/Node.groovy @@ -123,7 +123,9 @@ class Node extends CordformNode { if (notary) { config = config.withValue("notary", ConfigValueFactory.fromMap(notary)) } - config = config.withValue('extraAdvertisedServiceIds', ConfigValueFactory.fromIterable(advertisedServices*.toString())) + if (extraConfig) { + config = config.withFallback(ConfigFactory.parseMap(extraConfig)) + } } /** diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/config/ConfigUtilities.kt b/node-api/src/main/kotlin/net/corda/nodeapi/config/ConfigUtilities.kt index a67a55db37..cd1118928c 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/config/ConfigUtilities.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/config/ConfigUtilities.kt @@ -12,6 +12,7 @@ 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.Modifier.isStatic import java.lang.reflect.ParameterizedType import java.net.Proxy import java.net.URL @@ -142,7 +143,7 @@ fun Any.toConfig(): Config = ConfigValueFactory.fromMap(toConfigMap()).toConfig( private fun Any.toConfigMap(): Map { val values = HashMap() for (field in javaClass.declaredFields) { - if (field.isSynthetic) continue + if (isStatic(field.modifiers) || field.isSynthetic) continue field.isAccessible = true val value = field.get(this) ?: continue val configValue = if (value is String || value is Boolean || value is Number) { diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/config/ConfigParsingTest.kt b/node-api/src/test/kotlin/net/corda/nodeapi/config/ConfigParsingTest.kt index 8737ac9160..452e25ce78 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/config/ConfigParsingTest.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/config/ConfigParsingTest.kt @@ -181,6 +181,11 @@ class ConfigParsingTest { assertThat(OldData("old").toConfig()).isEqualTo(config("newValue" to "old")) } + @Test + fun `static field`() { + assertThat(DataWithCompanion(3).toConfig()).isEqualTo(config("value" to 3)) + } + private inline fun , reified L : ListData, V : Any> testPropertyType( value1: V, value2: V, @@ -259,6 +264,12 @@ class ConfigParsingTest { data class OldData( @OldConfig("oldValue") val newValue: String) + data class DataWithCompanion(val value: Int) { + companion object { + @Suppress("unused") + val companionValue = 2 + } + } enum class TestEnum { Value1, Value2 } } \ No newline at end of file diff --git a/node/src/integration-test/kotlin/net/corda/node/BootTests.kt b/node/src/integration-test/kotlin/net/corda/node/BootTests.kt index 4b5c17a069..525790ea22 100644 --- a/node/src/integration-test/kotlin/net/corda/node/BootTests.kt +++ b/node/src/integration-test/kotlin/net/corda/node/BootTests.kt @@ -1,20 +1,20 @@ package net.corda.node import co.paralleluniverse.fibers.Suspendable -import net.corda.core.internal.div import net.corda.core.flows.FlowLogic import net.corda.core.flows.StartableByRPC +import net.corda.core.internal.div import net.corda.core.messaging.startFlow import net.corda.core.utilities.getOrThrow -import net.corda.testing.ALICE import net.corda.node.internal.NodeStartup import net.corda.node.services.FlowPermissions.Companion.startFlowPermission +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.ProjectStructure.projectRootDir import net.corda.testing.driver.ListenProcessDeathException import net.corda.testing.driver.NetworkMapStartStrategy -import net.corda.testing.ProjectStructure.projectRootDir import net.corda.testing.driver.driver import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThatThrownBy @@ -60,7 +60,7 @@ class BootTests { fun `node quits on failure to register with network map`() { val tooManyAdvertisedServices = (1..100).map { ServiceInfo(ServiceType.notary.getSubType("$it")) }.toSet() driver(networkMapStartStrategy = NetworkMapStartStrategy.Nominated(ALICE.name)) { - val future = startNode(providedName = ALICE.name, advertisedServices = tooManyAdvertisedServices) + val future = startNode(providedName = ALICE.name) assertFailsWith(ListenProcessDeathException::class) { future.getOrThrow() } } } diff --git a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt index 779604259d..0d92fe6df5 100644 --- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt @@ -70,7 +70,6 @@ import net.corda.node.services.vault.NodeVaultService 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 org.apache.activemq.artemis.utils.ReusableLatch import org.slf4j.Logger import rx.Observable @@ -101,7 +100,6 @@ import net.corda.core.crypto.generateKeyPair as cryptoGenerateKeyPair // In theory the NodeInfo for the node should be passed in, instead, however currently this is constructed by the // AbstractNode. It should be possible to generate the NodeInfo outside of AbstractNode, so it can be passed in. abstract class AbstractNode(config: NodeConfiguration, - val advertisedServices: Set, val platformClock: Clock, protected val versionInfo: VersionInfo, @VisibleForTesting val busyNodeLatch: ReusableLatch = ReusableLatch()) : SingletonSerializeAsToken() { diff --git a/node/src/main/kotlin/net/corda/node/internal/Node.kt b/node/src/main/kotlin/net/corda/node/internal/Node.kt index 696098df29..84b126980a 100644 --- a/node/src/main/kotlin/net/corda/node/internal/Node.kt +++ b/node/src/main/kotlin/net/corda/node/internal/Node.kt @@ -21,7 +21,6 @@ import net.corda.node.services.RPCUserService import net.corda.node.services.RPCUserServiceImpl import net.corda.node.services.api.NetworkMapCacheInternal import net.corda.node.services.api.SchemaService -import net.corda.nodeapi.internal.ServiceInfo import net.corda.node.services.config.FullNodeConfiguration import net.corda.node.services.messaging.ArtemisMessagingServer import net.corda.node.services.messaging.ArtemisMessagingServer.Companion.ipDetectRequestProperty @@ -60,14 +59,11 @@ import kotlin.system.exitProcess * loads important data off disk and starts listening for connections. * * @param configuration This is typically loaded from a TypeSafe HOCON configuration file. - * @param advertisedServices The services this node advertises. This must be a subset of the services it runs, - * but nodes are not required to advertise services they run (hence subset). */ open class Node(override val configuration: FullNodeConfiguration, - advertisedServices: Set, versionInfo: VersionInfo, val initialiseSerialization: Boolean = true -) : AbstractNode(configuration, advertisedServices, createClock(configuration), versionInfo) { +) : AbstractNode(configuration, createClock(configuration), versionInfo) { companion object { private val logger = loggerFor() var renderBasicInfoToConsole = true diff --git a/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt b/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt index 2294024e90..67a06aa2e9 100644 --- a/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt +++ b/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt @@ -12,7 +12,6 @@ import net.corda.node.services.transactions.bftSMaRtSerialFilter import net.corda.node.shell.InteractiveShell import net.corda.node.utilities.registration.HTTPNetworkRegistrationService import net.corda.node.utilities.registration.NetworkRegistrationHelper -import net.corda.nodeapi.internal.ServiceInfo import net.corda.nodeapi.internal.addShutdownHook import org.fusesource.jansi.Ansi import org.fusesource.jansi.AnsiConsole @@ -86,13 +85,10 @@ open class NodeStartup(val args: Array) { open protected fun preNetworkRegistration(conf: FullNodeConfiguration) = Unit - open protected fun createNode(conf: FullNodeConfiguration, versionInfo: VersionInfo, services: Set): Node { - return Node(conf, services, versionInfo) - } + open protected fun createNode(conf: FullNodeConfiguration, versionInfo: VersionInfo): Node = Node(conf, versionInfo) open protected fun startNode(conf: FullNodeConfiguration, versionInfo: VersionInfo, startTime: Long, cmdlineOptions: CmdLineOptions) { - val advertisedServices = conf.calculateServices() - val node = createNode(conf, versionInfo, advertisedServices) + val node = createNode(conf, versionInfo) if (cmdlineOptions.justGenerateNodeInfo) { // Perform the minimum required start-up logic to be able to write a nodeInfo to disk node.generateNodeInfo() diff --git a/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt b/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt index 64b460b2ba..a72465ccee 100644 --- a/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt +++ b/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt @@ -7,7 +7,6 @@ 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.internal.ServiceInfo import java.net.URL import java.nio.file.Path import java.util.* @@ -82,7 +81,6 @@ data class FullNodeConfiguration( // 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, override val notary: NotaryConfig?, override val certificateChainCheckPolicies: List, override val devMode: Boolean = false, @@ -103,13 +101,6 @@ data class FullNodeConfiguration( require(myLegalName.commonName == null) { "Common name must be null: $myLegalName" } require(minimumPlatformVersion >= 1) { "minimumPlatformVersion cannot be less than 1" } } - - fun calculateServices(): Set { - return extraAdvertisedServiceIds - .filter(String::isNotBlank) - .map { ServiceInfo.parse(it) } - .toSet() - } } enum class VerifierType { diff --git a/node/src/main/kotlin/net/corda/node/services/statemachine/FlowStateMachineImpl.kt b/node/src/main/kotlin/net/corda/node/services/statemachine/FlowStateMachineImpl.kt index dea328709a..c61ef66ead 100644 --- a/node/src/main/kotlin/net/corda/node/services/statemachine/FlowStateMachineImpl.kt +++ b/node/src/main/kotlin/net/corda/node/services/statemachine/FlowStateMachineImpl.kt @@ -24,7 +24,6 @@ import net.corda.core.utilities.* import net.corda.node.services.api.FlowAppAuditEvent import net.corda.node.services.api.FlowPermissionAuditEvent import net.corda.node.services.api.ServiceHubInternal -import net.corda.node.services.config.FullNodeConfiguration import net.corda.node.services.statemachine.FlowSessionState.Initiating import net.corda.node.utilities.CordaPersistence import net.corda.node.utilities.DatabaseTransaction @@ -262,10 +261,7 @@ class FlowStateMachineImpl(override val id: StateMachineRunId, // TODO Dummy implementation of access to application specific permission controls and audit logging override fun checkFlowPermission(permissionName: String, extraAuditData: Map) { - // This is a hack to allow cash app access list of permitted issuer currency. - // TODO: replace this with cordapp configuration. - val config = serviceHub.configuration as? FullNodeConfiguration - val permissionGranted = config?.extraAdvertisedServiceIds?.contains(permissionName) != false + val permissionGranted = true // TODO define permission control service on ServiceHubInternal and actually check authorization. val checkPermissionEvent = FlowPermissionAuditEvent( serviceHub.clock.instant(), flowInitiator, @@ -276,6 +272,7 @@ class FlowStateMachineImpl(override val id: StateMachineRunId, permissionName, permissionGranted) serviceHub.auditService.recordAuditEvent(checkPermissionEvent) + @Suppress("ConstantConditionIf") if (!permissionGranted) { throw FlowPermissionException("User $flowInitiator not permissioned for $permissionName on flow $id") } @@ -398,14 +395,8 @@ class FlowStateMachineImpl(override val id: StateMachineRunId, waitForConfirmation: Boolean, retryable: Boolean = false ): FlowSessionInternal { - val session = openSessions[Pair(sessionFlow, otherParty)] - if (session == null) { - throw IllegalStateException("Expected an Uninitiated session for $otherParty") - } - val state = session.state - if (state !is FlowSessionState.Uninitiated) { - throw IllegalStateException("Tried to initiate a session $session, but it's already initiating/initiated") - } + val session = openSessions[Pair(sessionFlow, otherParty)] ?: throw IllegalStateException("Expected an Uninitiated session for $otherParty") + val state = session.state as? FlowSessionState.Uninitiated ?: throw IllegalStateException("Tried to initiate a session $session, but it's already initiating/initiated") logger.trace { "Initiating a new session with ${state.otherParty}" } session.state = FlowSessionState.Initiating(state.otherParty) session.retryable = retryable diff --git a/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt b/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt index 79e224fe76..1d19ed5833 100644 --- a/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt +++ b/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt @@ -275,9 +275,8 @@ class TwoPartyTradeFlowTests(val anonymous: Boolean) { // that Bob was waiting on before the reboot occurred. bobNode = mockNet.createNode(bobAddr.id, object : MockNetwork.Factory { override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?, - advertisedServices: Set, id: Int, notaryIdentity: Pair?, - entropyRoot: BigInteger): MockNetwork.MockNode { - return MockNetwork.MockNode(config, network, networkMapAddr, advertisedServices, bobAddr.id, notaryIdentity, entropyRoot) + id: Int, notaryIdentity: Pair?, entropyRoot: BigInteger): MockNetwork.MockNode { + return MockNetwork.MockNode(config, network, networkMapAddr, bobAddr.id, notaryIdentity, entropyRoot) } }, BOB.name) @@ -312,18 +311,15 @@ class TwoPartyTradeFlowTests(val anonymous: Boolean) { // Creates a mock node with an overridden storage service that uses a RecordingMap, that lets us test the order // of gets and puts. - private fun makeNodeWithTracking( - networkMapAddress: SingleMessageRecipient?, - name: CordaX500Name): StartedNode { + private fun makeNodeWithTracking(name: CordaX500Name): StartedNode { // Create a node in the mock network ... return mockNet.createNode(nodeFactory = object : MockNetwork.Factory { override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?, - advertisedServices: Set, id: Int, - notaryIdentity: Pair?, + id: Int, notaryIdentity: Pair?, entropyRoot: BigInteger): MockNetwork.MockNode { - return object : MockNetwork.MockNode(config, network, networkMapAddr, advertisedServices, id, notaryIdentity, entropyRoot) { + return object : MockNetwork.MockNode(config, network, networkMapAddr, id, notaryIdentity, entropyRoot) { // That constructs a recording tx storage override fun makeTransactionStorage(): WritableTransactionStorage { return RecordingTransactionStorage(database, super.makeTransactionStorage()) @@ -338,9 +334,9 @@ class TwoPartyTradeFlowTests(val anonymous: Boolean) { mockNet = MockNetwork(false) val notaryNode = mockNet.createNotaryNode() - val aliceNode = makeNodeWithTracking(notaryNode.network.myAddress, ALICE.name) - val bobNode = makeNodeWithTracking(notaryNode.network.myAddress, BOB.name) - val bankNode = makeNodeWithTracking(notaryNode.network.myAddress, BOC.name) + val aliceNode = makeNodeWithTracking(ALICE.name) + val bobNode = makeNodeWithTracking(BOB.name) + val bankNode = makeNodeWithTracking(BOC.name) val issuer = bankNode.info.chooseIdentity().ref(1, 2, 3) mockNet.runNetwork() notaryNode.internals.ensureRegistered() @@ -443,9 +439,9 @@ class TwoPartyTradeFlowTests(val anonymous: Boolean) { mockNet = MockNetwork(false) val notaryNode = mockNet.createNotaryNode() - val aliceNode = makeNodeWithTracking(notaryNode.network.myAddress, ALICE.name) - val bobNode = makeNodeWithTracking(notaryNode.network.myAddress, BOB.name) - val bankNode = makeNodeWithTracking(notaryNode.network.myAddress, BOC.name) + val aliceNode = makeNodeWithTracking(ALICE.name) + val bobNode = makeNodeWithTracking(BOB.name) + val bankNode = makeNodeWithTracking(BOC.name) val issuer = bankNode.info.chooseIdentity().ref(1, 2, 3) mockNet.runNetwork() diff --git a/node/src/test/kotlin/net/corda/node/services/config/FullNodeConfigurationTest.kt b/node/src/test/kotlin/net/corda/node/services/config/FullNodeConfigurationTest.kt index d46c32c5a0..bc40165c06 100644 --- a/node/src/test/kotlin/net/corda/node/services/config/FullNodeConfigurationTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/config/FullNodeConfigurationTest.kt @@ -30,7 +30,6 @@ class FullNodeConfigurationTest { p2pAddress = NetworkHostAndPort("localhost", 0), rpcAddress = NetworkHostAndPort("localhost", 1), messagingServerAddress = null, - extraAdvertisedServiceIds = emptyList(), notary = null, certificateChainCheckPolicies = emptyList(), devMode = true, diff --git a/node/src/test/kotlin/net/corda/node/services/network/AbstractNetworkMapServiceTest.kt b/node/src/test/kotlin/net/corda/node/services/network/AbstractNetworkMapServiceTest.kt index 5e0f97e770..b3b9a9f769 100644 --- a/node/src/test/kotlin/net/corda/node/services/network/AbstractNetworkMapServiceTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/network/AbstractNetworkMapServiceTest.kt @@ -8,7 +8,6 @@ import net.corda.core.serialization.deserialize import net.corda.core.utilities.getOrThrow import net.corda.node.internal.StartedNode import net.corda.node.services.api.NetworkMapCacheInternal -import net.corda.nodeapi.internal.ServiceInfo import net.corda.node.services.config.NodeConfiguration import net.corda.node.services.messaging.MessagingService import net.corda.node.services.messaging.send @@ -25,6 +24,7 @@ import net.corda.node.services.network.NetworkMapService.Companion.SUBSCRIPTION_ import net.corda.node.utilities.AddOrRemove import net.corda.node.utilities.AddOrRemove.ADD import net.corda.node.utilities.AddOrRemove.REMOVE +import net.corda.nodeapi.internal.ServiceInfo import net.corda.testing.* import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork.MockNode @@ -270,11 +270,10 @@ abstract class AbstractNetworkMapServiceTest override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?, - advertisedServices: Set, id: Int, notaryIdentity: Pair?, entropyRoot: BigInteger): MockNode { - return object : MockNode(config, network, null, advertisedServices, id, notaryIdentity, entropyRoot) { + return object : MockNode(config, network, null, id, notaryIdentity, entropyRoot) { override fun makeNetworkMapService(network: MessagingService, networkMapCache: NetworkMapCacheInternal) = NullNetworkMapService } } diff --git a/node/src/test/kotlin/net/corda/node/services/network/PersistentNetworkMapServiceTest.kt b/node/src/test/kotlin/net/corda/node/services/network/PersistentNetworkMapServiceTest.kt index 7e8e6a34a1..612c8e943a 100644 --- a/node/src/test/kotlin/net/corda/node/services/network/PersistentNetworkMapServiceTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/network/PersistentNetworkMapServiceTest.kt @@ -2,12 +2,11 @@ package net.corda.node.services.network import net.corda.core.messaging.SingleMessageRecipient import net.corda.node.services.api.NetworkMapCacheInternal -import net.corda.nodeapi.internal.ServiceInfo import net.corda.node.services.config.NodeConfiguration import net.corda.node.services.messaging.MessagingService +import net.corda.nodeapi.internal.ServiceInfo import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork.MockNode -import net.corda.testing.node.MockServices.Companion.MOCK_VERSION_INFO import java.math.BigInteger import java.security.KeyPair @@ -32,11 +31,10 @@ class PersistentNetworkMapServiceTest : AbstractNetworkMapServiceTest, id: Int, notaryIdentity: Pair?, entropyRoot: BigInteger): MockNode { - return object : MockNode(config, network, networkMapAddr, advertisedServices, id, notaryIdentity, entropyRoot) { + return object : MockNode(config, network, networkMapAddr, id, notaryIdentity, entropyRoot) { override fun makeNetworkMapService(network: MessagingService, networkMapCache: NetworkMapCacheInternal) = SwizzleNetworkMapService(network, networkMapCache) } } diff --git a/node/src/test/kotlin/net/corda/node/services/statemachine/FlowFrameworkTests.kt b/node/src/test/kotlin/net/corda/node/services/statemachine/FlowFrameworkTests.kt index 57ca2cebba..00b66b30b9 100644 --- a/node/src/test/kotlin/net/corda/node/services/statemachine/FlowFrameworkTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/statemachine/FlowFrameworkTests.kt @@ -135,7 +135,7 @@ class FlowFrameworkTests { node2.internals.acceptableLiveFiberCountOnStop = 1 node2.dispose() mockNet.runNetwork() - val restoredFlow = node2.restartAndGetRestoredFlow(node1) + val restoredFlow = node2.restartAndGetRestoredFlow() assertThat(restoredFlow.receivedPayloads[0]).isEqualTo("Hello") } @@ -184,7 +184,7 @@ class FlowFrameworkTests { node2.smm.executor.flush() node2.internals.disableDBCloseOnStop() node2.dispose() // kill receiver - val restoredFlow = node2.restartAndGetRestoredFlow(node1) + val restoredFlow = node2.restartAndGetRestoredFlow() assertThat(restoredFlow.receivedPayloads[0]).isEqualTo("Hello") } @@ -214,7 +214,7 @@ class FlowFrameworkTests { assertEquals(1, node2.checkpointStorage.checkpoints().size) // confirm checkpoint node2.services.networkMapCache.clearNetworkMapCache() } - val node2b = mockNet.createNode(node2.internals.id, advertisedServices = *node2.internals.advertisedServices.toTypedArray()) + val node2b = mockNet.createNode(node2.internals.id) node2.internals.manuallyCloseDB() val (firstAgain, fut1) = node2b.getSingleFlow() // Run the network which will also fire up the second flow. First message should get deduped. So message data stays in sync. @@ -685,10 +685,10 @@ class FlowFrameworkTests { //////////////////////////////////////////////////////////////////////////////////////////////////////////// //region Helpers - private inline fun > StartedNode.restartAndGetRestoredFlow(networkMapNode: StartedNode<*>? = null) = internals.run { + private inline fun > StartedNode.restartAndGetRestoredFlow() = internals.run { disableDBCloseOnStop() // Handover DB to new node copy stop() - val newNode = mockNet.createNode(id, advertisedServices = *advertisedServices.toTypedArray()) + val newNode = mockNet.createNode(id) newNode.internals.acceptableLiveFiberCountOnStop = 1 manuallyCloseDB() mockNet.runNetwork() // allow NetworkMapService messages to stabilise and thus start the state machine diff --git a/samples/attachment-demo/build.gradle b/samples/attachment-demo/build.gradle index 5fa296e26d..c331834529 100644 --- a/samples/attachment-demo/build.gradle +++ b/samples/attachment-demo/build.gradle @@ -42,7 +42,6 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { node { name "O=Notary Service,L=Zurich,C=CH" notary = [validating : true] - advertisedServices = [] p2pPort 10002 rpcPort 10003 cordapps = [] @@ -50,7 +49,6 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { } node { name "O=Bank A,L=London,C=GB" - advertisedServices = [] p2pPort 10005 rpcPort 10006 cordapps = [] @@ -58,7 +56,6 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { } node { name "O=Bank B,L=New York,C=US" - advertisedServices = [] p2pPort 10008 rpcPort 10009 webPort 10010 diff --git a/samples/bank-of-corda-demo/build.gradle b/samples/bank-of-corda-demo/build.gradle index 043ead8c0b..da04426168 100644 --- a/samples/bank-of-corda-demo/build.gradle +++ b/samples/bank-of-corda-demo/build.gradle @@ -55,14 +55,13 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { node { name "O=Notary Service,L=Zurich,C=CH" notary = [validating : true] - advertisedServices = [] p2pPort 10002 rpcPort 10003 cordapps = ["net.corda:finance:$corda_release_version"] } node { name "O=BankOfCorda,L=London,C=GB" - advertisedServices = ["corda.issuer.USD"] + extraConfig = [issuableCurrencies : ["USD"]] p2pPort 10005 rpcPort 10006 webPort 10007 @@ -79,7 +78,6 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { } node { name "O=BigCorporation,L=New York,C=US" - advertisedServices = [] p2pPort 10008 rpcPort 10009 webPort 10010 diff --git a/samples/irs-demo/build.gradle b/samples/irs-demo/build.gradle index 7d1dccfb8d..2341793e1f 100644 --- a/samples/irs-demo/build.gradle +++ b/samples/irs-demo/build.gradle @@ -55,7 +55,6 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { node { name "O=Notary Service,L=Zurich,C=CH" notary = [validating : true] - advertisedServices = ["corda.interest_rates"] p2pPort 10002 rpcPort 10003 webPort 10004 @@ -64,7 +63,6 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { } node { name "O=Bank A,L=London,C=GB" - advertisedServices = [] p2pPort 10005 rpcPort 10006 webPort 10007 @@ -73,7 +71,6 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { } node { name "O=Bank B,L=New York,C=US" - advertisedServices = [] p2pPort 10008 rpcPort 10009 webPort 10010 diff --git a/samples/network-visualiser/src/main/kotlin/net/corda/netmap/simulation/Simulation.kt b/samples/network-visualiser/src/main/kotlin/net/corda/netmap/simulation/Simulation.kt index 74529cd530..6c929c47b7 100644 --- a/samples/network-visualiser/src/main/kotlin/net/corda/netmap/simulation/Simulation.kt +++ b/samples/network-visualiser/src/main/kotlin/net/corda/netmap/simulation/Simulation.kt @@ -49,9 +49,9 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean, // This puts together a mock network of SimulatedNodes. open class SimulatedNode(config: NodeConfiguration, mockNet: MockNetwork, networkMapAddress: SingleMessageRecipient?, - advertisedServices: Set, id: Int, notaryIdentity: Pair?, + id: Int, notaryIdentity: Pair?, entropyRoot: BigInteger) - : MockNetwork.MockNode(config, mockNet, networkMapAddress, advertisedServices, id, notaryIdentity, entropyRoot) { + : MockNetwork.MockNode(config, mockNet, networkMapAddress, id, notaryIdentity, entropyRoot) { override val started: StartedNode? get() = uncheckedCast(super.started) override fun findMyLocation(): WorldMapLocation? { return configuration.myLegalName.locality.let { CityDatabase[it] } @@ -62,15 +62,14 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean, var counter = 0 override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?, - advertisedServices: Set, id: Int, notaryIdentity: Pair?, - entropyRoot: BigInteger): SimulatedNode { + id: Int, notaryIdentity: Pair?, entropyRoot: BigInteger): SimulatedNode { val letter = 'A' + counter val (city, country) = bankLocations[counter++ % bankLocations.size] val cfg = testNodeConfiguration( baseDirectory = config.baseDirectory, myLegalName = CordaX500Name(organisation = "Bank $letter", locality = city, country = country)) - return SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, notaryIdentity, entropyRoot) + return SimulatedNode(cfg, network, networkMapAddr, id, notaryIdentity, entropyRoot) } fun createAll(): List { @@ -85,25 +84,23 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean, object NetworkMapNodeFactory : MockNetwork.Factory { override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?, - advertisedServices: Set, id: Int, notaryIdentity: Pair?, - entropyRoot: BigInteger): SimulatedNode { + id: Int, notaryIdentity: Pair?, entropyRoot: BigInteger): SimulatedNode { val cfg = testNodeConfiguration( baseDirectory = config.baseDirectory, myLegalName = DUMMY_MAP.name) - return object : SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, notaryIdentity, entropyRoot) {} + return object : SimulatedNode(cfg, network, networkMapAddr, id, notaryIdentity, entropyRoot) {} } } object NotaryNodeFactory : MockNetwork.Factory { override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?, - advertisedServices: Set, id: Int, notaryIdentity: Pair?, - entropyRoot: BigInteger): SimulatedNode { + id: Int, notaryIdentity: Pair?, entropyRoot: BigInteger): SimulatedNode { requireNotNull(config.notary) val cfg = testNodeConfiguration( baseDirectory = config.baseDirectory, myLegalName = DUMMY_NOTARY.name, notaryConfig = config.notary) - return SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, notaryIdentity, entropyRoot) + return SimulatedNode(cfg, network, networkMapAddr, id, notaryIdentity, entropyRoot) } } @@ -112,12 +109,11 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean, val RATES_SERVICE_NAME = CordaX500Name(organisation = "Rates Service Provider", locality = "Madrid", country = "ES") override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?, - advertisedServices: Set, id: Int, notaryIdentity: Pair?, - entropyRoot: BigInteger): SimulatedNode { + id: Int, notaryIdentity: Pair?, entropyRoot: BigInteger): SimulatedNode { val cfg = testNodeConfiguration( baseDirectory = config.baseDirectory, myLegalName = RATES_SERVICE_NAME) - return object : SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, notaryIdentity, entropyRoot) { + return object : SimulatedNode(cfg, network, networkMapAddr, id, notaryIdentity, entropyRoot) { override fun start() = super.start().apply { registerInitiatedFlow(NodeInterestRates.FixQueryHandler::class.java) registerInitiatedFlow(NodeInterestRates.FixSignHandler::class.java) @@ -133,12 +129,11 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean, object RegulatorFactory : MockNetwork.Factory { override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?, - advertisedServices: Set, id: Int, notaryIdentity: Pair?, - entropyRoot: BigInteger): SimulatedNode { + id: Int, notaryIdentity: Pair?, entropyRoot: BigInteger): SimulatedNode { val cfg = testNodeConfiguration( baseDirectory = config.baseDirectory, myLegalName = DUMMY_REGULATOR.name) - return object : SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, notaryIdentity, entropyRoot) { + return object : SimulatedNode(cfg, network, networkMapAddr, id, notaryIdentity, entropyRoot) { // TODO: Regulatory nodes don't actually exist properly, this is a last minute demo request. // So we just fire a message at a node that doesn't know how to handle it, and it'll ignore it. // But that's fine for visualisation purposes. diff --git a/samples/simm-valuation-demo/build.gradle b/samples/simm-valuation-demo/build.gradle index ec982a20a7..502b2bdee8 100644 --- a/samples/simm-valuation-demo/build.gradle +++ b/samples/simm-valuation-demo/build.gradle @@ -68,13 +68,11 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { node { name "O=Notary Service,L=Zurich,C=CH" notary = [validating : true] - advertisedServices = [] p2pPort 10002 cordapps = ["net.corda:finance:$corda_release_version"] } node { name "O=Bank A,L=London,C=GB" - advertisedServices = [] p2pPort 10004 webPort 10005 rpcPort 10006 @@ -83,7 +81,6 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { } node { name "O=Bank B,L=New York,C=US" - advertisedServices = [] p2pPort 10007 webPort 10008 rpcPort 10009 @@ -92,7 +89,6 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { } node { name "O=Bank C,L=Tokyo,C=JP" - advertisedServices = [] p2pPort 10010 webPort 10011 rpcPort 10012 diff --git a/samples/trader-demo/build.gradle b/samples/trader-demo/build.gradle index 5d0a57663e..8d224d11ab 100644 --- a/samples/trader-demo/build.gradle +++ b/samples/trader-demo/build.gradle @@ -56,13 +56,11 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { node { name "O=Notary Service,L=Zurich,C=CH" notary = [validating : true] - advertisedServices = [] p2pPort 10002 cordapps = ["net.corda:finance:$corda_release_version"] } node { name "O=Bank A,L=London,C=GB" - advertisedServices = [] p2pPort 10005 rpcPort 10006 cordapps = ["net.corda:finance:$corda_release_version"] @@ -70,7 +68,6 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { } node { name "O=Bank B,L=New York,C=US" - advertisedServices = [] p2pPort 10008 rpcPort 10009 cordapps = ["net.corda:finance:$corda_release_version"] @@ -78,7 +75,6 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { } node { name "O=BankOfCorda,L=New York,C=US" - advertisedServices = [] p2pPort 10011 rpcPort 10012 cordapps = ["net.corda:finance:$corda_release_version"] diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/driver/Driver.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/driver/Driver.kt index 9382ce4b3a..9a1ce481ca 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/driver/Driver.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/driver/Driver.kt @@ -30,7 +30,6 @@ 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.addShutdownHook import net.corda.testing.* import net.corda.testing.node.MockServices.Companion.MOCK_VERSION_INFO @@ -78,7 +77,6 @@ interface DriverDSLExposedInterface : CordformContext { * when called from Java code. * @param providedName Optional name of the node, which will be its legal name in [Party]. Defaults to something * random. Note that this must be unique as the driver uses it as a primary key! - * @param advertisedServices The set of services to be advertised by the node. Defaults to empty set. * @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 @@ -88,7 +86,6 @@ interface DriverDSLExposedInterface : CordformContext { fun startNode( defaultParameters: NodeParameters = NodeParameters(), providedName: CordaX500Name? = defaultParameters.providedName, - advertisedServices: Set = defaultParameters.advertisedServices, rpcUsers: List = defaultParameters.rpcUsers, verifierType: VerifierType = defaultParameters.verifierType, customOverrides: Map = defaultParameters.customOverrides, @@ -267,7 +264,6 @@ sealed class PortAllocation { */ data class NodeParameters( val providedName: CordaX500Name? = null, - val advertisedServices: Set = emptySet(), val rpcUsers: List = emptyList(), val verifierType: VerifierType = VerifierType.InMemory, val customOverrides: Map = emptyMap(), @@ -275,7 +271,6 @@ data class NodeParameters( val maximumHeapSize: String = "200m" ) { fun setProvidedName(providedName: CordaX500Name?) = copy(providedName = providedName) - fun setAdvertisedServices(advertisedServices: Set) = copy(advertisedServices = advertisedServices) fun setRpcUsers(rpcUsers: List) = copy(rpcUsers = rpcUsers) fun setVerifierType(verifierType: VerifierType) = copy(verifierType = verifierType) fun setCustomerOverrides(customOverrides: Map) = copy(customOverrides = customOverrides) @@ -686,7 +681,6 @@ class DriverDSL( override fun startNode( defaultParameters: NodeParameters, providedName: CordaX500Name?, - advertisedServices: Set, rpcUsers: List, verifierType: VerifierType, customOverrides: Map, @@ -710,7 +704,6 @@ class DriverDSL( "p2pAddress" to p2pAddress.toString(), "rpcAddress" to rpcAddress.toString(), "webAddress" to webAddress.toString(), - "extraAdvertisedServiceIds" to advertisedServices.map { it.toString() }, "networkMapService" to networkMapServiceConfigLookup(name), "useTestClock" to useTestClock, "rpcUsers" to if (rpcUsers.isEmpty()) defaultRpcUserList else rpcUsers.map { it.toMap() }, @@ -741,7 +734,6 @@ class DriverDSL( baseDirectory = baseDirectory(name), allowMissingConfig = true, configOverrides = node.config + notary + mapOf( - "extraAdvertisedServiceIds" to node.advertisedServices, "networkMapService" to networkMapServiceConfigLookup(name), "rpcUsers" to if (rpcUsers.isEmpty()) defaultRpcUserList else rpcUsers ) @@ -935,7 +927,7 @@ class DriverDSL( // Write node.conf writeConfig(nodeConf.baseDirectory, "node.conf", config) // TODO pass the version in? - val node = Node(nodeConf, nodeConf.calculateServices(), MOCK_VERSION_INFO, initialiseSerialization = false).start() + val node = Node(nodeConf, MOCK_VERSION_INFO, initialiseSerialization = false).start() val nodeThread = thread(name = nodeConf.myLegalName.organisation) { node.internals.run() } diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/internal/demorun/CordformUtils.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/internal/demorun/CordformUtils.kt index 80f078d2bf..dcf0255a9a 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/internal/demorun/CordformUtils.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/internal/demorun/CordformUtils.kt @@ -8,7 +8,6 @@ import net.corda.core.identity.CordaX500Name 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() } @@ -23,7 +22,3 @@ fun CordformNode.rpcUsers(vararg users: User) { fun CordformNode.notary(notaryConfig: NotaryConfig) { notary = notaryConfig.toConfig().root().unwrapped() } - -fun CordformNode.advertisedServices(vararg services: ServiceInfo) { - advertisedServices = services.map { it.toString() } -} diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockNode.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockNode.kt index 43471696df..88824e118e 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockNode.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockNode.kt @@ -115,15 +115,13 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false, * but can be overriden to cause nodes to have stable or colliding identity/service keys. */ fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?, - advertisedServices: Set, id: Int, notaryIdentity: Pair?, - entropyRoot: BigInteger): N + id: Int, notaryIdentity: Pair?, entropyRoot: BigInteger): N } object DefaultFactory : Factory { override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?, - advertisedServices: Set, id: Int, notaryIdentity: Pair?, - entropyRoot: BigInteger): MockNode { - return MockNode(config, network, networkMapAddr, advertisedServices, id, notaryIdentity, entropyRoot) + id: Int, notaryIdentity: Pair?, entropyRoot: BigInteger): MockNode { + return MockNode(config, network, networkMapAddr, id, notaryIdentity, entropyRoot) } } @@ -159,11 +157,10 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false, open class MockNode(config: NodeConfiguration, val mockNet: MockNetwork, override val networkMapAddress: SingleMessageRecipient?, - advertisedServices: Set, val id: Int, internal val notaryIdentity: Pair?, val entropyRoot: BigInteger = BigInteger.valueOf(random63BitValue())) : - AbstractNode(config, advertisedServices, TestClock(), MOCK_VERSION_INFO, mockNet.busyLatch) { + AbstractNode(config, TestClock(), MOCK_VERSION_INFO, mockNet.busyLatch) { var counter = entropyRoot override val log: Logger = loggerFor() override val serverThread: AffinityExecutor = @@ -303,7 +300,6 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false, nodeFactory = nodeFactory ?: defaultFactory, legalName = MOCK_NET_MAP.name, notaryIdentity = null, - advertisedServices = arrayOf(), entropyRoot = BigInteger.valueOf(random63BitValue()), configOverrides = {}, start = true @@ -315,18 +311,16 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false, fun createUnstartedNode(forcedID: Int? = null, legalName: CordaX500Name? = null, notaryIdentity: Pair? = null, entropyRoot: BigInteger = BigInteger.valueOf(random63BitValue()), - vararg advertisedServices: ServiceInfo, configOverrides: (NodeConfiguration) -> Any? = {}): MockNode { - return createUnstartedNode(forcedID, defaultFactory, legalName, notaryIdentity, entropyRoot, *advertisedServices, configOverrides = configOverrides) + return createUnstartedNode(forcedID, defaultFactory, legalName, notaryIdentity, entropyRoot, configOverrides = configOverrides) } fun createUnstartedNode(forcedID: Int? = null, nodeFactory: Factory, legalName: CordaX500Name? = null, notaryIdentity: Pair? = null, entropyRoot: BigInteger = BigInteger.valueOf(random63BitValue()), - vararg advertisedServices: ServiceInfo, configOverrides: (NodeConfiguration) -> Any? = {}): N { val networkMapAddress = networkMapNode.network.myAddress - return createNodeImpl(networkMapAddress, forcedID, nodeFactory, false, legalName, notaryIdentity, entropyRoot, advertisedServices, configOverrides) + return createNodeImpl(networkMapAddress, forcedID, nodeFactory, false, legalName, notaryIdentity, entropyRoot, configOverrides) } /** @@ -340,25 +334,22 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false, fun createNode(forcedID: Int? = null, legalName: CordaX500Name? = null, notaryIdentity: Pair? = null, entropyRoot: BigInteger = BigInteger.valueOf(random63BitValue()), - vararg advertisedServices: ServiceInfo, configOverrides: (NodeConfiguration) -> Any? = {}): StartedNode { - return createNode(forcedID, defaultFactory, legalName, notaryIdentity, entropyRoot, *advertisedServices, configOverrides = configOverrides) + return createNode(forcedID, defaultFactory, legalName, notaryIdentity, entropyRoot, configOverrides = configOverrides) } /** Like the other [createNode] but takes a [Factory] and propagates its [MockNode] subtype. */ fun createNode(forcedID: Int? = null, nodeFactory: Factory, legalName: CordaX500Name? = null, notaryIdentity: Pair? = null, entropyRoot: BigInteger = BigInteger.valueOf(random63BitValue()), - vararg advertisedServices: ServiceInfo, configOverrides: (NodeConfiguration) -> Any? = {}): StartedNode { val networkMapAddress = networkMapNode.network.myAddress - return uncheckedCast(createNodeImpl(networkMapAddress, forcedID, nodeFactory, true, legalName, notaryIdentity, entropyRoot, advertisedServices, configOverrides).started)!! + return uncheckedCast(createNodeImpl(networkMapAddress, forcedID, nodeFactory, true, legalName, notaryIdentity, entropyRoot, configOverrides).started)!! } private fun createNodeImpl(networkMapAddress: SingleMessageRecipient?, forcedID: Int?, nodeFactory: Factory, start: Boolean, legalName: CordaX500Name?, notaryIdentity: Pair?, entropyRoot: BigInteger, - advertisedServices: Array, configOverrides: (NodeConfiguration) -> Any?): N { val id = forcedID ?: nextNodeId++ val config = testNodeConfiguration( @@ -367,7 +358,7 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false, whenever(it.dataSourceProperties).thenReturn(makeTestDataSourceProperties("node_${id}_net_$networkId")) configOverrides(it) } - return nodeFactory.create(config, this, networkMapAddress, advertisedServices.toSet(), id, notaryIdentity, entropyRoot).apply { + return nodeFactory.create(config, this, networkMapAddress, id, notaryIdentity, entropyRoot).apply { if (start) { start() if (threadPerNode && networkMapAddress != null) nodeReadyFuture.getOrThrow() // XXX: What about manually-started nodes? @@ -425,7 +416,7 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false, return when (msgRecipient) { is SingleMessageRecipient -> nodes.single { it.started!!.network.myAddress == msgRecipient } is InMemoryMessagingNetwork.ServiceHandle -> { - nodes.firstOrNull { it.advertisedServices.any { it.name == msgRecipient.party.name } } + nodes.firstOrNull { it.started!!.info.isLegalIdentity(msgRecipient.party) } ?: throw IllegalArgumentException("Couldn't find node advertising service with owning party name: ${msgRecipient.party.name} ") } else -> throw IllegalArgumentException("Method not implemented for different type of message recipients") diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/NodeBasedTest.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/NodeBasedTest.kt index 3a8f838ffb..3d4d4e9d63 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/NodeBasedTest.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/NodeBasedTest.kt @@ -14,7 +14,6 @@ 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.testing.DUMMY_MAP import net.corda.testing.TestDependencyInjectionBase import net.corda.testing.driver.addressMustNotBeBoundFuture @@ -83,11 +82,10 @@ abstract class NodeBasedTest : TestDependencyInjectionBase() { */ fun startNetworkMapNode(legalName: CordaX500Name = DUMMY_MAP.name, platformVersion: Int = 1, - advertisedServices: Set = emptySet(), rpcUsers: List = emptyList(), configOverrides: Map = emptyMap()): StartedNode { check(_networkMapNode == null || _networkMapNode!!.info.legalIdentitiesAndCerts.first().name == legalName) - return startNodeInternal(legalName, platformVersion, advertisedServices, rpcUsers, configOverrides).apply { + return startNodeInternal(legalName, platformVersion, rpcUsers, configOverrides).apply { _networkMapNode = this } } @@ -95,7 +93,6 @@ abstract class NodeBasedTest : TestDependencyInjectionBase() { @JvmOverloads fun startNode(legalName: CordaX500Name, platformVersion: Int = 1, - advertisedServices: Set = emptySet(), rpcUsers: List = emptyList(), configOverrides: Map = emptyMap(), noNetworkMap: Boolean = false, @@ -119,7 +116,6 @@ abstract class NodeBasedTest : TestDependencyInjectionBase() { val node = startNodeInternal( legalName, platformVersion, - advertisedServices, rpcUsers, networkMapConf + configOverrides, noNetworkMap) @@ -175,7 +171,6 @@ abstract class NodeBasedTest : TestDependencyInjectionBase() { private fun startNodeInternal(legalName: CordaX500Name, platformVersion: Int, - advertisedServices: Set, rpcUsers: List, configOverrides: Map, noNetworkMap: Boolean = false): StartedNode { @@ -189,14 +184,15 @@ abstract class NodeBasedTest : TestDependencyInjectionBase() { "myLegalName" to legalName.toString(), "p2pAddress" to p2pAddress, "rpcAddress" to localPort[1].toString(), - "extraAdvertisedServiceIds" to advertisedServices.map { it.toString() }, "rpcUsers" to rpcUsers.map { it.toMap() }, "noNetworkMap" to noNetworkMap ) + configOverrides ) val parsedConfig = config.parseAs() - val node = Node(parsedConfig, parsedConfig.calculateServices(), MOCK_VERSION_INFO.copy(platformVersion = platformVersion), + val node = Node( + parsedConfig, + MOCK_VERSION_INFO.copy(platformVersion = platformVersion), initialiseSerialization = false).start() nodes += node thread(name = legalName.organisation) { diff --git a/tools/demobench/README.md b/tools/demobench/README.md index dc42716039..ad1550b9e5 100644 --- a/tools/demobench/README.md +++ b/tools/demobench/README.md @@ -70,9 +70,6 @@ node in a new tab. ![Configure Bank Node](demobench-configure-bank.png) -This time, there will be additional services available. Select `corda.cash` and -`corda.issuer.GBP`, and then press the `Start node` button. - When you press the `Launch Web Server` this time, your browser should open to a page saying: > ### Installed CorDapps diff --git a/tools/demobench/build.gradle b/tools/demobench/build.gradle index 727a5c8237..c2d1142cc7 100644 --- a/tools/demobench/build.gradle +++ b/tools/demobench/build.gradle @@ -71,6 +71,7 @@ dependencies { testCompile "junit:junit:$junit_version" testCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version" + testCompile "org.assertj:assertj-core:${assertj_version}" testCompile "org.mockito:mockito-core:$mockito_version" } diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/explorer/Explorer.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/explorer/Explorer.kt index a03e83d88c..165388b2b0 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/explorer/Explorer.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/explorer/Explorer.kt @@ -5,13 +5,12 @@ import net.corda.core.internal.div import net.corda.core.internal.list import net.corda.core.utilities.loggerFor import net.corda.demobench.model.JVMConfig -import net.corda.demobench.model.NodeConfig -import net.corda.demobench.model.forceDirectory +import net.corda.demobench.model.NodeConfigWrapper import net.corda.demobench.readErrorLines import tornadofx.* import java.io.IOException import java.nio.file.Files -import java.nio.file.StandardCopyOption.* +import java.nio.file.StandardCopyOption.REPLACE_EXISTING import java.util.concurrent.Executors class Explorer internal constructor(private val explorerController: ExplorerController) : AutoCloseable { @@ -23,29 +22,32 @@ class Explorer internal constructor(private val explorerController: ExplorerCont private var process: Process? = null @Throws(IOException::class) - fun open(config: NodeConfig, onExit: (NodeConfig) -> Unit) { - val explorerDir = config.explorerDir.toFile() + fun open(config: NodeConfigWrapper, onExit: (NodeConfigWrapper) -> Unit) { + val explorerDir = config.explorerDir - if (!explorerDir.forceDirectory()) { - log.warn("Failed to create working directory '{}'", explorerDir.absolutePath) + try { + explorerDir.createDirectories() + } catch (e: IOException) { + log.warn("Failed to create working directory '{}'", explorerDir.toAbsolutePath()) onExit(config) return } + val legalName = config.nodeConfig.myLegalName try { installApps(config) - val user = config.users.elementAt(0) + val user = config.nodeConfig.rpcUsers[0] val p = explorerController.process( "--host=localhost", - "--port=${config.rpcPort}", + "--port=${config.nodeConfig.rpcAddress.port}", "--username=${user.username}", "--password=${user.password}") - .directory(explorerDir) + .directory(explorerDir.toFile()) .start() process = p - log.info("Launched Node Explorer for '{}'", config.legalName) + log.info("Launched Node Explorer for '{}'", legalName) // Close these streams because no-one is using them. safeClose(p.outputStream) @@ -57,21 +59,21 @@ class Explorer internal constructor(private val explorerController: ExplorerCont process = null if (errors.isEmpty()) { - log.info("Node Explorer for '{}' has exited (value={})", config.legalName, exitValue) + log.info("Node Explorer for '{}' has exited (value={})", legalName, exitValue) } else { - log.error("Node Explorer for '{}' has exited (value={}, {})", config.legalName, exitValue, errors) + log.error("Node Explorer for '{}' has exited (value={}, {})", legalName, exitValue, errors) } onExit(config) } } catch (e: IOException) { - log.error("Failed to launch Node Explorer for '{}': {}", config.legalName, e.message) + log.error("Failed to launch Node Explorer for '{}': {}", legalName, e.message) onExit(config) throw e } } - private fun installApps(config: NodeConfig) { + private fun installApps(config: NodeConfigWrapper) { // Make sure that the explorer has cordapps on its class path. This is only necessary because currently apps // require the original class files to deserialise states: Kryo serialisation doesn't let us write generic // tools that work with serialised data structures. But the AMQP serialisation revamp will fix this by diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/model/InstallFactory.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/model/InstallFactory.kt index 4d8876b2ed..f34ebfef6d 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/model/InstallFactory.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/model/InstallFactory.kt @@ -1,76 +1,46 @@ package net.corda.demobench.model import com.typesafe.config.Config -import net.corda.core.identity.CordaX500Name +import net.corda.core.internal.div import net.corda.core.utilities.NetworkHostAndPort +import net.corda.nodeapi.config.parseAs import tornadofx.* import java.io.IOException import java.nio.file.Files import java.nio.file.Path class InstallFactory : Controller() { - private val nodeController by inject() - private val serviceController by inject() @Throws(IOException::class) fun toInstallConfig(config: Config, baseDir: Path): InstallConfig { - val p2pPort = config.parsePort("p2pAddress") - val rpcPort = config.parsePort("rpcAddress") - val webPort = config.parsePort("webAddress") - val h2Port = config.getInt("h2port") - val x500name = CordaX500Name.parse(config.getString("myLegalName")) - val extraServices = config.parseExtraServices("extraAdvertisedServiceIds") - val tempDir = Files.createTempDirectory(baseDir, ".node") - - val nodeConfig = NodeConfig( - tempDir, - x500name, - p2pPort, - rpcPort, - webPort, - h2Port, - extraServices, - config.getObjectList("rpcUsers").map { toUser(it.unwrapped()) }.toList() - ) - - if (config.hasPath("networkMapService")) { - val nmap = config.getConfig("networkMapService") - nodeConfig.networkMap = NetworkMapConfig(CordaX500Name.parse(nmap.getString("legalName")), nmap.parsePort("address")) - } else { - log.info("Node '${nodeConfig.legalName}' is the network map") + fun NetworkHostAndPort.checkPort() { + require(nodeController.isPortValid(port)) { "Invalid port $port" } } - return InstallConfig(tempDir, nodeConfig) - } + val nodeConfig = config.parseAs() + nodeConfig.p2pAddress.checkPort() + nodeConfig.rpcAddress.checkPort() + nodeConfig.webAddress.checkPort() - private fun Config.parsePort(path: String): Int { - val address = this.getString(path) - val port = NetworkHostAndPort.parse(address).port - require(nodeController.isPortValid(port), { "Invalid port $port from '$path'." }) - return port - } + val tempDir = Files.createTempDirectory(baseDir, ".node") - private fun Config.parseExtraServices(path: String): MutableList { - val services = serviceController.services.values.toSortedSet() - return this.getStringList(path) - .filter { !it.isNullOrEmpty() } - .map { svc -> - require(svc in services, { "Unknown service '$svc'." }) - svc - }.toMutableList() - } + if (nodeConfig.isNetworkMap) { + log.info("Node '${nodeConfig.myLegalName}' is the network map") + } + return InstallConfig(tempDir, NodeConfigWrapper(tempDir, nodeConfig)) + } } /** * Wraps the configuration information for a Node * which isn't ready to be instantiated yet. */ -class InstallConfig internal constructor(val baseDir: Path, private val config: NodeConfig) : HasPlugins { +class InstallConfig internal constructor(val baseDir: Path, private val config: NodeConfigWrapper) : HasPlugins { val key = config.key - override val pluginDir: Path = baseDir.resolve("plugins") + override val pluginDir: Path = baseDir / "plugins" fun deleteBaseDir(): Boolean = baseDir.toFile().deleteRecursively() - fun installTo(installDir: Path) = config.moveTo(installDir) + fun installTo(installDir: Path) = config.copy(baseDir = installDir) } diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NetworkMapConfig.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NetworkMapConfig.kt deleted file mode 100644 index 3960ee9a24..0000000000 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NetworkMapConfig.kt +++ /dev/null @@ -1,10 +0,0 @@ -package net.corda.demobench.model - -import net.corda.core.identity.CordaX500Name - -open class NetworkMapConfig(val legalName: CordaX500Name, val p2pPort: Int) { - val key: String = legalName.organisation.toKey() -} - -fun String.stripWhitespace() = String(this.filter { !it.isWhitespace() }.toCharArray()) -fun String.toKey() = stripWhitespace().toLowerCase() diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeConfig.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeConfig.kt index 8cde8f3bcf..e536b3bfb4 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeConfig.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeConfig.kt @@ -1,87 +1,77 @@ package net.corda.demobench.model -import com.typesafe.config.* +import com.typesafe.config.ConfigRenderOptions import net.corda.core.identity.CordaX500Name +import net.corda.core.internal.copyToDirectory +import net.corda.core.internal.createDirectories +import net.corda.core.internal.div +import net.corda.core.utilities.NetworkHostAndPort import net.corda.nodeapi.User -import java.io.File -import java.nio.file.Files +import net.corda.nodeapi.config.toConfig import java.nio.file.Path import java.nio.file.StandardCopyOption -class NodeConfig constructor( - baseDir: Path, - legalName: CordaX500Name, - p2pPort: Int, - val rpcPort: Int, - val webPort: Int, - val h2Port: Int, - val extraServices: MutableList = mutableListOf(), - val users: List = listOf(defaultUser), - var networkMap: NetworkMapConfig? = null -) : NetworkMapConfig(legalName, p2pPort), HasPlugins { - +/** + * This is a subset of FullNodeConfiguration, containing only those configs which we need. The node uses reference.conf + * to fill in the defaults so we're not required to specify them here. + */ +data class NodeConfig( + val myLegalName: CordaX500Name, + val p2pAddress: NetworkHostAndPort, + val rpcAddress: NetworkHostAndPort, + /** This is not used by the node but by the webserver which looks at node.conf. */ + val webAddress: NetworkHostAndPort, + val notary: NotaryService?, + val networkMapService: NetworkMapConfig?, + val h2port: Int, + val rpcUsers: List = listOf(defaultUser), + /** This is an extra config used by the Cash app. */ + val issuableCurrencies: List = emptyList() +) { companion object { val renderOptions: ConfigRenderOptions = ConfigRenderOptions.defaults().setOriginComments(false) val defaultUser = user("guest") } - val nearestCity: String = legalName.locality - val nodeDir: Path = baseDir.resolve(key) - override val pluginDir: Path = nodeDir.resolve("plugins") - val explorerDir: Path = baseDir.resolve("$key-explorer") + @Suppress("unused") + private val detectPublicIp = false + @Suppress("unused") + private val useTestClock = true + val isNetworkMap: Boolean get() = networkMapService == null + + fun toText(): String = toConfig().root().render(renderOptions) +} + +/** + * This is a mirror of NetworkMapInfo. + */ +data class NetworkMapConfig(val legalName: CordaX500Name, val address: NetworkHostAndPort) + +/** + * This is a subset of NotaryConfig. It implements [ExtraService] to avoid unnecessary copying. + */ +data class NotaryService(val validating: Boolean) : ExtraService { + override fun toString(): String = "${if (validating) "V" else "Non-v"}alidating Notary" +} + +// TODO Think of a better name +data class NodeConfigWrapper(val baseDir: Path, val nodeConfig: NodeConfig) : HasPlugins { + val key: String = nodeConfig.myLegalName.organisation.toKey() + val nodeDir: Path = baseDir / key + val explorerDir: Path = baseDir / "$key-explorer" + override val pluginDir: Path = nodeDir / "plugins" var state: NodeState = NodeState.STARTING - val isCashIssuer: Boolean = extraServices.any { - it.startsWith("corda.issuer.") - } - - fun isNetworkMap(): Boolean = networkMap == null - - /* - * The configuration object depends upon the networkMap, - * which is mutable. - */ - 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) - - fun moveTo(baseDir: Path) = NodeConfig( - baseDir, legalName, p2pPort, rpcPort, webPort, h2Port, extraServices, users, networkMap - ) - - fun install(plugins: Collection) { - if (plugins.isNotEmpty() && pluginDir.toFile().forceDirectory()) { - plugins.forEach { - Files.copy(it, pluginDir.resolve(it.fileName.toString()), StandardCopyOption.REPLACE_EXISTING) - } + fun install(cordapps: Collection) { + if (cordapps.isEmpty()) return + pluginDir.createDirectories() + for (cordapp in cordapps) { + cordapp.copyToDirectory(pluginDir, StandardCopyOption.REPLACE_EXISTING) } } - } -private fun valueFor(any: T): ConfigValue? = ConfigValueFactory.fromAnyRef(any) +fun user(name: String) = User(name, "letmein", setOf("ALL")) -private fun addressValueFor(port: Int) = valueFor("localhost:$port") - -private inline fun optional(path: String, obj: T?, body: (Config, T) -> Config): Config { - val config = ConfigFactory.empty() - return if (obj == null) config else body(config, obj).atPath(path) -} - -fun File.forceDirectory(): Boolean = this.isDirectory || this.mkdirs() +fun String.toKey() = filter { !it.isWhitespace() }.toLowerCase() diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeController.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeController.kt index 5bd33b700e..4e7b6a6cc7 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeController.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeController.kt @@ -1,6 +1,12 @@ package net.corda.demobench.model +import javafx.beans.binding.IntegerExpression import net.corda.core.identity.CordaX500Name +import net.corda.core.internal.copyToDirectory +import net.corda.core.internal.createDirectories +import net.corda.core.internal.div +import net.corda.core.internal.noneOrSingle +import net.corda.core.utilities.NetworkHostAndPort import net.corda.demobench.plugin.PluginController import net.corda.demobench.pty.R3Pty import tornadofx.* @@ -22,18 +28,17 @@ class NodeController(check: atRuntime = ::checkExists) : Controller() { private val jvm by inject() private val pluginController by inject() - private val serviceController by inject() private var baseDir: Path = baseDirFor(ManagementFactory.getRuntimeMXBean().startTime) private val cordaPath: Path = jvm.applicationDir.resolve("corda").resolve("corda.jar") private val command = jvm.commandFor(cordaPath).toTypedArray() - private val nodes = LinkedHashMap() + private val nodes = LinkedHashMap() private val port = AtomicInteger(firstPort) private var networkMapConfig: NetworkMapConfig? = null - val activeNodes: List + val activeNodes: List get() = nodes.values.filter { (it.state == NodeState.RUNNING) || (it.state == NodeState.STARTING) } @@ -50,38 +55,45 @@ class NodeController(check: atRuntime = ::checkExists) : Controller() { /** * Validate a Node configuration provided by [net.corda.demobench.views.NodeTabView]. */ - fun validate(nodeData: NodeData): NodeConfig? { + fun validate(nodeData: NodeData): NodeConfigWrapper? { + fun IntegerExpression.toLocalAddress() = NetworkHostAndPort("localhost", value) + val location = nodeData.nearestCity.value - val config = NodeConfig( - baseDir, - CordaX500Name( + val nodeConfig = NodeConfig( + myLegalName = CordaX500Name( organisation = nodeData.legalName.value.trim(), locality = location.description, country = location.countryCode ), - nodeData.p2pPort.value, - nodeData.rpcPort.value, - nodeData.webPort.value, - nodeData.h2Port.value, - nodeData.extraServices.map { serviceController.services[it]!! }.toMutableList() + p2pAddress = nodeData.p2pPort.toLocalAddress(), + rpcAddress = nodeData.rpcPort.toLocalAddress(), + webAddress = nodeData.webPort.toLocalAddress(), + notary = nodeData.extraServices.filterIsInstance().noneOrSingle(), + networkMapService = networkMapConfig, // The first node becomes the network map + h2port = nodeData.h2Port.value, + issuableCurrencies = nodeData.extraServices.filterIsInstance().map { it.currency.toString() } ) - if (nodes.putIfAbsent(config.key, config) != null) { - log.warning("Node with key '${config.key}' already exists.") + val wrapper = NodeConfigWrapper(baseDir, nodeConfig) + + if (nodes.putIfAbsent(wrapper.key, wrapper) != null) { + log.warning("Node with key '${wrapper.key}' already exists.") return null } - // The first node becomes our network map - chooseNetworkMap(config) + if (nodeConfig.isNetworkMap) { + networkMapConfig = nodeConfig.let { NetworkMapConfig(it.myLegalName, it.p2pAddress) } + log.info("Network map provided by: ${nodeConfig.myLegalName}") + } - return config + return wrapper } - fun dispose(config: NodeConfig) { + fun dispose(config: NodeConfigWrapper) { config.state = NodeState.DEAD - if (config.networkMap == null) { - log.warning("Network map service (Node '${config.legalName}') has exited.") + if (config.nodeConfig.isNetworkMap) { + log.warning("Network map service (Node '${config.nodeConfig.myLegalName}') has exited.") } } @@ -95,39 +107,26 @@ class NodeController(check: atRuntime = ::checkExists) : Controller() { fun hasNetworkMap(): Boolean = networkMapConfig != null - private fun chooseNetworkMap(config: NodeConfig) { - if (hasNetworkMap()) { - config.networkMap = networkMapConfig - } else { - networkMapConfig = config - log.info("Network map provided by: ${config.legalName}") - } - } + fun runCorda(pty: R3Pty, config: NodeConfigWrapper): Boolean { + try { + config.nodeDir.createDirectories() - fun runCorda(pty: R3Pty, config: NodeConfig): Boolean { - val nodeDir = config.nodeDir.toFile() + // Install any built-in plugins into the working directory. + pluginController.populate(config) - if (nodeDir.forceDirectory()) { - try { - // Install any built-in plugins into the working directory. - pluginController.populate(config) + // Write this node's configuration file into its working directory. + val confFile = config.nodeDir / "node.conf" + Files.write(confFile, config.nodeConfig.toText().toByteArray()) - // Write this node's configuration file into its working directory. - val confFile = nodeDir.resolve("node.conf") - confFile.writeText(config.toText()) - - // Execute the Corda node - val cordaEnv = System.getenv().toMutableMap().apply { - jvm.setCapsuleCacheDir(this) - } - pty.run(command, cordaEnv, nodeDir.toString()) - log.info("Launched node: ${config.legalName}") - return true - } catch (e: Exception) { - log.log(Level.SEVERE, "Failed to launch Corda: ${e.message}", e) - return false + // Execute the Corda node + val cordaEnv = System.getenv().toMutableMap().apply { + jvm.setCapsuleCacheDir(this) } - } else { + pty.run(command, cordaEnv, config.nodeDir.toString()) + log.info("Launched node: ${config.nodeConfig.myLegalName}") + return true + } catch (e: Exception) { + log.log(Level.SEVERE, "Failed to launch Corda: ${e.message}", e) return false } } @@ -144,15 +143,15 @@ class NodeController(check: atRuntime = ::checkExists) : Controller() { /** * Add a [NodeConfig] object that has been loaded from a profile. */ - fun register(config: NodeConfig): Boolean { + fun register(config: NodeConfigWrapper): Boolean { if (nodes.putIfAbsent(config.key, config) != null) { return false } - updatePort(config) + updatePort(config.nodeConfig) - if ((networkMapConfig == null) && config.isNetworkMap()) { - networkMapConfig = config + if (networkMapConfig == null && config.nodeConfig.isNetworkMap) { + networkMapConfig = config.nodeConfig.let { NetworkMapConfig(it.myLegalName, it.p2pAddress) } } return true @@ -162,12 +161,12 @@ class NodeController(check: atRuntime = ::checkExists) : Controller() { * Creates a node directory that can host a running instance of Corda. */ @Throws(IOException::class) - fun install(config: InstallConfig): NodeConfig { + fun install(config: InstallConfig): NodeConfigWrapper { val installed = config.installTo(baseDir) pluginController.userPluginsFor(config).forEach { - val pluginDir = Files.createDirectories(installed.pluginDir) - val plugin = Files.copy(it, pluginDir.resolve(it.fileName.toString())) + installed.pluginDir.createDirectories() + val plugin = it.copyToDirectory(installed.pluginDir) log.info("Installed: $plugin") } @@ -179,7 +178,7 @@ class NodeController(check: atRuntime = ::checkExists) : Controller() { } private fun updatePort(config: NodeConfig) { - val nextPort = 1 + arrayOf(config.p2pPort, config.rpcPort, config.webPort, config.h2Port).max() as Int + val nextPort = 1 + arrayOf(config.p2pAddress.port, config.rpcAddress.port, config.webAddress.port, config.h2port).max() as Int port.getAndUpdate { Math.max(nextPort, it) } } diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeData.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeData.kt index 90147c5b43..7abdd09775 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeData.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeData.kt @@ -4,8 +4,10 @@ import javafx.beans.property.SimpleIntegerProperty import javafx.beans.property.SimpleListProperty import javafx.beans.property.SimpleObjectProperty import javafx.beans.property.SimpleStringProperty +import javafx.collections.FXCollections.observableArrayList import net.corda.finance.utils.CityDatabase import tornadofx.* +import java.util.* object SuggestedDetails { val banks = listOf( @@ -35,7 +37,7 @@ class NodeData { val rpcPort = SimpleIntegerProperty() val webPort = SimpleIntegerProperty() val h2Port = SimpleIntegerProperty() - val extraServices = SimpleListProperty(mutableListOf().observable()) + val extraServices = SimpleListProperty(observableArrayList()) } class NodeDataModel : ItemViewModel(NodeData()) { @@ -46,3 +48,9 @@ class NodeDataModel : ItemViewModel(NodeData()) { val webPort = bind { item?.webPort } val h2Port = bind { item?.h2Port } } + +interface ExtraService + +data class CurrencyIssuer(val currency: Currency) : ExtraService { + override fun toString(): String = "Issuer $currency" +} diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/model/ServiceController.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/model/ServiceController.kt deleted file mode 100644 index 729f305805..0000000000 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/model/ServiceController.kt +++ /dev/null @@ -1,44 +0,0 @@ -package net.corda.demobench.model - -import tornadofx.* -import java.io.IOException -import java.io.InputStreamReader -import java.net.URL -import java.util.logging.Level - -class ServiceController(resourceName: String = "/services.conf") : Controller() { - - val services: Map = loadConf(resources.url(resourceName)) - - val notaries: Map = services.filter { it.value.startsWith("corda.notary.") } - - val issuers: Map = services.filter { it.value.startsWith("corda.issuer.") } - - /* - * Load our list of known extra Corda services. - */ - private fun loadConf(url: URL?): Map { - return if (url == null) { - emptyMap() - } else { - try { - val map = linkedMapOf() - InputStreamReader(url.openStream()).useLines { sq -> - sq.forEach { line -> - val service = line.split(":").map { it.trim() } - if (service.size != 2) { - log.warning("Encountered corrupted line '$line' while reading services from config: $url") - } else { - map[service[1]] = service[0] - log.info("Supports: $service") - } - } - map - } - } catch (e: IOException) { - log.log(Level.SEVERE, "Failed to load $url: ${e.message}", e) - emptyMap() - } - } - } -} diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/model/User.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/model/User.kt deleted file mode 100644 index c55f3bc5d3..0000000000 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/model/User.kt +++ /dev/null @@ -1,15 +0,0 @@ -@file:JvmName("User") - -package net.corda.demobench.model - -import net.corda.core.internal.uncheckedCast -import net.corda.nodeapi.User -import java.util.* - -fun toUser(map: Map) = User( - map.getOrElse("username", { "none" }) as String, - map.getOrElse("password", { "none" }) as String, - LinkedHashSet(uncheckedCast>(map.getOrElse("permissions", { emptyList() }))) -) - -fun user(name: String) = User(name, "letmein", setOf("ALL")) diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/plugin/PluginController.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/plugin/PluginController.kt index 3e9d52f5ca..ac25d72c55 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/plugin/PluginController.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/plugin/PluginController.kt @@ -5,7 +5,7 @@ import net.corda.core.internal.createDirectories import net.corda.core.internal.exists import net.corda.demobench.model.HasPlugins import net.corda.demobench.model.JVMConfig -import net.corda.demobench.model.NodeConfig +import net.corda.demobench.model.NodeConfigWrapper import tornadofx.* import java.io.IOException import java.nio.file.Files @@ -24,16 +24,14 @@ class PluginController : Controller() { * Install any built-in plugins that this node requires. */ @Throws(IOException::class) - fun populate(config: NodeConfig) { - if (!config.pluginDir.exists()) { - config.pluginDir.createDirectories() - } + fun populate(config: NodeConfigWrapper) { + config.pluginDir.createDirectories() if (finance.exists()) { finance.copyToDirectory(config.pluginDir, StandardCopyOption.REPLACE_EXISTING) log.info("Installed 'Finance' plugin") } // Nodes cannot issue cash unless they contain the "Bank of Corda" plugin. - if (config.isCashIssuer && bankOfCorda.exists()) { + if (config.nodeConfig.issuableCurrencies.isNotEmpty() && bankOfCorda.exists()) { bankOfCorda.copyToDirectory(config.pluginDir, StandardCopyOption.REPLACE_EXISTING) log.info("Installed 'Bank of Corda' plugin") } diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/profile/ProfileController.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/profile/ProfileController.kt index 5d9a773466..c963a1c9ae 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/profile/ProfileController.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/profile/ProfileController.kt @@ -4,6 +4,8 @@ import com.typesafe.config.Config import com.typesafe.config.ConfigFactory import javafx.stage.FileChooser import javafx.stage.FileChooser.ExtensionFilter +import net.corda.core.internal.createDirectories +import net.corda.core.internal.div import net.corda.demobench.model.InstallConfig import net.corda.demobench.model.InstallFactory import net.corda.demobench.model.JVMConfig @@ -58,8 +60,8 @@ class ProfileController : Controller() { FileSystems.newFileSystem(URI.create("jar:" + target.toURI()), mapOf("create" to "true")).use { fs -> configs.forEach { config -> // Write the configuration file. - val nodeDir = Files.createDirectories(fs.getPath(config.key)) - val file = Files.write(nodeDir.resolve("node.conf"), config.toText().toByteArray(UTF_8)) + val nodeDir = fs.getPath(config.key).createDirectories() + val file = Files.write(nodeDir / "node.conf", config.nodeConfig.toText().toByteArray(UTF_8)) log.info("Wrote: $file") // Write all of the non-built-in plugins. diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/rpc/NodeRPC.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/rpc/NodeRPC.kt index 339eed00ad..a92dbd4a3d 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/rpc/NodeRPC.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/rpc/NodeRPC.kt @@ -5,18 +5,17 @@ import net.corda.client.rpc.CordaRPCConnection import net.corda.core.messaging.CordaRPCOps import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.loggerFor -import net.corda.demobench.model.NodeConfig +import net.corda.demobench.model.NodeConfigWrapper import java.util.* import java.util.concurrent.TimeUnit.SECONDS -class NodeRPC(config: NodeConfig, start: (NodeConfig, CordaRPCOps) -> Unit, invoke: (CordaRPCOps) -> Unit) : AutoCloseable { - +class NodeRPC(config: NodeConfigWrapper, start: (NodeConfigWrapper, CordaRPCOps) -> Unit, invoke: (CordaRPCOps) -> Unit) : AutoCloseable { private companion object { val log = loggerFor() val oneSecond = SECONDS.toMillis(1) } - private val rpcClient = CordaRPCClient(NetworkHostAndPort("localhost", config.rpcPort)) + private val rpcClient = CordaRPCClient(NetworkHostAndPort("localhost", config.nodeConfig.rpcAddress.port)) private var rpcConnection: CordaRPCConnection? = null private val timer = Timer() @@ -24,7 +23,7 @@ class NodeRPC(config: NodeConfig, start: (NodeConfig, CordaRPCOps) -> Unit, invo val setupTask = object : TimerTask() { override fun run() { try { - val user = config.users.elementAt(0) + val user = config.nodeConfig.rpcUsers[0] val connection = rpcClient.start(user.username, user.password) rpcConnection = connection val ops = connection.proxy @@ -42,7 +41,7 @@ class NodeRPC(config: NodeConfig, start: (NodeConfig, CordaRPCOps) -> Unit, invo } }, 0, oneSecond) } catch (e: Exception) { - log.warn("Node '{}' not ready yet (Error: {})", config.legalName, e.message) + log.warn("Node '{}' not ready yet (Error: {})", config.nodeConfig.myLegalName, e.message) } } } diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/views/NodeTabView.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/views/NodeTabView.kt index f36edea872..c9f993a5c2 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/views/NodeTabView.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/views/NodeTabView.kt @@ -16,10 +16,14 @@ import javafx.scene.layout.Priority import javafx.stage.FileChooser import javafx.util.StringConverter import net.corda.core.internal.* -import net.corda.finance.utils.CityDatabase -import net.corda.finance.utils.WorldMapLocation import net.corda.demobench.model.* import net.corda.demobench.ui.CloseableTab +import net.corda.finance.CHF +import net.corda.finance.EUR +import net.corda.finance.GBP +import net.corda.finance.USD +import net.corda.finance.utils.CityDatabase +import net.corda.finance.utils.WorldMapLocation import org.controlsfx.control.CheckListView import tornadofx.* import java.nio.file.Path @@ -39,10 +43,10 @@ class NodeTabView : Fragment() { val cordappPathsFile: Path = jvm.dataHome / "cordapp-paths.txt" fun loadDefaultCordappPaths(): MutableList { - if (cordappPathsFile.exists()) - return cordappPathsFile.readAllLines().map { Paths.get(it) }.filter { it.exists() }.toMutableList() + return if (cordappPathsFile.exists()) + cordappPathsFile.readAllLines().map { Paths.get(it) }.filter { it.exists() }.toMutableList() else - return ArrayList() + ArrayList() } // This is shared between tabs. @@ -58,11 +62,9 @@ class NodeTabView : Fragment() { } private val nodeController by inject() - private val serviceController by inject() private val chooser = FileChooser() private val model = NodeDataModel() - private val availableServices: List = if (nodeController.hasNetworkMap()) serviceController.issuers.keys.toList() else serviceController.notaries.keys.toList() private val nodeTerminalView = find() private val nodeConfigView = stackpane { @@ -112,8 +114,13 @@ class NodeTabView : Fragment() { fieldset("Additional configuration") { styleClass.addAll("services-panel") + val extraServices = if (nodeController.hasNetworkMap()) { + listOf(USD, GBP, CHF, EUR).map { CurrencyIssuer(it) } + } else { + listOf(NotaryService(true), NotaryService(false)) + } - val servicesList = CheckListView(availableServices.observable()).apply { + val servicesList = CheckListView(extraServices.observable()).apply { vboxConstraints { vGrow = Priority.ALWAYS } model.item.extraServices.set(checkModel.checkedItems) if (!nodeController.hasNetworkMap()) { @@ -263,17 +270,17 @@ class NodeTabView : Fragment() { /** * Launches a preconfigured Corda node, e.g. from a saved profile. */ - fun launch(config: NodeConfig) { + fun launch(config: NodeConfigWrapper) { nodeController.register(config) launchNode(config) } - private fun launchNode(config: NodeConfig) { - val countryCode = CityDatabase.cityMap[config.nearestCity]?.countryCode + private fun launchNode(config: NodeConfigWrapper) { + val countryCode = CityDatabase.cityMap[config.nodeConfig.myLegalName.locality]?.countryCode if (countryCode != null) { nodeTab.graphic = ImageView(flags.get()[countryCode]).apply { fitWidth = 24.0; isPreserveRatio = true } } - nodeTab.text = config.legalName.organisation + nodeTab.text = config.nodeConfig.myLegalName.organisation nodeTerminalView.open(config) { exitCode -> Platform.runLater { if (exitCode == 0) { diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/views/NodeTerminalView.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/views/NodeTerminalView.kt index 6046aa0e11..d1e2f59492 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/views/NodeTerminalView.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/views/NodeTerminalView.kt @@ -20,6 +20,7 @@ import net.corda.core.messaging.vaultTrackBy import net.corda.core.node.services.vault.PageSpecification import net.corda.demobench.explorer.ExplorerController import net.corda.demobench.model.NodeConfig +import net.corda.demobench.model.NodeConfigWrapper import net.corda.demobench.model.NodeController import net.corda.demobench.model.NodeState import net.corda.demobench.pty.R3Pty @@ -69,8 +70,8 @@ class NodeTerminalView : Fragment() { private lateinit var logo: ImageView private lateinit var swingTerminal: SwingNode - fun open(config: NodeConfig, onExit: (Int) -> Unit) { - nodeName.text = config.legalName.organisation + fun open(config: NodeConfigWrapper, onExit: (Int) -> Unit) { + nodeName.text = config.nodeConfig.myLegalName.organisation swingTerminal = SwingNode() swingTerminal.setOnMouseClicked { @@ -85,13 +86,13 @@ class NodeTerminalView : Fragment() { root.isVisible = true SwingUtilities.invokeLater({ - val r3pty = R3Pty(config.legalName, TerminalSettingsProvider(), Dimension(160, 80), onExit) + val r3pty = R3Pty(config.nodeConfig.myLegalName, TerminalSettingsProvider(), Dimension(160, 80), onExit) pty = r3pty if (nodeController.runCorda(r3pty, config)) { swingTerminal.content = r3pty.terminal - configureDatabaseButton(config) + configureDatabaseButton(config.nodeConfig) configureExplorerButton(config) configureWebButton(config) @@ -105,7 +106,7 @@ class NodeTerminalView : Fragment() { * and close the RPC client if it has. */ if (!r3pty.isConnected) { - log.severe("Node '${config.legalName}' has failed to start.") + log.severe("Node '${config.nodeConfig.myLegalName}' has failed to start.") swingTerminal.content = null rpc?.close() } @@ -119,7 +120,7 @@ class NodeTerminalView : Fragment() { * launched the explorer and only reenable it when * the explorer has exited. */ - private fun configureExplorerButton(config: NodeConfig) { + private fun configureExplorerButton(config: NodeConfigWrapper) { launchExplorerButton.setOnAction { launchExplorerButton.isDisable = true @@ -131,7 +132,7 @@ class NodeTerminalView : Fragment() { private fun configureDatabaseButton(config: NodeConfig) { viewDatabaseButton.setOnAction { - viewer.openBrowser(config.h2Port) + viewer.openBrowser(config.h2port) } } @@ -144,7 +145,7 @@ class NodeTerminalView : Fragment() { * launched the web server and only reenable it when * the web server has exited. */ - private fun configureWebButton(config: NodeConfig) { + private fun configureWebButton(config: NodeConfigWrapper) { launchWebButton.setOnAction { if (webURL != null) { app.hostServices.showDocument(webURL.toString()) @@ -161,12 +162,12 @@ class NodeTerminalView : Fragment() { launchWebButton.text = "" launchWebButton.graphic = ProgressIndicator() - log.info("Starting web server for ${config.legalName}") + log.info("Starting web server for ${config.nodeConfig.myLegalName}") webServer.open(config).then { Platform.runLater { launchWebButton.graphic = null it.match(success = { - log.info("Web server for ${config.legalName} started on $it") + log.info("Web server for ${config.nodeConfig.myLegalName} started on $it") webURL = it launchWebButton.text = "Reopen\nweb site" app.hostServices.showDocument(it.toString()) @@ -178,13 +179,13 @@ class NodeTerminalView : Fragment() { } } - private fun launchRPC(config: NodeConfig) = NodeRPC( + private fun launchRPC(config: NodeConfigWrapper) = NodeRPC( config = config, start = this::initialise, invoke = this::pollCashBalances ) - private fun initialise(config: NodeConfig, ops: CordaRPCOps) { + private fun initialise(config: NodeConfigWrapper, ops: CordaRPCOps) { try { val (txInit, txNext) = ops.internalVerifiedTransactionsFeed() val (stateInit, stateNext) = ops.vaultTrackBy(paging = pageSpecification) @@ -212,7 +213,7 @@ class NodeTerminalView : Fragment() { } config.state = NodeState.RUNNING - log.info("Node '${config.legalName}' is now ready.") + log.info("Node '${config.nodeConfig.myLegalName}' is now ready.") header.isDisable = false } @@ -225,7 +226,7 @@ class NodeTerminalView : Fragment() { ) Platform.runLater { - balance.value = if (cashBalances.isNullOrEmpty()) "0" else cashBalances + balance.value = if (cashBalances.isEmpty()) "0" else cashBalances } } catch (e: ClassNotFoundException) { // TODO: Remove this special case once Rick's serialisation work means we can deserialise states that weren't on our own classpath. diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/web/WebServer.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/web/WebServer.kt index 4aec34a73b..5fe5f96fe1 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/web/WebServer.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/web/WebServer.kt @@ -2,11 +2,11 @@ package net.corda.demobench.web import com.google.common.util.concurrent.RateLimiter import net.corda.core.concurrent.CordaFuture -import net.corda.core.utilities.minutes import net.corda.core.internal.concurrent.openFuture import net.corda.core.internal.until import net.corda.core.utilities.loggerFor -import net.corda.demobench.model.NodeConfig +import net.corda.core.utilities.minutes +import net.corda.demobench.model.NodeConfigWrapper import net.corda.demobench.readErrorLines import java.io.IOException import java.net.HttpURLConnection @@ -25,7 +25,7 @@ class WebServer internal constructor(private val webServerController: WebServerC private var process: Process? = null @Throws(IOException::class) - fun open(config: NodeConfig): CordaFuture { + fun open(config: NodeConfigWrapper): CordaFuture { val nodeDir = config.nodeDir.toFile() if (!nodeDir.isDirectory) { @@ -33,13 +33,14 @@ class WebServer internal constructor(private val webServerController: WebServerC return openFuture() } + val legalName = config.nodeConfig.myLegalName try { val p = webServerController.process() .directory(nodeDir) .start() process = p - log.info("Launched Web Server for '{}'", config.legalName) + log.info("Launched Web Server for '{}'", legalName) // Close these streams because no-one is using them. safeClose(p.outputStream) @@ -51,22 +52,22 @@ class WebServer internal constructor(private val webServerController: WebServerC process = null if (errors.isEmpty()) { - log.info("Web Server for '{}' has exited (value={})", config.legalName, exitValue) + log.info("Web Server for '{}' has exited (value={})", legalName, exitValue) } else { - log.error("Web Server for '{}' has exited (value={}, {})", config.legalName, exitValue, errors) + log.error("Web Server for '{}' has exited (value={}, {})", legalName, exitValue, errors) } } val future = openFuture() thread { future.capture { - log.info("Waiting for web server for ${config.legalName} to start ...") - waitForStart(config.webPort) + log.info("Waiting for web server for $legalName to start ...") + waitForStart(config.nodeConfig.webAddress.port) } } return future } catch (e: IOException) { - log.error("Failed to launch Web Server for '{}': {}", config.legalName, e.message) + log.error("Failed to launch Web Server for '{}': {}", legalName, e.message) throw e } } diff --git a/tools/demobench/src/main/resources/services.conf b/tools/demobench/src/main/resources/services.conf deleted file mode 100644 index d8319ddccb..0000000000 --- a/tools/demobench/src/main/resources/services.conf +++ /dev/null @@ -1,6 +0,0 @@ -corda.notary.validating : Validating Notary -corda.notary.simple : Non-validating Notary -corda.issuer.USD : Issuer USD -corda.issuer.GBP : Issuer GBP -corda.issuer.CHF : Issuer CHF -corda.issuer.EUR : Issuer EUR \ No newline at end of file diff --git a/tools/demobench/src/test/kotlin/net/corda/demobench/LoggingTestSuite.kt b/tools/demobench/src/test/kotlin/net/corda/demobench/LoggingTestSuite.kt index 946718c42a..33e9d4169b 100644 --- a/tools/demobench/src/test/kotlin/net/corda/demobench/LoggingTestSuite.kt +++ b/tools/demobench/src/test/kotlin/net/corda/demobench/LoggingTestSuite.kt @@ -3,7 +3,6 @@ package net.corda.demobench import net.corda.demobench.config.LoggingConfig import net.corda.demobench.model.JVMConfigTest import net.corda.demobench.model.NodeControllerTest -import net.corda.demobench.model.ServiceControllerTest import org.junit.BeforeClass import org.junit.runner.RunWith import org.junit.runners.Suite @@ -13,7 +12,6 @@ import org.junit.runners.Suite */ @RunWith(Suite::class) @Suite.SuiteClasses( - ServiceControllerTest::class, NodeControllerTest::class, JVMConfigTest::class ) diff --git a/tools/demobench/src/test/kotlin/net/corda/demobench/model/NetworkMapConfigTest.kt b/tools/demobench/src/test/kotlin/net/corda/demobench/model/NetworkMapConfigTest.kt deleted file mode 100644 index 0c9892f340..0000000000 --- a/tools/demobench/src/test/kotlin/net/corda/demobench/model/NetworkMapConfigTest.kt +++ /dev/null @@ -1,22 +0,0 @@ -package net.corda.demobench.model - -import net.corda.core.identity.CordaX500Name -import org.bouncycastle.asn1.x500.X500Name -import org.junit.Ignore -import org.junit.Test -import kotlin.test.assertEquals - -class NetworkMapConfigTest { - @Ignore("This has been superseded by validation logic in CordaX500Name") - @Test - fun keyValue() { - val config = NetworkMapConfig(CordaX500Name.parse("O=My\tNasty Little\rLabel\n,L=London,C=GB"), 10000) - assertEquals("mynastylittlelabel", config.key) - } - - @Test - fun removeWhitespace() { - assertEquals("OneTwoThreeFour!", "One\tTwo \rThree\r\nFour!".stripWhitespace()) - } - -} diff --git a/tools/demobench/src/test/kotlin/net/corda/demobench/model/NodeConfigTest.kt b/tools/demobench/src/test/kotlin/net/corda/demobench/model/NodeConfigTest.kt index 4970d68c11..e8fb14dff4 100644 --- a/tools/demobench/src/test/kotlin/net/corda/demobench/model/NodeConfigTest.kt +++ b/tools/demobench/src/test/kotlin/net/corda/demobench/model/NodeConfigTest.kt @@ -1,190 +1,30 @@ package net.corda.demobench.model -import com.fasterxml.jackson.annotation.JsonInclude -import com.fasterxml.jackson.databind.ObjectMapper -import com.fasterxml.jackson.databind.SerializationFeature import com.typesafe.config.ConfigFactory import com.typesafe.config.ConfigValueFactory import net.corda.core.identity.CordaX500Name -import net.corda.core.internal.div import net.corda.core.utilities.NetworkHostAndPort import net.corda.node.internal.NetworkMapInfo import net.corda.node.services.config.FullNodeConfiguration import net.corda.nodeapi.User import net.corda.nodeapi.config.parseAs +import net.corda.nodeapi.config.toConfig import net.corda.testing.DUMMY_NOTARY import net.corda.webserver.WebServerConfig +import org.assertj.core.api.Assertions.assertThat import org.junit.Test -import java.io.StringWriter import java.nio.file.Path import java.nio.file.Paths import kotlin.test.assertEquals import kotlin.test.assertFalse -import kotlin.test.assertNull import kotlin.test.assertTrue - class NodeConfigTest { - companion object { private val baseDir: Path = Paths.get(".").toAbsolutePath() private val myLegalName = CordaX500Name(organisation = "My Name", locality = "New York", country = "US") } - @Test - fun `test name`() { - val config = createConfig(legalName = myLegalName) - assertEquals(myLegalName, config.legalName) - assertEquals("myname", config.key) - } - - @Test - fun `test node directory`() { - val config = createConfig(legalName = myLegalName) - assertEquals(baseDir / "myname", config.nodeDir) - } - - @Test - fun `test explorer directory`() { - val config = createConfig(legalName = myLegalName) - assertEquals(baseDir / "myname-explorer", config.explorerDir) - } - - @Test - fun `test plugin directory`() { - val config = createConfig(legalName = myLegalName) - assertEquals(baseDir / "myname" / "plugins", config.pluginDir) - } - - @Test - fun `test P2P port`() { - val config = createConfig(p2pPort = 10001) - assertEquals(10001, config.p2pPort) - } - - @Test - fun `test rpc port`() { - val config = createConfig(rpcPort = 40002) - assertEquals(40002, config.rpcPort) - } - - @Test - fun `test web port`() { - val config = createConfig(webPort = 20001) - assertEquals(20001, config.webPort) - } - - @Test - fun `test H2 port`() { - val config = createConfig(h2Port = 30001) - assertEquals(30001, config.h2Port) - } - - @Test - fun `test services`() { - val config = createConfig(services = mutableListOf("my.service")) - assertEquals(listOf("my.service"), config.extraServices) - } - - @Test - fun `test users`() { - val config = createConfig(users = listOf(user("myuser"))) - assertEquals(listOf(user("myuser")), config.users) - } - - @Test - fun `test default state`() { - val config = createConfig() - assertEquals(NodeState.STARTING, config.state) - } - - @Test - fun `test network map`() { - val config = createConfig() - assertNull(config.networkMap) - assertTrue(config.isNetworkMap()) - } - - @Test - fun `test cash issuer`() { - val config = createConfig(services = mutableListOf("corda.issuer.GBP")) - assertTrue(config.isCashIssuer) - } - - @Test - fun `test not cash issuer`() { - val config = createConfig(services = mutableListOf("corda.issuerubbish")) - assertFalse(config.isCashIssuer) - } - - /** - * Reformat JSON via Jackson to ensure a consistent format for comparison purposes. - */ - private fun prettyPrint(content: String): String { - val mapper = ObjectMapper() - mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL) - mapper.enable(SerializationFeature.INDENT_OUTPUT) - val sw = StringWriter() - val parsed = mapper.readTree(content) - mapper.writeValue(sw, parsed) - return sw.toString() - } - - @Test - fun `test config text`() { - val config = createConfig( - legalName = myLegalName, - p2pPort = 10001, - rpcPort = 40002, - webPort = 20001, - h2Port = 30001, - services = mutableListOf("my.service"), - users = listOf(user("jenny")) - ) - assertEquals(prettyPrint("{" - + "\"detectPublicIp\":false," - + "\"extraAdvertisedServiceIds\":[\"my.service\"]," - + "\"h2port\":30001," - + "\"myLegalName\":\"C=US,L=New York,O=My Name\"," - + "\"p2pAddress\":\"localhost:10001\"," - + "\"rpcAddress\":\"localhost:40002\"," - + "\"rpcUsers\":[" - + "{\"password\":\"letmein\",\"permissions\":[\"ALL\"],\"username\":\"jenny\"}" - + "]," - + "\"useTestClock\":true," - + "\"webAddress\":\"localhost:20001\"" - + "}"), prettyPrint(config.toText())) - } - - @Test - fun `test config text with network map`() { - val config = createConfig( - legalName = myLegalName, - p2pPort = 10001, - rpcPort = 40002, - webPort = 20001, - h2Port = 30001, - services = mutableListOf("my.service"), - users = listOf(user("jenny")) - ) - config.networkMap = NetworkMapConfig(DUMMY_NOTARY.name, 12345) - - assertEquals(prettyPrint("{" - + "\"detectPublicIp\":false," - + "\"extraAdvertisedServiceIds\":[\"my.service\"]," - + "\"h2port\":30001," - + "\"myLegalName\":\"C=US,L=New York,O=My Name\"," - + "\"networkMapService\":{\"address\":\"localhost:12345\",\"legalName\":\"C=CH,L=Zurich,O=Notary Service\"}," - + "\"p2pAddress\":\"localhost:10001\"," - + "\"rpcAddress\":\"localhost:40002\"," - + "\"rpcUsers\":[" - + "{\"password\":\"letmein\",\"permissions\":[\"ALL\"],\"username\":\"jenny\"}" - + "]," - + "\"useTestClock\":true," - + "\"webAddress\":\"localhost:20001\"" - + "}"), prettyPrint(config.toText())) - } - @Test fun `reading node configuration`() { val config = createConfig( @@ -192,13 +32,13 @@ class NodeConfigTest { p2pPort = 10001, rpcPort = 40002, webPort = 20001, - h2Port = 30001, - services = mutableListOf("my.service"), + h2port = 30001, + notary = NotaryService(validating = false), + networkMap = NetworkMapConfig(DUMMY_NOTARY.name, localPort(12345)), users = listOf(user("jenny")) ) - config.networkMap = NetworkMapConfig(DUMMY_NOTARY.name, 12345) - val nodeConfig = config.toFileConfig() + val nodeConfig = config.toConfig() .withValue("baseDirectory", ConfigValueFactory.fromAnyRef(baseDir.toString())) .withFallback(ConfigFactory.parseResources("reference.conf")) .resolve() @@ -207,10 +47,9 @@ class NodeConfigTest { assertEquals(myLegalName, fullConfig.myLegalName) assertEquals(localPort(40002), fullConfig.rpcAddress) assertEquals(localPort(10001), fullConfig.p2pAddress) - assertEquals(listOf("my.service"), fullConfig.extraAdvertisedServiceIds) assertEquals(listOf(user("jenny")), fullConfig.rpcUsers) assertEquals(NetworkMapInfo(localPort(12345), DUMMY_NOTARY.name), fullConfig.networkMapService) - assertTrue((fullConfig.dataSourceProperties["dataSource.url"] as String).contains("AUTO_SERVER_PORT=30001")) + assertThat(fullConfig.dataSourceProperties["dataSource.url"] as String).contains("AUTO_SERVER_PORT=30001") assertTrue(fullConfig.useTestClock) assertFalse(fullConfig.detectPublicIp) } @@ -222,13 +61,13 @@ class NodeConfigTest { p2pPort = 10001, rpcPort = 40002, webPort = 20001, - h2Port = 30001, - services = mutableListOf("my.service"), + h2port = 30001, + notary = NotaryService(validating = false), + networkMap = NetworkMapConfig(DUMMY_NOTARY.name, localPort(12345)), users = listOf(user("jenny")) ) - config.networkMap = NetworkMapConfig(DUMMY_NOTARY.name, 12345) - val nodeConfig = config.toFileConfig() + val nodeConfig = config.toConfig() .withValue("baseDirectory", ConfigValueFactory.fromAnyRef(baseDir.toString())) .withFallback(ConfigFactory.parseResources("web-reference.conf")) .resolve() @@ -240,35 +79,27 @@ class NodeConfigTest { assertEquals("cordacadevpass", webConfig.keyStorePassword) } - @Test - fun `test moving`() { - val config = createConfig(legalName = myLegalName) - - val elsewhere = baseDir / "elsewhere" - val moved = config.moveTo(elsewhere) - assertEquals(elsewhere / "myname", moved.nodeDir) - assertEquals(elsewhere / "myname-explorer", moved.explorerDir) - assertEquals(elsewhere / "myname" / "plugins", moved.pluginDir) - } - private fun createConfig( legalName: CordaX500Name = CordaX500Name(organisation = "Unknown", locality = "Nowhere", country = "GB"), p2pPort: Int = -1, rpcPort: Int = -1, webPort: Int = -1, - h2Port: Int = -1, - services: MutableList = mutableListOf("extra.service"), + h2port: Int = -1, + notary: NotaryService?, + networkMap: NetworkMapConfig?, users: List = listOf(user("guest")) - ) = NodeConfig( - baseDir, - legalName = legalName, - p2pPort = p2pPort, - rpcPort = rpcPort, - webPort = webPort, - h2Port = h2Port, - extraServices = services, - users = users - ) + ): NodeConfig { + return NodeConfig( + myLegalName = legalName, + p2pAddress = localPort(p2pPort), + rpcAddress = localPort(rpcPort), + webAddress = localPort(webPort), + h2port = h2port, + notary = notary, + networkMapService = networkMap, + rpcUsers = users + ) + } private fun localPort(port: Int) = NetworkHostAndPort("localhost", port) } diff --git a/tools/demobench/src/test/kotlin/net/corda/demobench/model/NodeControllerTest.kt b/tools/demobench/src/test/kotlin/net/corda/demobench/model/NodeControllerTest.kt index f6c73aba2d..bae103a317 100644 --- a/tools/demobench/src/test/kotlin/net/corda/demobench/model/NodeControllerTest.kt +++ b/tools/demobench/src/test/kotlin/net/corda/demobench/model/NodeControllerTest.kt @@ -1,6 +1,7 @@ package net.corda.demobench.model import net.corda.core.identity.CordaX500Name +import net.corda.core.utilities.NetworkHostAndPort import net.corda.nodeapi.User import net.corda.testing.DUMMY_NOTARY import org.junit.Test @@ -51,7 +52,7 @@ class NodeControllerTest { fun `test first validated node becomes network map`() { val data = NodeData() data.legalName.value = node1Name - data.p2pPort.value = 100000 + data.p2pPort.value = 10000 assertFalse(controller.hasNetworkMap()) controller.validate(data) @@ -90,7 +91,7 @@ class NodeControllerTest { @Test fun `test register network map node`() { val config = createConfig(commonName = "Organisation is Network Map") - assertTrue(config.isNetworkMap()) + assertTrue(config.nodeConfig.isNetworkMap) assertFalse(controller.hasNetworkMap()) controller.register(config) @@ -99,9 +100,10 @@ class NodeControllerTest { @Test fun `test register non-network-map node`() { - val config = createConfig(commonName = "Organisation is not Network Map") - config.networkMap = NetworkMapConfig(DUMMY_NOTARY.name, 10000) - assertFalse(config.isNetworkMap()) + val config = createConfig( + commonName = "Organisation is not Network Map", + networkMap = NetworkMapConfig(DUMMY_NOTARY.name, localPort(10000))) + assertFalse(config.nodeConfig.isNetworkMap) assertFalse(controller.hasNetworkMap()) controller.register(config) @@ -146,7 +148,7 @@ class NodeControllerTest { @Test fun `test H2 port is max`() { val portNumber = NodeController.firstPort + 3478 - val config = createConfig(h2Port = portNumber) + val config = createConfig(h2port = portNumber) assertEquals(NodeController.firstPort, controller.nextPort) controller.register(config) assertEquals(portNumber + 1, controller.nextPort) @@ -166,25 +168,30 @@ class NodeControllerTest { private fun createConfig( commonName: String = "Unknown", - p2pPort: Int = -1, - rpcPort: Int = -1, - webPort: Int = -1, - h2Port: Int = -1, - services: MutableList = mutableListOf("extra.service"), + p2pPort: Int = 0, + rpcPort: Int = 0, + webPort: Int = 0, + h2port: Int = 0, + notary: NotaryService? = null, + networkMap: NetworkMapConfig? = null, users: List = listOf(user("guest")) - ) = NodeConfig( - baseDir, - legalName = CordaX500Name( - organisation = commonName, - locality = "New York", - country = "US" - ), - p2pPort = p2pPort, - rpcPort = rpcPort, - webPort = webPort, - h2Port = h2Port, - extraServices = services, - users = users - ) + ): NodeConfigWrapper { + val nodeConfig = NodeConfig( + myLegalName = CordaX500Name( + organisation = commonName, + locality = "New York", + country = "US" + ), + p2pAddress = localPort(p2pPort), + rpcAddress = localPort(rpcPort), + webAddress = localPort(webPort), + h2port = h2port, + notary = notary, + networkMapService = networkMap, + rpcUsers = users + ) + return NodeConfigWrapper(baseDir, nodeConfig) + } + private fun localPort(port: Int) = NetworkHostAndPort("localhost", port) } diff --git a/tools/demobench/src/test/kotlin/net/corda/demobench/model/ServiceControllerTest.kt b/tools/demobench/src/test/kotlin/net/corda/demobench/model/ServiceControllerTest.kt deleted file mode 100644 index f80f13b165..0000000000 --- a/tools/demobench/src/test/kotlin/net/corda/demobench/model/ServiceControllerTest.kt +++ /dev/null @@ -1,44 +0,0 @@ -package net.corda.demobench.model - -import org.junit.Test -import kotlin.test.assertEquals -import kotlin.test.assertNotNull -import kotlin.test.assertTrue - -class ServiceControllerTest { - - @Test - fun `test empty`() { - val controller = ServiceController("/empty-services.conf") - assertNotNull(controller.services) - assertTrue(controller.services.isEmpty()) - - assertNotNull(controller.notaries) - assertTrue(controller.notaries.isEmpty()) - } - - @Test - fun `test duplicates`() { - val controller = ServiceController("/duplicate-services.conf") - assertNotNull(controller.services) - assertEquals(listOf("corda.example"), controller.services.map { it.value }) - } - - @Test - fun `test notaries`() { - val controller = ServiceController("/notary-services.conf") - assertNotNull(controller.notaries) - assertEquals(listOf("corda.notary.simple"), controller.notaries.map { it.value }) - } - - @Test - fun `test services`() { - val controller = ServiceController() - assertNotNull(controller.services) - assertTrue(controller.services.isNotEmpty()) - - assertNotNull(controller.notaries) - assertTrue(controller.notaries.isNotEmpty()) - } - -} \ No newline at end of file diff --git a/tools/demobench/src/test/kotlin/net/corda/demobench/model/UserTest.kt b/tools/demobench/src/test/kotlin/net/corda/demobench/model/UserTest.kt deleted file mode 100644 index 5376c0915e..0000000000 --- a/tools/demobench/src/test/kotlin/net/corda/demobench/model/UserTest.kt +++ /dev/null @@ -1,47 +0,0 @@ -package net.corda.demobench.model - -import net.corda.nodeapi.User -import org.junit.Test -import kotlin.test.assertEquals - -class UserTest { - - @Test - fun createFromEmptyMap() { - val user = toUser(emptyMap()) - assertEquals("none", user.username) - assertEquals("none", user.password) - assertEquals(emptySet(), user.permissions) - } - - @Test - fun createFromMap() { - val map = mapOf( - "username" to "MyName", - "password" to "MyPassword", - "permissions" to listOf("Flow.MyFlow") - ) - val user = toUser(map) - assertEquals("MyName", user.username) - assertEquals("MyPassword", user.password) - assertEquals(setOf("Flow.MyFlow"), user.permissions) - } - - @Test - fun userToMap() { - val user = User("MyName", "MyPassword", setOf("Flow.MyFlow")) - val map = user.toMap() - assertEquals("MyName", map["username"]) - assertEquals("MyPassword", map["password"]) - assertEquals(listOf("Flow.MyFlow"), map["permissions"]) - } - - @Test - fun `default user`() { - val user = user("guest") - assertEquals("guest", user.username) - assertEquals("letmein", user.password) - assertEquals(setOf("ALL"), user.permissions) - } - -} diff --git a/tools/demobench/src/test/resources/duplicate-services.conf b/tools/demobench/src/test/resources/duplicate-services.conf deleted file mode 100644 index f7faf80aed..0000000000 --- a/tools/demobench/src/test/resources/duplicate-services.conf +++ /dev/null @@ -1,3 +0,0 @@ -corda.example : Example -corda.example : Example -corda.example : Example diff --git a/tools/demobench/src/test/resources/empty-services.conf b/tools/demobench/src/test/resources/empty-services.conf deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tools/demobench/src/test/resources/notary-services.conf b/tools/demobench/src/test/resources/notary-services.conf deleted file mode 100644 index 79c6835073..0000000000 --- a/tools/demobench/src/test/resources/notary-services.conf +++ /dev/null @@ -1,2 +0,0 @@ -corda.notary.simple : Notary Simple -corda.example : Example diff --git a/tools/explorer/src/main/kotlin/net/corda/explorer/ExplorerSimulation.kt b/tools/explorer/src/main/kotlin/net/corda/explorer/ExplorerSimulation.kt index 5dbb09753c..d22e628596 100644 --- a/tools/explorer/src/main/kotlin/net/corda/explorer/ExplorerSimulation.kt +++ b/tools/explorer/src/main/kotlin/net/corda/explorer/ExplorerSimulation.kt @@ -22,8 +22,6 @@ 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.nodeapi.User -import net.corda.nodeapi.internal.ServiceInfo -import net.corda.nodeapi.internal.ServiceType import net.corda.testing.ALICE import net.corda.testing.BOB import net.corda.testing.DUMMY_NOTARY @@ -71,19 +69,19 @@ class ExplorerSimulation(val options: OptionSet) { // TODO : Supported flow should be exposed somehow from the node instead of set of ServiceInfo. 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")) val bob = startNode(providedName = BOB.name, rpcUsers = arrayListOf(user), - advertisedServices = setOf(ServiceInfo(ServiceType.corda.getSubType("cash"))), customOverrides = mapOf("nearestCity" to "Madrid")) val ukBankName = CordaX500Name(organisation = "UK Bank Plc", locality = "London", country = "GB") val usaBankName = CordaX500Name(organisation = "USA Bank Corp", locality = "New York", country = "US") val issuerGBP = startNode(providedName = ukBankName, rpcUsers = arrayListOf(manager), - advertisedServices = setOf(ServiceInfo(ServiceType.corda.getSubType("issuer.GBP"))), - customOverrides = mapOf("nearestCity" to "London")) + customOverrides = mapOf( + "issuableCurrencies" to listOf("GBP"), + "nearestCity" to "London")) val issuerUSD = startNode(providedName = usaBankName, rpcUsers = arrayListOf(manager), - advertisedServices = setOf(ServiceInfo(ServiceType.corda.getSubType("issuer.USD"))), - customOverrides = mapOf("nearestCity" to "New York")) + customOverrides = mapOf( + "issuableCurrencies" to listOf("USD"), + "nearestCity" to "New York")) notaryNode = notary.get() aliceNode = alice.get() diff --git a/tools/explorer/src/test/kotlin/net/corda/explorer/model/IssuerModelTest.kt b/tools/explorer/src/test/kotlin/net/corda/explorer/model/IssuerModelTest.kt deleted file mode 100644 index a363e8cd3f..0000000000 --- a/tools/explorer/src/test/kotlin/net/corda/explorer/model/IssuerModelTest.kt +++ /dev/null @@ -1,27 +0,0 @@ -package net.corda.explorer.model - -import net.corda.finance.USD -import org.junit.Test -import java.util.* -import kotlin.test.assertEquals -import kotlin.test.assertFailsWith -import kotlin.test.assertFalse -import kotlin.test.assertTrue - -class IssuerModelTest { - @Test - fun `test issuer regex`() { - val regex = Regex("corda.issuer.(USD|GBP|CHF)") - assertTrue("corda.issuer.USD".matches(regex)) - assertTrue("corda.issuer.GBP".matches(regex)) - - assertFalse("corda.issuer.USD.GBP".matches(regex)) - assertFalse("corda.issuer.EUR".matches(regex)) - assertFalse("corda.issuer".matches(regex)) - - assertEquals(USD, Currency.getInstance("corda.issuer.USD".substringAfterLast("."))) - assertFailsWith(IllegalArgumentException::class) { - Currency.getInstance("corda.issuer.DOLLAR".substringBeforeLast(".")) - } - } -} \ No newline at end of file