diff --git a/build.gradle b/build.gradle index 864366babd..3d2f519807 100644 --- a/build.gradle +++ b/build.gradle @@ -120,7 +120,9 @@ buildscript { classpath "net.corda.plugins:quasar-utils:$gradle_plugins_version" classpath "net.corda.plugins:cordformation:$gradle_plugins_version" classpath "net.corda.plugins:cordapp:$gradle_plugins_version" - classpath "net.corda.plugins:api-scanner:$gradle_plugins_version" + //TODO Anthony- this should be changed back to $gradle_plugins_version when the api-scaner is fixed +// classpath "net.corda.plugins:api-scanner:$gradle_plugins_version" + classpath "net.corda.plugins:api-scanner:4.0.15" classpath 'com.github.ben-manes:gradle-versions-plugin:0.15.0' classpath "org.jetbrains.kotlin:kotlin-noarg:$kotlin_version" classpath "org.jetbrains.dokka:dokka-gradle-plugin:${dokka_version}" diff --git a/constants.properties b/constants.properties index 55d36f37b5..9a24b1d894 100644 --- a/constants.properties +++ b/constants.properties @@ -8,7 +8,7 @@ # Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited. # -gradlePluginsVersion=4.0.15 +gradlePluginsVersion=4.0.19 kotlinVersion=1.2.41 platformVersion=4 guavaVersion=21.0 diff --git a/core/src/main/kotlin/net/corda/core/internal/Emoji.kt b/core/src/main/kotlin/net/corda/core/internal/Emoji.kt index e013395624..c1c377a4d0 100644 --- a/core/src/main/kotlin/net/corda/core/internal/Emoji.kt +++ b/core/src/main/kotlin/net/corda/core/internal/Emoji.kt @@ -55,6 +55,10 @@ object Emoji { val CODE_FREE: String = codePointsString(0x1F193) @JvmStatic val CODE_SOON: String = codePointsString(0x1F51C) + @JvmStatic + val CODE_DEVELOPER: String = codePointsString(0x1F469, 0x200D, 0x1F4BB) + @JvmStatic + val CODE_WARNING_SIGN: String = codePointsString(0x26A0, 0xFE0F) /** @@ -75,6 +79,8 @@ object Emoji { val lightBulb: String get() = if (emojiMode.get() != null) "$CODE_LIGHTBULB " else "" val free: String get() = if (emojiMode.get() != null) "$CODE_FREE " else "" val soon: String get() = if (emojiMode.get() != null) "$CODE_SOON " else "" + val developer: String get() = if (emojiMode.get() != null) "$CODE_DEVELOPER " else "" + val warningSign: String get() = if (emojiMode.get() != null) "$CODE_WARNING_SIGN " else "!" // These have old/non-emoji symbols with better platform support. val greenTick: String get() = if (emojiMode.get() != null) "$CODE_GREEN_TICK " else "✓" diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index dbc43d100a..52fff25e44 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -10,6 +10,12 @@ Unreleased * Node will now gracefully fail to start if ``devMode`` is true and ``compatibilityZoneURL`` is specified. +* Added smart detection logic for the development mode setting and an option to override it from the command line. + +* Fixed an error thrown by NodeVaultService upon recording a transaction with a number of inputs greater than the default page size. + +* Fixed incorrect computation of ``totalStates`` from ``otherResults`` in ``NodeVaultService``. + * Changes to the JSON/YAML serialisation format from ``JacksonSupport``, which also applies to the node shell: * ``Instant`` and ``Date`` objects are serialised as ISO-8601 formatted strings rather than timestamps diff --git a/docs/source/corda-configuration-file.rst b/docs/source/corda-configuration-file.rst index 92cdd652ae..a9151e6fe1 100644 --- a/docs/source/corda-configuration-file.rst +++ b/docs/source/corda-configuration-file.rst @@ -172,9 +172,12 @@ absolute path to the node's base directory. :devMode: This flag sets the node to run in development mode. On startup, if the keystore ``/certificates/sslkeystore.jks`` does not exist, a developer keystore will be used if ``devMode`` is true. The node will exit if ``devMode`` is false and the keystore does not exist. ``devMode`` also turns on background checking of flow checkpoints to shake out any - bugs in the checkpointing process. Also, if ``devMode`` is true, Hibernate will try to automatically create the schema required by Corda - or update an existing schema in the SQL database; if ``devMode`` is false, Hibernate will simply validate an existing schema - failing on node start if this schema is either not present or not compatible. + bugs in the checkpointing process. + Also, if ``devMode`` is true, Hibernate will try to automatically create the schema required by Corda + or update an existing schema in the SQL database; if ``devMode`` is false, Hibernate will simply validate the existing schema, + failing on node start if the schema is either not present or not compatible. + If no value is specified in the node config file, the node will attempt to detect if it's running on a developer machine and set ``devMode=true`` in that case. + This value can be overridden from the command line using the ``--dev-mode`` option. :detectPublicIp: This flag toggles the auto IP detection behaviour, it is enabled by default. On startup the node will attempt to discover its externally visible IP address first by looking for any public addresses on its network diff --git a/node/src/integration-test/kotlin/net/corda/node/utilities/registration/NodeRegistrationTest.kt b/node/src/integration-test/kotlin/net/corda/node/utilities/registration/NodeRegistrationTest.kt index d2254dbe7f..6ff39284a5 100644 --- a/node/src/integration-test/kotlin/net/corda/node/utilities/registration/NodeRegistrationTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/utilities/registration/NodeRegistrationTest.kt @@ -101,11 +101,12 @@ class NodeRegistrationTest : IntegrationTest() { compatibilityZone = compatibilityZone, initialiseSerialization = false, notarySpecs = listOf(NotarySpec(notaryName)), - extraCordappPackagesToScan = listOf("net.corda.finance") + extraCordappPackagesToScan = listOf("net.corda.finance"), + notaryCustomOverrides = mapOf("devMode" to false) ) { val (alice, genevieve) = listOf( - startNode(providedName = aliceName), - startNode(providedName = genevieveName) + startNode(providedName = aliceName, customOverrides = mapOf("devMode" to false)), + startNode(providedName = genevieveName, customOverrides = mapOf("devMode" to false)) ).transpose().getOrThrow() assertThat(registrationHandler.idsPolled).containsOnly( diff --git a/node/src/main/kotlin/net/corda/node/NodeArgsParser.kt b/node/src/main/kotlin/net/corda/node/NodeArgsParser.kt index 038d2d26b4..4e885beea9 100644 --- a/node/src/main/kotlin/net/corda/node/NodeArgsParser.kt +++ b/node/src/main/kotlin/net/corda/node/NodeArgsParser.kt @@ -57,6 +57,7 @@ class NodeArgsParser : AbstractArgsParser() { .withRequiredArg() .withValuesConvertedBy(object : EnumConverter(UnknownConfigKeysPolicy::class.java) {}) .defaultsTo(UnknownConfigKeysPolicy.FAIL) + private val devModeArg = optionParser.accepts("dev-mode", "Run the node in developer mode. Unsafe for production.") private val isVersionArg = optionParser.accepts("version", "Print the version and exit") private val justGenerateNodeInfoArg = optionParser.accepts("just-generate-node-info", @@ -80,6 +81,7 @@ class NodeArgsParser : AbstractArgsParser() { val networkRootTrustStorePath = optionSet.valueOf(networkRootTrustStorePathArg) val networkRootTrustStorePassword = optionSet.valueOf(networkRootTrustStorePasswordArg) val unknownConfigKeysPolicy = optionSet.valueOf(unknownConfigKeysPolicy) + val devMode = optionSet.has(devModeArg) val registrationConfig = if (isRegistration) { requireNotNull(networkRootTrustStorePassword) { "Network root trust store password must be provided in registration mode using --network-root-truststore-password." } @@ -99,7 +101,8 @@ class NodeArgsParser : AbstractArgsParser() { sshdServer, justGenerateNodeInfo, bootstrapRaftCluster, - unknownConfigKeysPolicy) + unknownConfigKeysPolicy, + devMode) } } @@ -115,12 +118,14 @@ data class CmdLineOptions(val baseDirectory: Path, val sshdServer: Boolean, val justGenerateNodeInfo: Boolean, val bootstrapRaftCluster: Boolean, - val unknownConfigKeysPolicy: UnknownConfigKeysPolicy) { + val unknownConfigKeysPolicy: UnknownConfigKeysPolicy, + val devMode: Boolean) { fun loadConfig(): NodeConfiguration { val config = ConfigHelper.loadConfig( baseDirectory, configFile, - configOverrides = ConfigFactory.parseMap(mapOf("noLocalShell" to this.noLocalShell)) + configOverrides = ConfigFactory.parseMap(mapOf("noLocalShell" to this.noLocalShell) + + if (devMode) mapOf("devMode" to this.devMode) else emptyMap()) ).parseAsNodeConfiguration(unknownConfigKeysPolicy::handle) if (nodeRegistrationOption != null) { require(!config.devMode) { "registration cannot occur in devMode" } 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 61015442b6..9228047dcf 100644 --- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt @@ -23,6 +23,7 @@ import net.corda.core.flows.* import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate +import net.corda.core.internal.Emoji import net.corda.core.internal.FlowStateMachine import net.corda.core.internal.VisibleForTesting import net.corda.core.internal.concurrent.map @@ -179,8 +180,10 @@ abstract class AbstractNode(val configuration: NodeConfiguration, private fun initCertificate() { if (configuration.devMode) { - log.warn("Corda node is running in dev mode.") + log.warn("The Corda node is running in developer mode. This is not suitable for production usage.") configuration.configureWithDevSSLCertificate() + } else { + log.info("The Corda node is running in production mode. If this is a developer environment you can set 'devMode=true' in the node.conf file.") } validateKeystore() } @@ -205,6 +208,9 @@ abstract class AbstractNode(val configuration: NodeConfiguration, open fun start(): StartedNode { check(started == null) { "Node has already been started" } + if (configuration.devMode) { + Emoji.renderIfSupported { Node.printWarning("This node is running in developer mode! ${Emoji.developer} This is not safe for production deployment.") } + } log.info("Node starting up ...") initCertificate() initialiseJVMAgents() 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 f0fdf70f6e..1e643b5598 100644 --- a/node/src/main/kotlin/net/corda/node/internal/Node.kt +++ b/node/src/main/kotlin/net/corda/node/internal/Node.kt @@ -13,6 +13,7 @@ package net.corda.node.internal import com.codahale.metrics.JmxReporter import net.corda.client.rpc.internal.serialization.kryo.KryoClientSerializationScheme import net.corda.core.concurrent.CordaFuture +import net.corda.core.internal.Emoji import net.corda.core.internal.concurrent.openFuture import net.corda.core.internal.concurrent.thenMatch import net.corda.core.internal.div @@ -85,6 +86,13 @@ open class Node(configuration: NodeConfiguration, LoggerFactory.getLogger(loggerName).info(msg) } + fun printWarning(message: String) { + Emoji.renderIfSupported { + println("${Emoji.warningSign} ATTENTION: ${message}") + } + staticLog.warn(message) + } + internal fun failStartUp(message: String): Nothing { println(message) println("Corda will now exit...") diff --git a/node/src/main/kotlin/net/corda/node/services/config/ConfigUtilities.kt b/node/src/main/kotlin/net/corda/node/services/config/ConfigUtilities.kt index 97eee02aed..4eb8cfc72e 100644 --- a/node/src/main/kotlin/net/corda/node/services/config/ConfigUtilities.kt +++ b/node/src/main/kotlin/net/corda/node/services/config/ConfigUtilities.kt @@ -46,9 +46,13 @@ object ConfigHelper { val appConfig = ConfigFactory.parseFile(configFile.toFile(), parseOptions.setAllowMissing(allowMissingConfig)) val databaseConfig = ConfigFactory.parseResources(System.getProperty("custom.databaseProvider")+".conf", parseOptions.setAllowMissing(true)) + // Detect the underlying OS. If mac or windows non-server then we assume we're running in devMode. Unless specified otherwise. + val smartDevMode = CordaSystemUtils.isOsMac() || (CordaSystemUtils.isOsWindows() && !CordaSystemUtils.getOsName().toLowerCase().contains("server")) + val devModeConfig = ConfigFactory.parseMap(mapOf("devMode" to smartDevMode)) + val systemOverrides = systemProperties().cordaEntriesOnly() val environmentOverrides = systemEnvironment().cordaEntriesOnly() - val finalConfig = configOverrides + val finalConfig = configOf( // Add substitution values here .withFallback(configOf("custom.nodeOrganizationName" to parseToDbSchemaFriendlyName(baseDirectory.fileName.toString()))) //for database integration tests .withFallback(systemOverrides) //for database integration tests @@ -56,6 +60,7 @@ object ConfigHelper { .withFallback(configOf("baseDirectory" to baseDirectory.toString())) .withFallback(databaseConfig) //for database integration tests .withFallback(appConfig) + .withFallback(devModeConfig) // this needs to be after the appConfig, so it doesn't override the configured devMode .withFallback(defaultConfig) .resolve() @@ -112,3 +117,15 @@ fun SSLConfiguration.configureDevKeyAndTrustStores(myLegalName: CordaX500Name) { /** Parse a value to be database schema name friendly and removes the last part if it matches a port ("_" followed by at least 5 digits) */ fun parseToDbSchemaFriendlyName(value: String) = value.replace(" ", "").replace("-", "_").replace(Regex("_\\d{5,}$"),"") + +/** This is generally covered by commons-lang. */ +object CordaSystemUtils { + const val OS_NAME = "os.name" + + const val MAC_PREFIX = "Mac" + const val WIN_PREFIX = "Windows" + + fun isOsMac() = getOsName().startsWith(MAC_PREFIX) + fun isOsWindows() = getOsName().startsWith(WIN_PREFIX) + fun getOsName() = System.getProperty(OS_NAME) +} \ No newline at end of file diff --git a/node/src/main/resources/reference.conf b/node/src/main/resources/reference.conf index e635f3a1a0..d833a4593b 100644 --- a/node/src/main/resources/reference.conf +++ b/node/src/main/resources/reference.conf @@ -22,7 +22,6 @@ database = { transactionIsolationLevel = "REPEATABLE_READ" exportHibernateJMXStatistics = "false" } -devMode = true h2port = 0 useTestClock = false verifierType = InMemory diff --git a/node/src/test/kotlin/net/corda/node/NodeArgsParserTest.kt b/node/src/test/kotlin/net/corda/node/NodeArgsParserTest.kt index 3e8437ecba..973d3af7cc 100644 --- a/node/src/test/kotlin/net/corda/node/NodeArgsParserTest.kt +++ b/node/src/test/kotlin/net/corda/node/NodeArgsParserTest.kt @@ -53,7 +53,8 @@ class NodeArgsParserTest { sshdServer = false, justGenerateNodeInfo = false, bootstrapRaftCluster = false, - unknownConfigKeysPolicy = UnknownConfigKeysPolicy.FAIL)) + unknownConfigKeysPolicy = UnknownConfigKeysPolicy.FAIL, + devMode = false)) } @Test diff --git a/node/src/test/kotlin/net/corda/node/services/config/NodeConfigurationImplTest.kt b/node/src/test/kotlin/net/corda/node/services/config/NodeConfigurationImplTest.kt index 6993ada31f..115f91f74c 100644 --- a/node/src/test/kotlin/net/corda/node/services/config/NodeConfigurationImplTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/config/NodeConfigurationImplTest.kt @@ -11,7 +11,10 @@ package net.corda.node.services.config import com.zaxxer.hikari.HikariConfig +import com.typesafe.config.Config +import com.typesafe.config.ConfigFactory import net.corda.core.internal.div +import net.corda.core.internal.toPath import net.corda.core.utilities.NetworkHostAndPort import net.corda.nodeapi.internal.persistence.CordaPersistence.DataSourceConfigTag import net.corda.core.utilities.seconds @@ -86,6 +89,59 @@ class NodeConfigurationImplTest { assertFalse { testConfiguration.copy(noLocalShell = true, sshd = null).shouldInitCrashShell() } } + @Test + fun `Dev mode is autodetected correctly`() { + val os = System.getProperty("os.name") + + setSystemOs("Windows 98") + assertTrue(getConfig("test-config-empty.conf").getBoolean("devMode")) + + setSystemOs("Mac Sierra") + assertTrue(getConfig("test-config-empty.conf").getBoolean("devMode")) + + setSystemOs("Windows server 2008") + assertFalse(getConfig("test-config-empty.conf").getBoolean("devMode")) + + setSystemOs("Linux") + assertFalse(getConfig("test-config-empty.conf").getBoolean("devMode")) + + setSystemOs(os) + } + + private fun setSystemOs(os: String) { + System.setProperty("os.name", os) + } + + @Test + fun `Dev mode is read from the config over the autodetect logic`() { + assertTrue(getConfig("test-config-DevMode.conf").getBoolean("devMode")) + assertFalse(getConfig("test-config-noDevMode.conf").getBoolean("devMode")) + } + + @Test + fun `Dev mode is true if overriden`() { + assertTrue(getConfig("test-config-DevMode.conf", ConfigFactory.parseMap(mapOf("devMode" to true))).getBoolean("devMode")) + assertTrue(getConfig("test-config-noDevMode.conf", ConfigFactory.parseMap(mapOf("devMode" to true))).getBoolean("devMode")) + assertTrue(getConfig("test-config-empty.conf", ConfigFactory.parseMap(mapOf("devMode" to true))).getBoolean("devMode")) + } + + @Test + fun `Dev mode is false if overriden`() { + assertFalse(getConfig("test-config-DevMode.conf", ConfigFactory.parseMap(mapOf("devMode" to false))).getBoolean("devMode")) + assertFalse(getConfig("test-config-noDevMode.conf", ConfigFactory.parseMap(mapOf("devMode" to false))).getBoolean("devMode")) + assertFalse(getConfig("test-config-empty.conf", ConfigFactory.parseMap(mapOf("devMode" to false))).getBoolean("devMode")) + } + + private fun getConfig(cfgName: String, overrides: Config = ConfigFactory.empty()): Config { + val path = this::class.java.classLoader.getResource(cfgName).toPath() + val cfg = ConfigHelper.loadConfig( + baseDirectory = path.parent, + configFile = path, + configOverrides = overrides + ) + return cfg + } + @Test fun `validation has error when compatibilityZoneURL is present and devMode is true`() { val configuration = testConfiguration.copy(devMode = true, compatibilityZoneURL = URI.create("https://r3.com").toURL()) diff --git a/node/src/test/resources/test-config-DevMode.conf b/node/src/test/resources/test-config-DevMode.conf new file mode 100644 index 0000000000..f0c599c1d8 --- /dev/null +++ b/node/src/test/resources/test-config-DevMode.conf @@ -0,0 +1 @@ +devMode=true \ No newline at end of file diff --git a/node/src/test/resources/test-config-empty.conf b/node/src/test/resources/test-config-empty.conf new file mode 100644 index 0000000000..e69de29bb2 diff --git a/node/src/test/resources/test-config-noDevMode.conf b/node/src/test/resources/test-config-noDevMode.conf new file mode 100644 index 0000000000..ddf59af5b0 --- /dev/null +++ b/node/src/test/resources/test-config-noDevMode.conf @@ -0,0 +1 @@ +devMode=false \ No newline at end of file diff --git a/samples/bank-of-corda-demo/src/main/kotlin/net/corda/bank/BankOfCordaCordform.kt b/samples/bank-of-corda-demo/src/main/kotlin/net/corda/bank/BankOfCordaCordform.kt index 1abca9dabc..67aaed8c79 100644 --- a/samples/bank-of-corda-demo/src/main/kotlin/net/corda/bank/BankOfCordaCordform.kt +++ b/samples/bank-of-corda-demo/src/main/kotlin/net/corda/bank/BankOfCordaCordform.kt @@ -46,6 +46,7 @@ class BankOfCordaCordform : CordformDefinition() { address("localhost:10003") adminAddress("localhost:10004") } + devMode(true) } node { name(BOC_NAME) @@ -57,6 +58,7 @@ class BankOfCordaCordform : CordformDefinition() { } webPort(BOC_WEB_PORT) rpcUsers(User("bankUser", "test", setOf(all()))) + devMode(true) } node { name(BIGCORP_NAME) @@ -67,6 +69,7 @@ class BankOfCordaCordform : CordformDefinition() { } webPort(10010) rpcUsers(User("bigCorpUser", "test", setOf(all()))) + devMode(true) } } diff --git a/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/BFTNotaryCordform.kt b/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/BFTNotaryCordform.kt index 5effba72b1..2902afdf1f 100644 --- a/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/BFTNotaryCordform.kt +++ b/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/BFTNotaryCordform.kt @@ -44,6 +44,7 @@ class BFTNotaryCordform : CordformDefinition() { adminAddress("localhost:10103") } rpcUsers(notaryDemoUser) + devMode(true) } node { name(BOB_NAME) @@ -52,6 +53,7 @@ class BFTNotaryCordform : CordformDefinition() { address("localhost:10006") adminAddress("localhost:10106") } + devMode(true) } val clusterAddresses = (0 until clusterSize).map { NetworkHostAndPort("localhost", 11000 + it * 10) } fun notaryNode(replicaId: Int, configure: CordformNode.() -> Unit) = node { @@ -65,6 +67,7 @@ class BFTNotaryCordform : CordformDefinition() { address("localhost:10010") adminAddress("localhost:10110") } + devMode(true) } notaryNode(1) { p2pPort(10013) @@ -72,6 +75,7 @@ class BFTNotaryCordform : CordformDefinition() { address("localhost:10014") adminAddress("localhost:10114") } + devMode(true) } notaryNode(2) { p2pPort(10017) @@ -79,6 +83,7 @@ class BFTNotaryCordform : CordformDefinition() { address("localhost:10018") adminAddress("localhost:10118") } + devMode(true) } notaryNode(3) { p2pPort(10021) @@ -86,6 +91,7 @@ class BFTNotaryCordform : CordformDefinition() { address("localhost:10022") adminAddress("localhost:10122") } + devMode(true) } } diff --git a/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/CustomNotaryCordform.kt b/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/CustomNotaryCordform.kt index e096211324..ce27373833 100644 --- a/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/CustomNotaryCordform.kt +++ b/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/CustomNotaryCordform.kt @@ -32,6 +32,7 @@ class CustomNotaryCordform : CordformDefinition() { adminAddress("localhost:10103") } rpcUsers(notaryDemoUser) + devMode(true) } node { name(BOB_NAME) @@ -40,6 +41,7 @@ class CustomNotaryCordform : CordformDefinition() { address("localhost:10006") adminAddress("localhost:10106") } + devMode(true) } node { name(DUMMY_NOTARY_NAME) @@ -49,6 +51,7 @@ class CustomNotaryCordform : CordformDefinition() { adminAddress("localhost:10110") } notary(NotaryConfig(validating = true, custom = true)) + devMode(true) } } diff --git a/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/RaftNotaryCordform.kt b/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/RaftNotaryCordform.kt index 1c1f7fdf6c..8e4b2fc8b0 100644 --- a/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/RaftNotaryCordform.kt +++ b/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/RaftNotaryCordform.kt @@ -44,6 +44,7 @@ class RaftNotaryCordform : CordformDefinition() { adminAddress("localhost:10103") } rpcUsers(notaryDemoUser) + devMode(true) } node { name(BOB_NAME) @@ -52,12 +53,14 @@ class RaftNotaryCordform : CordformDefinition() { address("localhost:10006") adminAddress("localhost:10106") } + devMode(true) } fun notaryNode(index: Int, nodePort: Int, clusterPort: Int? = null, configure: CordformNode.() -> Unit) = node { name(notaryNames[index]) val clusterAddresses = if (clusterPort != null ) listOf(NetworkHostAndPort("localhost", clusterPort)) else emptyList() notary(NotaryConfig(validating = true, raft = RaftConfig(NetworkHostAndPort("localhost", nodePort), clusterAddresses))) configure() + devMode(true) } notaryNode(0, 10008) { p2pPort(10009) @@ -65,6 +68,7 @@ class RaftNotaryCordform : CordformDefinition() { address("localhost:10010") adminAddress("localhost:10110") } + devMode(true) } notaryNode(1, 10012, 10008) { p2pPort(10013) @@ -72,6 +76,7 @@ class RaftNotaryCordform : CordformDefinition() { address("localhost:10014") adminAddress("localhost:10114") } + devMode(true) } notaryNode(2, 10016, 10008) { p2pPort(10017) @@ -79,6 +84,7 @@ class RaftNotaryCordform : CordformDefinition() { address("localhost:10018") adminAddress("localhost:10118") } + devMode(true) } } diff --git a/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/SingleNotaryCordform.kt b/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/SingleNotaryCordform.kt index 7d0b7deec5..2f09466812 100644 --- a/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/SingleNotaryCordform.kt +++ b/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/SingleNotaryCordform.kt @@ -38,6 +38,7 @@ class SingleNotaryCordform : CordformDefinition() { adminAddress("localhost:10103") } rpcUsers(notaryDemoUser) + devMode(true) } node { name(BOB_NAME) @@ -46,6 +47,7 @@ class SingleNotaryCordform : CordformDefinition() { address("localhost:10006") adminAddress("localhost:10106") } + devMode(true) } node { name(DUMMY_NOTARY_NAME) @@ -55,6 +57,7 @@ class SingleNotaryCordform : CordformDefinition() { adminAddress("localhost:10110") } notary(NotaryConfig(validating = true)) + devMode(true) } } 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 0e159752cd..eb2901655e 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 @@ -176,7 +176,7 @@ data class NodeParameters( */ data class JmxPolicy(val startJmxHttpServer: Boolean = false, val jmxHttpServerPortAllocation: PortAllocation? = - if (startJmxHttpServer) PortAllocation.Incremental(7005) else null) + if (startJmxHttpServer) PortAllocation.Incremental(7005) else null) /** * [driver] allows one to start up nodes like this: @@ -211,7 +211,8 @@ fun driver(defaultParameters: DriverParameters = DriverParameters(), dsl: Dr extraCordappPackagesToScan = defaultParameters.extraCordappPackagesToScan, jmxPolicy = defaultParameters.jmxPolicy, compatibilityZone = null, - networkParameters = defaultParameters.networkParameters + networkParameters = defaultParameters.networkParameters, + notaryCustomOverrides = defaultParameters.notaryCustomOverrides ), coerce = { it }, dsl = dsl, @@ -243,6 +244,7 @@ fun driver(defaultParameters: DriverParameters = DriverParameters(), dsl: Dr * @property jmxPolicy Used to specify whether to expose JMX metrics via Jolokia HHTP/JSON. * @property networkParameters The network parameters to be used by all the nodes. [NetworkParameters.notaries] must be * empty as notaries are defined by [notarySpecs]. + * @property notaryCustomOverrides Extra settings that need to be passed to the notary. */ @Suppress("unused") data class DriverParameters( @@ -258,8 +260,37 @@ data class DriverParameters( val notarySpecs: List = listOf(NotarySpec(DUMMY_NOTARY_NAME)), val extraCordappPackagesToScan: List = emptyList(), val jmxPolicy: JmxPolicy = JmxPolicy(), - val networkParameters: NetworkParameters = testNetworkParameters(notaries = emptyList()) + val networkParameters: NetworkParameters = testNetworkParameters(notaries = emptyList()), + val notaryCustomOverrides: Map = emptyMap() ) { + constructor( + isDebug: Boolean, + driverDirectory: Path, + portAllocation: PortAllocation, + debugPortAllocation: PortAllocation, + systemProperties: Map, + useTestClock: Boolean, + startNodesInProcess: Boolean, + waitForAllNodesToFinish: Boolean, + notarySpecs: List, + extraCordappPackagesToScan: List, + jmxPolicy: JmxPolicy, + networkParameters: NetworkParameters + ) : this( + isDebug, + driverDirectory, + portAllocation, + debugPortAllocation, + systemProperties, + useTestClock, + startNodesInProcess, + waitForAllNodesToFinish, + notarySpecs, + extraCordappPackagesToScan, + jmxPolicy, + networkParameters, emptyMap() + ) + fun withIsDebug(isDebug: Boolean): DriverParameters = copy(isDebug = isDebug) fun withDriverDirectory(driverDirectory: Path): DriverParameters = copy(driverDirectory = driverDirectory) fun withPortAllocation(portAllocation: PortAllocation): DriverParameters = copy(portAllocation = portAllocation) @@ -273,4 +304,33 @@ data class DriverParameters( fun withExtraCordappPackagesToScan(extraCordappPackagesToScan: List): DriverParameters = copy(extraCordappPackagesToScan = extraCordappPackagesToScan) fun withJmxPolicy(jmxPolicy: JmxPolicy): DriverParameters = copy(jmxPolicy = jmxPolicy) fun withNetworkParameters(networkParameters: NetworkParameters): DriverParameters = copy(networkParameters = networkParameters) + fun withNotaryCustomOverrides(notaryCustomOverrides: Map): DriverParameters = copy(notaryCustomOverrides = notaryCustomOverrides) + + fun copy( + isDebug: Boolean, + driverDirectory: Path, + portAllocation: PortAllocation, + debugPortAllocation: PortAllocation, + systemProperties: Map, + useTestClock: Boolean, + startNodesInProcess: Boolean, + waitForAllNodesToFinish: Boolean, + notarySpecs: List, + extraCordappPackagesToScan: List, + jmxPolicy: JmxPolicy, + networkParameters: NetworkParameters + ) = this.copy( + isDebug, + driverDirectory, + portAllocation, + debugPortAllocation, + systemProperties, + useTestClock, + startNodesInProcess, + waitForAllNodesToFinish, + notarySpecs, + extraCordappPackagesToScan, + jmxPolicy, + networkParameters, emptyMap() + ) } diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/DriverDSLImpl.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/DriverDSLImpl.kt index c10bfe7690..7e48180ac0 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/DriverDSLImpl.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/DriverDSLImpl.kt @@ -100,7 +100,8 @@ class DriverDSLImpl( val jmxPolicy: JmxPolicy, val notarySpecs: List, val compatibilityZone: CompatibilityZoneParams?, - val networkParameters: NetworkParameters + val networkParameters: NetworkParameters, + val notaryCustomOverrides: Map ) : InternalDriverDSL { private var _executorService: ScheduledExecutorService? = null val executorService get() = _executorService!! @@ -224,18 +225,19 @@ class DriverDSLImpl( val webAddress = portAllocation.nextHostAndPort() val users = rpcUsers.map { it.copy(permissions = it.permissions + DRIVER_REQUIRED_PERMISSIONS) } val czUrlConfig = if (compatibilityZone != null) mapOf("compatibilityZoneURL" to compatibilityZone.url.toString()) else emptyMap() + val overrides = configOf( + "myLegalName" to name.toString(), + "p2pAddress" to p2pAddress.toString(), + "rpcSettings.address" to rpcAddress.toString(), + "rpcSettings.adminAddress" to rpcAdminAddress.toString(), + "useTestClock" to useTestClock, + "rpcUsers" to if (users.isEmpty()) defaultRpcUserList else users.map { it.toConfig().root().unwrapped() }, + "verifierType" to verifierType.name + ) + czUrlConfig + customOverrides val config = NodeConfig(ConfigHelper.loadConfig( baseDirectory = baseDirectory(name), allowMissingConfig = true, - configOverrides = configOf( - "myLegalName" to name.toString(), - "p2pAddress" to p2pAddress.toString(), - "rpcSettings.address" to rpcAddress.toString(), - "rpcSettings.adminAddress" to rpcAdminAddress.toString(), - "useTestClock" to useTestClock, - "rpcUsers" to if (users.isEmpty()) defaultRpcUserList else users.map { it.toConfig().root().unwrapped() }, - "verifierType" to verifierType.name - ) + czUrlConfig + customOverrides + configOverrides = if (overrides.hasPath("devMode")) overrides else overrides + mapOf("devMode" to true) )) return startNodeInternal(config, webAddress, startInSameProcess, maximumHeapSize, localNetworkMap) } @@ -432,7 +434,7 @@ class DriverDSLImpl( networkMapAvailability = notaryInfosFuture.map { it.second } _notaries = notaryInfosFuture.map { (notaryInfos, localNetworkMap) -> - val listOfFutureNodeHandles = startNotaries(localNetworkMap) + val listOfFutureNodeHandles = startNotaries(localNetworkMap, notaryCustomOverrides) notaryInfos.zip(listOfFutureNodeHandles) { (identity, validating), nodeHandlesFuture -> NotaryHandle(identity, validating, nodeHandlesFuture) } @@ -508,10 +510,10 @@ class DriverDSLImpl( return (0 until spec.cluster!!.clusterSize).map { spec.name.copy(organisation = "${spec.name.organisation}-$it") } } - private fun startNotaries(localNetworkMap: LocalNetworkMap?): List>> { + private fun startNotaries(localNetworkMap: LocalNetworkMap?, customOverrides: Map): List>> { return notarySpecs.map { when (it.cluster) { - null -> startSingleNotary(it, localNetworkMap) + null -> startSingleNotary(it, localNetworkMap, customOverrides ) is ClusterSpec.Raft, // DummyCluster is used for testing the notary communication path, and it does not matter // which underlying consensus algorithm is used, so we just stick to Raft @@ -525,13 +527,13 @@ class DriverDSLImpl( // generating the configs for the nodes, probably making use of Any.toConfig() private fun NotaryConfig.toConfigMap(): Map = mapOf("notary" to toConfig().root().unwrapped()) - private fun startSingleNotary(spec: NotarySpec, localNetworkMap: LocalNetworkMap?): CordaFuture> { + private fun startSingleNotary(spec: NotarySpec, localNetworkMap: LocalNetworkMap?, customOverrides: Map): CordaFuture> { return startRegisteredNode( spec.name, localNetworkMap, spec.rpcUsers, spec.verifierType, - customOverrides = NotaryConfig(spec.validating).toConfigMap() + customOverrides = NotaryConfig(spec.validating).toConfigMap() + customOverrides ).map { listOf(it) } } @@ -1037,7 +1039,8 @@ fun genericDriver( jmxPolicy = defaultParameters.jmxPolicy, notarySpecs = defaultParameters.notarySpecs, compatibilityZone = null, - networkParameters = defaultParameters.networkParameters + networkParameters = defaultParameters.networkParameters, + notaryCustomOverrides = defaultParameters.notaryCustomOverrides ) ) val shutdownHook = addShutdownHook(driverDsl::shutdown) @@ -1081,6 +1084,7 @@ fun internalDriver( jmxPolicy: JmxPolicy = DriverParameters().jmxPolicy, networkParameters: NetworkParameters = DriverParameters().networkParameters, compatibilityZone: CompatibilityZoneParams? = null, + notaryCustomOverrides: Map = DriverParameters().notaryCustomOverrides, dsl: DriverDSLImpl.() -> A ): A { return genericDriver( @@ -1097,7 +1101,8 @@ fun internalDriver( extraCordappPackagesToScan = extraCordappPackagesToScan, jmxPolicy = jmxPolicy, compatibilityZone = compatibilityZone, - networkParameters = networkParameters + networkParameters = networkParameters, + notaryCustomOverrides = notaryCustomOverrides ), coerce = { it }, dsl = dsl, diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/NodeBasedTest.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/NodeBasedTest.kt index 98ae130b1b..c5b63d484e 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/NodeBasedTest.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/NodeBasedTest.kt @@ -105,6 +105,7 @@ abstract class NodeBasedTest(private val cordappPackages: List = emptyLi "database" to mapOf("runMigration" to "true"), "myLegalName" to legalName.toString(), "p2pAddress" to p2pAddress, + "devMode" to true, "rpcSettings.address" to localPort[1].toString(), "rpcSettings.adminAddress" to localPort[2].toString(), "rpcUsers" to rpcUsers.map { it.toConfig().root().unwrapped() } diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/RPCDriver.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/RPCDriver.kt index cbda711078..194d639145 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/RPCDriver.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/RPCDriver.kt @@ -126,6 +126,7 @@ fun rpcDriver( externalTrace: Trace? = null, jmxPolicy: JmxPolicy = JmxPolicy(), networkParameters: NetworkParameters = testNetworkParameters(notaries = emptyList()), + notaryCustomOverrides: Map = emptyMap(), dsl: RPCDriverDSL.() -> A ): A { return genericDriver( @@ -143,7 +144,8 @@ fun rpcDriver( notarySpecs = notarySpecs, jmxPolicy = jmxPolicy, compatibilityZone = null, - networkParameters = networkParameters + networkParameters = networkParameters, + notaryCustomOverrides = notaryCustomOverrides ), externalTrace ), coerce = { it }, 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 cd2a0ab76c..8e48009d3d 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 @@ -48,6 +48,7 @@ class NodeConfigTest { val nodeConfig = config.nodeConf() .withValue("baseDirectory", ConfigValueFactory.fromAnyRef(baseDir.toString())) .withFallback(ConfigFactory.parseResources("reference.conf")) + .withFallback(ConfigFactory.parseMap(mapOf("devMode" to true))) .resolve() val fullConfig = nodeConfig.parseAsNodeConfiguration()