From 739ffda6c72630a9210edd078f5bd5b9619326b8 Mon Sep 17 00:00:00 2001 From: Chris Rankin Date: Fri, 11 Oct 2019 13:37:15 +0100 Subject: [PATCH] Update node-driver to support testing nodes with DJVM support. --- node/build.gradle | 20 +++---- node/capsule/build.gradle | 3 +- .../src/main/resources/compile-commands.txt | 2 - .../djvm/NonDeterministicContract.kt | 20 +++++++ .../corda/flows/djvm/NonDeterministicFlow.kt | 31 ++++++++++ .../corda/node/DeterministicSourcesRule.kt | 31 ++++++++++ .../DeterministicContractVerifyTest.kt | 50 ++++++++++++++++ .../kotlin/net/corda/node/internal/Node.kt | 28 ++++++++- .../internal/djvm/DeterministicVerifier.kt | 4 +- .../node/services/config/NodeConfiguration.kt | 13 +++- .../config/schema/v1/ConfigSections.kt | 27 ++++----- .../kotlin/net/corda/testing/driver/Driver.kt | 8 ++- .../testing/node/internal/DriverDSLImpl.kt | 59 ++++++++++++++----- .../corda/testing/node/internal/RPCDriver.kt | 6 +- 14 files changed, 245 insertions(+), 57 deletions(-) delete mode 100644 node/capsule/src/main/resources/compile-commands.txt create mode 100644 node/src/integration-test/kotlin/net/corda/contracts/djvm/NonDeterministicContract.kt create mode 100644 node/src/integration-test/kotlin/net/corda/flows/djvm/NonDeterministicFlow.kt create mode 100644 node/src/integration-test/kotlin/net/corda/node/DeterministicSourcesRule.kt create mode 100644 node/src/integration-test/kotlin/net/corda/node/services/DeterministicContractVerifyTest.kt diff --git a/node/build.gradle b/node/build.gradle index 6b9a0cc1ba..677478fdd4 100644 --- a/node/build.gradle +++ b/node/build.gradle @@ -32,7 +32,6 @@ apply plugin: 'com.jfrog.artifactory' description 'Corda node modules' repositories { - mavenLocal() // Extra repository for the deterministic-rt JAR. maven { url "$artifactory_contextUrl/corda-dev" @@ -51,16 +50,6 @@ configurations { cacheChangingModulesFor 0, 'seconds' } deterministic - - // This is for the latest deterministic Corda SNAPSHOT artifacts... - [ compileClasspath, runtimeClasspath ].forEach { cfg -> - cfg.resolutionStrategy { - dependencySubstitution { - substitute module("net.corda:corda-core") with project(':core') - substitute module("net.corda:corda-serialization") with project(':serialization') - } - } - } } sourceSets { @@ -181,7 +170,9 @@ dependencies { // Sandbox for deterministic contract verification compile "net.corda.djvm:corda-djvm:$djvm_version" - compile "net.corda.djvm:corda-djvm-serialization:$djvm_version" + compile("net.corda.djvm:corda-djvm-serialization:$djvm_version") { + exclude group: 'net.corda' + } compile(project(':node:djvm')) { transitive = false } @@ -284,8 +275,11 @@ tasks.withType(JavaCompile) { } tasks.withType(Test) { - if (JavaVersion.current() == JavaVersion.VERSION_11) + if (JavaVersion.current() == JavaVersion.VERSION_11) { jvmArgs '-Djdk.attach.allowAttachSelf=true' + } + systemProperty 'deterministic-rt.path', configurations.jdkRt.asPath + systemProperty 'deterministic-sources.path', configurations.deterministic.asPath } task integrationTest(type: Test) { diff --git a/node/capsule/build.gradle b/node/capsule/build.gradle index 6ed91a74f4..7ebb4b981c 100644 --- a/node/capsule/build.gradle +++ b/node/capsule/build.gradle @@ -108,8 +108,9 @@ task buildCordaJAR(type: FatCapsule, dependsOn: [ // // If you change these flags, please also update Driver.kt jvmArgs = ['-Xmx512m', '-XX:+UseG1GC'] - if (JavaVersion.current() == JavaVersion.VERSION_11) + if (JavaVersion.current() == JavaVersion.VERSION_11) { jvmArgs += ['-Djdk.attach.allowAttachSelf=true'] + } } } diff --git a/node/capsule/src/main/resources/compile-commands.txt b/node/capsule/src/main/resources/compile-commands.txt deleted file mode 100644 index 355bb6110b..0000000000 --- a/node/capsule/src/main/resources/compile-commands.txt +++ /dev/null @@ -1,2 +0,0 @@ -quiet -exclude sandbox/*.* diff --git a/node/src/integration-test/kotlin/net/corda/contracts/djvm/NonDeterministicContract.kt b/node/src/integration-test/kotlin/net/corda/contracts/djvm/NonDeterministicContract.kt new file mode 100644 index 0000000000..e4fc1b90f1 --- /dev/null +++ b/node/src/integration-test/kotlin/net/corda/contracts/djvm/NonDeterministicContract.kt @@ -0,0 +1,20 @@ +package net.corda.contracts.djvm + +import net.corda.core.contracts.Contract +import net.corda.core.contracts.ContractState +import net.corda.core.contracts.TypeOnlyCommandData +import net.corda.core.identity.AbstractParty +import net.corda.core.transactions.LedgerTransaction +import java.time.Instant + +class NonDeterministicContract : Contract { + override fun verify(tx: LedgerTransaction) { + Instant.now().toString() + } + + class State : ContractState { + override val participants: List get() = emptyList() + } + + object Cmd : TypeOnlyCommandData() +} diff --git a/node/src/integration-test/kotlin/net/corda/flows/djvm/NonDeterministicFlow.kt b/node/src/integration-test/kotlin/net/corda/flows/djvm/NonDeterministicFlow.kt new file mode 100644 index 0000000000..8e07dad85b --- /dev/null +++ b/node/src/integration-test/kotlin/net/corda/flows/djvm/NonDeterministicFlow.kt @@ -0,0 +1,31 @@ +package net.corda.flows.djvm + +import co.paralleluniverse.fibers.Suspendable +import net.corda.contracts.djvm.NonDeterministicContract +import net.corda.core.contracts.Command +import net.corda.core.flows.FinalityFlow +import net.corda.core.flows.FlowLogic +import net.corda.core.flows.InitiatingFlow +import net.corda.core.flows.StartableByRPC +import net.corda.core.identity.Party +import net.corda.core.transactions.TransactionBuilder +import net.corda.core.utilities.unwrap + +@InitiatingFlow +@StartableByRPC +class NonDeterministicFlow(private val otherSide: Party) : FlowLogic() { + @Suspendable + override fun call() { + val notary = serviceHub.networkMapCache.notaryIdentities[0] + val stx = serviceHub.signInitialTransaction( + TransactionBuilder(notary) + .addOutputState(NonDeterministicContract.State()) + .addCommand(Command(NonDeterministicContract.Cmd, ourIdentity.owningKey)) + ) + stx.verify(serviceHub, checkSufficientSignatures = false) + val session = initiateFlow(otherSide) + subFlow(FinalityFlow(stx, session)) + // It's important we wait on this dummy receive, as otherwise it's possible we miss any errors the other side throws + session.receive().unwrap { require(it == "OK") { "Not OK: $it"} } + } +} diff --git a/node/src/integration-test/kotlin/net/corda/node/DeterministicSourcesRule.kt b/node/src/integration-test/kotlin/net/corda/node/DeterministicSourcesRule.kt new file mode 100644 index 0000000000..4171f40fda --- /dev/null +++ b/node/src/integration-test/kotlin/net/corda/node/DeterministicSourcesRule.kt @@ -0,0 +1,31 @@ +package net.corda.node + +import org.junit.rules.TestRule +import org.junit.runner.Description +import org.junit.runners.model.Statement +import java.io.File +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.Paths +import kotlin.test.fail + +class DeterministicSourcesRule : TestRule { + private var deterministicRt: Path? = null + private var deterministicSources: List? = null + + val bootstrap: Path get() = deterministicRt ?: fail("deterministic-rt.path property not set") + val corda: List get() = deterministicSources ?: fail("deterministic-sources.path property not set") + + override fun apply(statement: Statement, description: Description?): Statement { + deterministicRt = System.getProperty("deterministic-rt.path")?.run { Paths.get(this) } + deterministicSources = System.getProperty("deterministic-sources.path")?.split(File.pathSeparator) + ?.map { Paths.get(it) } + ?.filter { Files.exists(it) } + + return object : Statement() { + override fun evaluate() { + statement.evaluate() + } + } + } +} \ No newline at end of file diff --git a/node/src/integration-test/kotlin/net/corda/node/services/DeterministicContractVerifyTest.kt b/node/src/integration-test/kotlin/net/corda/node/services/DeterministicContractVerifyTest.kt new file mode 100644 index 0000000000..9a9075b993 --- /dev/null +++ b/node/src/integration-test/kotlin/net/corda/node/services/DeterministicContractVerifyTest.kt @@ -0,0 +1,50 @@ +package net.corda.node.services + +import net.corda.core.messaging.startFlow +import net.corda.core.utilities.getOrThrow +import net.corda.flows.djvm.NonDeterministicFlow +import net.corda.node.DeterministicSourcesRule +import net.corda.node.internal.djvm.DeterministicVerificationException +import net.corda.testing.core.ALICE_NAME +import net.corda.testing.core.DUMMY_NOTARY_NAME +import net.corda.testing.core.singleIdentity +import net.corda.testing.driver.DriverParameters +import net.corda.testing.driver.driver +import net.corda.testing.driver.internal.incrementalPortAllocation +import net.corda.testing.node.NotarySpec +import net.corda.testing.node.internal.cordappsForPackages +import org.assertj.core.api.AssertionsForInterfaceTypes.assertThat +import org.junit.ClassRule +import org.junit.Test +import org.junit.jupiter.api.assertThrows + +class DeterministicContractVerifyTest { + companion object { + @ClassRule + @JvmField + val djvmSources = DeterministicSourcesRule() + } + + @Test + fun `test DJVM rejects non-deterministic contract`() { + driver(DriverParameters( + portAllocation = incrementalPortAllocation(), + startNodesInProcess = false, + notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, validating = true)), + cordappsForAllNodes = cordappsForPackages( + "net.corda.contracts.djvm", + "net.corda.flows.djvm" + ), + djvmBootstrapSource = djvmSources.bootstrap, + djvmCordaSource = djvmSources.corda + )) { + val alice = startNode(providedName = ALICE_NAME).getOrThrow() + val ex = assertThrows { + alice.rpc.startFlow(::NonDeterministicFlow, alice.nodeInfo.singleIdentity()).returnValue.getOrThrow() + } + assertThat(ex) + .hasMessageStartingWith("NoSuchMethodError: ") + .hasMessageContaining(" sandbox.java.time.Instant.now()") + } + } +} 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 622674ec72..519c7fa217 100644 --- a/node/src/main/kotlin/net/corda/node/internal/Node.kt +++ b/node/src/main/kotlin/net/corda/node/internal/Node.kt @@ -104,7 +104,7 @@ open class Node(configuration: NodeConfiguration, flowManager: FlowManager = NodeFlowManager(configuration.flowOverrides), cacheFactoryPrototype: BindableNamedCacheFactory = DefaultNamedCacheFactory(), djvmBootstrapSource: ApiSource = createBootstrapSource(configuration), - djvmCordaSource: UserSource? = createDeterministicClasspath(configuration) + djvmCordaSource: UserSource? = createCordaSource(configuration) ) : AbstractNode( configuration, createClock(configuration), @@ -185,7 +185,7 @@ open class Node(configuration: NodeConfiguration, private fun manifestValue(attrName: String): String? = if (Manifests.exists(attrName)) Manifests.read(attrName) else null - fun createDeterministicClasspath(config: NodeConfiguration): UserSource? { + private fun createManifestCordaSource(config: NodeConfiguration): UserSource? { val classpathSource = config.baseDirectory.resolve("djvm") val djvmClasspath = manifestValue(CORDA_DETERMINISTIC_CLASSPATH_ATTR) @@ -207,7 +207,7 @@ open class Node(configuration: NodeConfiguration, } } - fun createBootstrapSource(config: NodeConfiguration): ApiSource { + private fun createManifestBootstrapSource(config: NodeConfiguration): ApiSource { val deterministicRt = manifestValue(CORDA_DETERMINISTIC_RUNTIME_ATTR) if (deterministicRt == null) { staticLog.warn("{} missing from MANIFEST.MF - will use host JVM for deterministic runtime.", @@ -224,6 +224,28 @@ open class Node(configuration: NodeConfiguration, EmptyApi } } + + private fun createBootstrapSource(config: NodeConfiguration): ApiSource { + val djvm = config.devModeOptions?.djvm + return if (config.devMode && djvm != null) { + djvm.bootstrapSource?.let { BootstrapClassLoader(Paths.get(it)) } ?: EmptyApi + } else { + createManifestBootstrapSource(config) + } + } + + private fun createCordaSource(config: NodeConfiguration): UserSource? { + val djvm = config.devModeOptions?.djvm + return if (config.devMode && djvm != null) { + if (djvm.cordaSource.isEmpty()) { + null + } else { + UserPathSource(djvm.cordaSource.map { Paths.get(it) }) + } + } else { + createManifestCordaSource(config) + } + } } override val log: Logger get() = staticLog diff --git a/node/src/main/kotlin/net/corda/node/internal/djvm/DeterministicVerifier.kt b/node/src/main/kotlin/net/corda/node/internal/djvm/DeterministicVerifier.kt index 4a158340ba..0bf04ab929 100644 --- a/node/src/main/kotlin/net/corda/node/internal/djvm/DeterministicVerifier.kt +++ b/node/src/main/kotlin/net/corda/node/internal/djvm/DeterministicVerifier.kt @@ -95,5 +95,5 @@ class DeterministicVerifier( } } -class DeterministicVerificationException(id: SecureHash, message: String, cause: Throwable) - : TransactionVerificationException(id, message, cause) +class DeterministicVerificationException(txId: SecureHash, message: String, cause: Throwable) + : TransactionVerificationException(txId, message, cause) 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 c6c7ebe54d..f9de2f1391 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 @@ -116,15 +116,22 @@ enum class JmxReporterType { JOLOKIA, NEW_RELIC } -data class DevModeOptions(val disableCheckpointChecker: Boolean = Defaults.disableCheckpointChecker, val allowCompatibilityZone: Boolean = Defaults.disableCheckpointChecker) { - +data class DevModeOptions( + val disableCheckpointChecker: Boolean = Defaults.disableCheckpointChecker, + val allowCompatibilityZone: Boolean = Defaults.allowCompatibilityZone, + val djvm: DJVMOptions? = null +) { internal object Defaults { - val disableCheckpointChecker = false val allowCompatibilityZone = false } } +data class DJVMOptions( + val bootstrapSource: String?, + val cordaSource: List +) + fun NodeConfiguration.shouldCheckCheckpoints(): Boolean { return this.devMode && this.devModeOptions?.disableCheckpointChecker != true } diff --git a/node/src/main/kotlin/net/corda/node/services/config/schema/v1/ConfigSections.kt b/node/src/main/kotlin/net/corda/node/services/config/schema/v1/ConfigSections.kt index 81fc40ff66..42e95a49f1 100644 --- a/node/src/main/kotlin/net/corda/node/services/config/schema/v1/ConfigSections.kt +++ b/node/src/main/kotlin/net/corda/node/services/config/schema/v1/ConfigSections.kt @@ -14,20 +14,7 @@ import net.corda.common.validation.internal.Validated.Companion.invalid import net.corda.common.validation.internal.Validated.Companion.valid import net.corda.core.context.AuthServiceId import net.corda.core.internal.notary.NotaryServiceFlow -import net.corda.node.services.config.AuthDataSourceType -import net.corda.node.services.config.CertChainPolicyConfig -import net.corda.node.services.config.CertChainPolicyType -import net.corda.node.services.config.DevModeOptions -import net.corda.node.services.config.FlowOverride -import net.corda.node.services.config.FlowOverrideConfig -import net.corda.node.services.config.FlowTimeoutConfiguration -import net.corda.node.services.config.NetworkParameterAcceptanceSettings -import net.corda.node.services.config.NetworkServicesConfig -import net.corda.node.services.config.NodeH2Settings -import net.corda.node.services.config.NodeRpcSettings -import net.corda.node.services.config.NotaryConfig -import net.corda.node.services.config.PasswordEncryption -import net.corda.node.services.config.SecurityConfiguration +import net.corda.node.services.config.* import net.corda.node.services.config.SecurityConfiguration.AuthService.Companion.defaultAuthServiceId import net.corda.node.services.config.Valid import net.corda.node.services.config.schema.parsers.attempt @@ -127,9 +114,19 @@ internal object SecurityConfigurationSpec : Configuration.Specification("DevModeOptions") { private val disableCheckpointChecker by boolean().optional().withDefaultValue(DevModeOptions.Defaults.disableCheckpointChecker) private val allowCompatibilityZone by boolean().optional().withDefaultValue(DevModeOptions.Defaults.allowCompatibilityZone) + private val djvm by nested(DJVMOptionsSpec).optional() + + private object DJVMOptionsSpec : Configuration.Specification("DJVMOptions") { + private val bootstrapSource by string().optional() + private val cordaSource by string().list() + + override fun parseValid(configuration: Config): Valid { + return valid(DJVMOptions(configuration[bootstrapSource], configuration[cordaSource])) + } + } override fun parseValid(configuration: Config): Valid { - return valid(DevModeOptions(configuration[disableCheckpointChecker], configuration[allowCompatibilityZone])) + return valid(DevModeOptions(configuration[disableCheckpointChecker], configuration[allowCompatibilityZone], configuration[djvm])) } } 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 79ba6b4e8d..94c93e780b 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 @@ -200,7 +200,9 @@ fun driver(defaultParameters: DriverParameters = DriverParameters(), dsl: Dr notaryCustomOverrides = defaultParameters.notaryCustomOverrides, inMemoryDB = defaultParameters.inMemoryDB, cordappsForAllNodes = uncheckedCast(defaultParameters.cordappsForAllNodes), - environmentVariables = defaultParameters.environmentVariables + environmentVariables = defaultParameters.environmentVariables, + djvmBootstrapSource = defaultParameters.djvmBootstrapSource, + djvmCordaSource = defaultParameters.djvmCordaSource ), coerce = { it }, dsl = dsl @@ -257,7 +259,9 @@ data class DriverParameters( val notaryCustomOverrides: Map = emptyMap(), val inMemoryDB: Boolean = true, val cordappsForAllNodes: Collection? = null, - val environmentVariables : Map = emptyMap() + val environmentVariables : Map = emptyMap(), + val djvmBootstrapSource: Path? = null, + val djvmCordaSource: List = emptyList() ) { constructor(cordappsForAllNodes: Collection) : this(isDebug = false, cordappsForAllNodes = cordappsForAllNodes) 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 c34d07b2c4..b9fa4949f0 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 @@ -2,10 +2,7 @@ package net.corda.testing.node.internal import co.paralleluniverse.fibers.instrument.JavaAgent import com.google.common.util.concurrent.ThreadFactoryBuilder -import com.typesafe.config.Config -import com.typesafe.config.ConfigFactory -import com.typesafe.config.ConfigRenderOptions -import com.typesafe.config.ConfigValueFactory +import com.typesafe.config.* import net.corda.client.rpc.CordaRPCClient import net.corda.cliutils.CommonCliConstants.BASE_DIR import net.corda.core.concurrent.CordaFuture @@ -92,7 +89,9 @@ class DriverDSLImpl( val notaryCustomOverrides: Map, val inMemoryDB: Boolean, val cordappsForAllNodes: Collection?, - val environmentVariables : Map + val environmentVariables : Map, + val djvmBootstrapSource: Path?, + val djvmCordaSource: List ) : InternalDriverDSL { private var _executorService: ScheduledExecutorService? = null @@ -129,7 +128,7 @@ class DriverDSLImpl( if (inMemoryDB && corda.dataSourceProperties.getProperty("dataSource.url").startsWith("jdbc:h2:")) { val jdbcUrl = "jdbc:h2:mem:persistence${inMemoryCounter.getAndIncrement()};DB_CLOSE_ON_EXIT=FALSE;LOCK_TIMEOUT=10000;WRITE_DELAY=100" corda.dataSourceProperties.setProperty("dataSource.url", jdbcUrl) - NodeConfig(typesafe = typesafe + mapOf("dataSourceProperties" to mapOf("dataSource.url" to jdbcUrl))) + NodeConfig(typesafe + mapOf("dataSourceProperties" to mapOf("dataSource.url" to jdbcUrl))) } else { this } @@ -236,11 +235,13 @@ class DriverDSLImpl( NodeConfiguration::flowOverrides.name to flowOverrideConfig.toConfig().root().unwrapped(), NodeConfiguration::additionalNodeInfoPollingFrequencyMsec.name to 1000 ) + czUrlConfig + jmxConfig + parameters.customOverrides - val config = NodeConfig(ConfigHelper.loadConfig( + val config = NodeConfig( + ConfigHelper.loadConfig( baseDirectory = baseDirectory(name), allowMissingConfig = true, configOverrides = if (overrides.hasPath("devMode")) overrides else overrides + mapOf("devMode" to true) - )).checkAndOverrideForInMemoryDB() + ).withDJVMConfig(djvmBootstrapSource, djvmCordaSource) + ).checkAndOverrideForInMemoryDB() return startNodeInternal(config, webAddress, localNetworkMap, parameters) } @@ -261,11 +262,13 @@ class DriverDSLImpl( ), "additionalNodeInfoPollingFrequencyMsec" to 1000, "devMode" to false) + customOverrides - val config = NodeConfig(ConfigHelper.loadConfig( + val config = NodeConfig( + ConfigHelper.loadConfig( baseDirectory = baseDirectory, allowMissingConfig = true, configOverrides = overrides - )).checkAndOverrideForInMemoryDB() + ).withDJVMConfig(djvmBootstrapSource, djvmCordaSource) + ).checkAndOverrideForInMemoryDB() val versionInfo = VersionInfo(PLATFORM_VERSION, "1", "1", "1") config.corda.certificatesDirectory.createDirectories() @@ -711,6 +714,25 @@ class DriverDSLImpl( Permissions.invokeRpc(CordaRPCOps::killFlow) ) + /** + * Add the DJVM's sources to the node's configuration file. + * These will all be ignored unless devMode is also true. + */ + private fun Config.withDJVMConfig(bootstrapSource: Path?, cordaSource: List): Config { + return withOptionalValue("devModeOptions.djvm.bootstrapSource", bootstrapSource) { path -> valueFor(path.toString()) } + .withValue("devModeOptions.djvm.cordaSource", valueFor(cordaSource.map(Path::toString))) + } + + private inline fun Config.withOptionalValue(key: String, obj: T?, body: (T) -> ConfigValue): Config { + return if (obj == null) { + this + } else { + withValue(key, body(obj)) + } + } + + private fun valueFor(any: T): ConfigValue = ConfigValueFactory.fromAnyRef(any) + private fun oneOf(array: Array) = array[Random().nextInt(array.size)] private fun startInProcessNode( @@ -767,16 +789,17 @@ class DriverDSLImpl( systemProperties += overriddenSystemProperties // See experimental/quasar-hook/README.md for how to generate. - val excludePattern = "x(antlr**;bftsmart**;ch**;co.paralleluniverse**;com.codahale**;com.esotericsoftware**;" + + val excludePackagePattern = "x(antlr**;bftsmart**;ch**;co.paralleluniverse**;com.codahale**;com.esotericsoftware**;" + "com.fasterxml**;com.google**;com.ibm**;com.intellij**;com.jcabi**;com.nhaarman**;com.opengamma**;" + "com.typesafe**;com.zaxxer**;de.javakaffee**;groovy**;groovyjarjarantlr**;groovyjarjarasm**;io.atomix**;" + - "io.github**;io.netty**;jdk**;joptsimple**;junit**;kotlin**;net.bytebuddy**;net.i2p**;org.apache**;" + + "io.github**;io.netty**;jdk**;joptsimple**;junit**;kotlin**;net.corda.djvm**;djvm.**;net.bytebuddy**;net.i2p**;org.apache**;" + "org.assertj**;org.bouncycastle**;org.codehaus**;org.crsh**;org.dom4j**;org.fusesource**;org.h2**;" + "org.hamcrest**;org.hibernate**;org.jboss**;org.jcp**;org.joda**;org.junit**;org.mockito**;org.objectweb**;" + "org.objenesis**;org.slf4j**;org.w3c**;org.xml**;org.yaml**;reflectasm**;rx**;org.jolokia**;" + "com.lmax**;picocli**;liquibase**;com.github.benmanes**;org.json**;org.postgresql**;nonapi.io.github.classgraph**;)" + val excludeClassloaderPattern = "l(net.corda.djvm.**)" val extraJvmArguments = systemProperties.removeResolvedClasspath().map { "-D${it.key}=${it.value}" } + - "-javaagent:$quasarJarPath=$excludePattern" + "-javaagent:$quasarJarPath=$excludePackagePattern$excludeClassloaderPattern" val loggingLevel = when { logLevelOverride != null -> logLevelOverride @@ -1030,7 +1053,9 @@ fun genericDriver( notaryCustomOverrides = defaultParameters.notaryCustomOverrides, inMemoryDB = defaultParameters.inMemoryDB, cordappsForAllNodes = uncheckedCast(defaultParameters.cordappsForAllNodes), - environmentVariables = defaultParameters.environmentVariables + environmentVariables = defaultParameters.environmentVariables, + djvmBootstrapSource = defaultParameters.djvmBootstrapSource, + djvmCordaSource = defaultParameters.djvmCordaSource ) ) val shutdownHook = addShutdownHook(driverDsl::shutdown) @@ -1126,6 +1151,8 @@ fun internalDriver( inMemoryDB: Boolean = DriverParameters().inMemoryDB, cordappsForAllNodes: Collection? = null, environmentVariables: Map = emptyMap(), + djvmBootstrapSource: Path? = null, + djvmCordaSource: List = emptyList(), dsl: DriverDSLImpl.() -> A ): A { return genericDriver( @@ -1146,7 +1173,9 @@ fun internalDriver( notaryCustomOverrides = notaryCustomOverrides, inMemoryDB = inMemoryDB, cordappsForAllNodes = cordappsForAllNodes, - environmentVariables = environmentVariables + environmentVariables = environmentVariables, + djvmBootstrapSource = djvmBootstrapSource, + djvmCordaSource = djvmCordaSource ), coerce = { it }, dsl = dsl 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 b8d0bda519..33bf184afb 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 @@ -123,6 +123,8 @@ fun rpcDriver( inMemoryDB: Boolean = true, cordappsForAllNodes: Collection? = null, environmentVariables: Map = emptyMap(), + djvmBootstrapSource: Path? = null, + djvmCordaSource: List = emptyList(), dsl: RPCDriverDSL.() -> A ): A { return genericDriver( @@ -144,7 +146,9 @@ fun rpcDriver( notaryCustomOverrides = notaryCustomOverrides, inMemoryDB = inMemoryDB, cordappsForAllNodes = cordappsForAllNodes, - environmentVariables = environmentVariables + environmentVariables = environmentVariables, + djvmBootstrapSource = djvmBootstrapSource, + djvmCordaSource = djvmCordaSource ), externalTrace ), coerce = { it },