mirror of
https://github.com/corda/corda.git
synced 2025-06-10 19:31:46 +00:00
Update node-driver to support testing nodes with DJVM support.
This commit is contained in:
parent
ea6db636fb
commit
739ffda6c7
@ -32,7 +32,6 @@ apply plugin: 'com.jfrog.artifactory'
|
|||||||
description 'Corda node modules'
|
description 'Corda node modules'
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenLocal()
|
|
||||||
// Extra repository for the deterministic-rt JAR.
|
// Extra repository for the deterministic-rt JAR.
|
||||||
maven {
|
maven {
|
||||||
url "$artifactory_contextUrl/corda-dev"
|
url "$artifactory_contextUrl/corda-dev"
|
||||||
@ -51,16 +50,6 @@ configurations {
|
|||||||
cacheChangingModulesFor 0, 'seconds'
|
cacheChangingModulesFor 0, 'seconds'
|
||||||
}
|
}
|
||||||
deterministic
|
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 {
|
sourceSets {
|
||||||
@ -181,7 +170,9 @@ dependencies {
|
|||||||
|
|
||||||
// Sandbox for deterministic contract verification
|
// Sandbox for deterministic contract verification
|
||||||
compile "net.corda.djvm:corda-djvm:$djvm_version"
|
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')) {
|
compile(project(':node:djvm')) {
|
||||||
transitive = false
|
transitive = false
|
||||||
}
|
}
|
||||||
@ -284,8 +275,11 @@ tasks.withType(JavaCompile) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType(Test) {
|
tasks.withType(Test) {
|
||||||
if (JavaVersion.current() == JavaVersion.VERSION_11)
|
if (JavaVersion.current() == JavaVersion.VERSION_11) {
|
||||||
jvmArgs '-Djdk.attach.allowAttachSelf=true'
|
jvmArgs '-Djdk.attach.allowAttachSelf=true'
|
||||||
|
}
|
||||||
|
systemProperty 'deterministic-rt.path', configurations.jdkRt.asPath
|
||||||
|
systemProperty 'deterministic-sources.path', configurations.deterministic.asPath
|
||||||
}
|
}
|
||||||
|
|
||||||
task integrationTest(type: Test) {
|
task integrationTest(type: Test) {
|
||||||
|
@ -108,9 +108,10 @@ task buildCordaJAR(type: FatCapsule, dependsOn: [
|
|||||||
//
|
//
|
||||||
// If you change these flags, please also update Driver.kt
|
// If you change these flags, please also update Driver.kt
|
||||||
jvmArgs = ['-Xmx512m', '-XX:+UseG1GC']
|
jvmArgs = ['-Xmx512m', '-XX:+UseG1GC']
|
||||||
if (JavaVersion.current() == JavaVersion.VERSION_11)
|
if (JavaVersion.current() == JavaVersion.VERSION_11) {
|
||||||
jvmArgs += ['-Djdk.attach.allowAttachSelf=true']
|
jvmArgs += ['-Djdk.attach.allowAttachSelf=true']
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assemble.dependsOn buildCordaJAR
|
assemble.dependsOn buildCordaJAR
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
quiet
|
|
||||||
exclude sandbox/*.*
|
|
@ -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<AbstractParty> get() = emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
object Cmd : TypeOnlyCommandData()
|
||||||
|
}
|
@ -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<Unit>() {
|
||||||
|
@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<String>().unwrap { require(it == "OK") { "Not OK: $it"} }
|
||||||
|
}
|
||||||
|
}
|
@ -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<Path>? = null
|
||||||
|
|
||||||
|
val bootstrap: Path get() = deterministicRt ?: fail("deterministic-rt.path property not set")
|
||||||
|
val corda: List<Path> 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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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<DeterministicVerificationException> {
|
||||||
|
alice.rpc.startFlow(::NonDeterministicFlow, alice.nodeInfo.singleIdentity()).returnValue.getOrThrow()
|
||||||
|
}
|
||||||
|
assertThat(ex)
|
||||||
|
.hasMessageStartingWith("NoSuchMethodError: ")
|
||||||
|
.hasMessageContaining(" sandbox.java.time.Instant.now()")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -104,7 +104,7 @@ open class Node(configuration: NodeConfiguration,
|
|||||||
flowManager: FlowManager = NodeFlowManager(configuration.flowOverrides),
|
flowManager: FlowManager = NodeFlowManager(configuration.flowOverrides),
|
||||||
cacheFactoryPrototype: BindableNamedCacheFactory = DefaultNamedCacheFactory(),
|
cacheFactoryPrototype: BindableNamedCacheFactory = DefaultNamedCacheFactory(),
|
||||||
djvmBootstrapSource: ApiSource = createBootstrapSource(configuration),
|
djvmBootstrapSource: ApiSource = createBootstrapSource(configuration),
|
||||||
djvmCordaSource: UserSource? = createDeterministicClasspath(configuration)
|
djvmCordaSource: UserSource? = createCordaSource(configuration)
|
||||||
) : AbstractNode<NodeInfo>(
|
) : AbstractNode<NodeInfo>(
|
||||||
configuration,
|
configuration,
|
||||||
createClock(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
|
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 classpathSource = config.baseDirectory.resolve("djvm")
|
||||||
val djvmClasspath = manifestValue(CORDA_DETERMINISTIC_CLASSPATH_ATTR)
|
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)
|
val deterministicRt = manifestValue(CORDA_DETERMINISTIC_RUNTIME_ATTR)
|
||||||
if (deterministicRt == null) {
|
if (deterministicRt == null) {
|
||||||
staticLog.warn("{} missing from MANIFEST.MF - will use host JVM for deterministic runtime.",
|
staticLog.warn("{} missing from MANIFEST.MF - will use host JVM for deterministic runtime.",
|
||||||
@ -224,6 +224,28 @@ open class Node(configuration: NodeConfiguration,
|
|||||||
EmptyApi
|
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
|
override val log: Logger get() = staticLog
|
||||||
|
@ -95,5 +95,5 @@ class DeterministicVerifier(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DeterministicVerificationException(id: SecureHash, message: String, cause: Throwable)
|
class DeterministicVerificationException(txId: SecureHash, message: String, cause: Throwable)
|
||||||
: TransactionVerificationException(id, message, cause)
|
: TransactionVerificationException(txId, message, cause)
|
||||||
|
@ -116,15 +116,22 @@ enum class JmxReporterType {
|
|||||||
JOLOKIA, NEW_RELIC
|
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 {
|
internal object Defaults {
|
||||||
|
|
||||||
val disableCheckpointChecker = false
|
val disableCheckpointChecker = false
|
||||||
val allowCompatibilityZone = false
|
val allowCompatibilityZone = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class DJVMOptions(
|
||||||
|
val bootstrapSource: String?,
|
||||||
|
val cordaSource: List<String>
|
||||||
|
)
|
||||||
|
|
||||||
fun NodeConfiguration.shouldCheckCheckpoints(): Boolean {
|
fun NodeConfiguration.shouldCheckCheckpoints(): Boolean {
|
||||||
return this.devMode && this.devModeOptions?.disableCheckpointChecker != true
|
return this.devMode && this.devModeOptions?.disableCheckpointChecker != true
|
||||||
}
|
}
|
||||||
|
@ -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.common.validation.internal.Validated.Companion.valid
|
||||||
import net.corda.core.context.AuthServiceId
|
import net.corda.core.context.AuthServiceId
|
||||||
import net.corda.core.internal.notary.NotaryServiceFlow
|
import net.corda.core.internal.notary.NotaryServiceFlow
|
||||||
import net.corda.node.services.config.AuthDataSourceType
|
import net.corda.node.services.config.*
|
||||||
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.SecurityConfiguration.AuthService.Companion.defaultAuthServiceId
|
import net.corda.node.services.config.SecurityConfiguration.AuthService.Companion.defaultAuthServiceId
|
||||||
import net.corda.node.services.config.Valid
|
import net.corda.node.services.config.Valid
|
||||||
import net.corda.node.services.config.schema.parsers.attempt
|
import net.corda.node.services.config.schema.parsers.attempt
|
||||||
@ -127,9 +114,19 @@ internal object SecurityConfigurationSpec : Configuration.Specification<Security
|
|||||||
internal object DevModeOptionsSpec : Configuration.Specification<DevModeOptions>("DevModeOptions") {
|
internal object DevModeOptionsSpec : Configuration.Specification<DevModeOptions>("DevModeOptions") {
|
||||||
private val disableCheckpointChecker by boolean().optional().withDefaultValue(DevModeOptions.Defaults.disableCheckpointChecker)
|
private val disableCheckpointChecker by boolean().optional().withDefaultValue(DevModeOptions.Defaults.disableCheckpointChecker)
|
||||||
private val allowCompatibilityZone by boolean().optional().withDefaultValue(DevModeOptions.Defaults.allowCompatibilityZone)
|
private val allowCompatibilityZone by boolean().optional().withDefaultValue(DevModeOptions.Defaults.allowCompatibilityZone)
|
||||||
|
private val djvm by nested(DJVMOptionsSpec).optional()
|
||||||
|
|
||||||
|
private object DJVMOptionsSpec : Configuration.Specification<DJVMOptions>("DJVMOptions") {
|
||||||
|
private val bootstrapSource by string().optional()
|
||||||
|
private val cordaSource by string().list()
|
||||||
|
|
||||||
|
override fun parseValid(configuration: Config): Valid<DJVMOptions> {
|
||||||
|
return valid(DJVMOptions(configuration[bootstrapSource], configuration[cordaSource]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun parseValid(configuration: Config): Valid<DevModeOptions> {
|
override fun parseValid(configuration: Config): Valid<DevModeOptions> {
|
||||||
return valid(DevModeOptions(configuration[disableCheckpointChecker], configuration[allowCompatibilityZone]))
|
return valid(DevModeOptions(configuration[disableCheckpointChecker], configuration[allowCompatibilityZone], configuration[djvm]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,7 +200,9 @@ fun <A> driver(defaultParameters: DriverParameters = DriverParameters(), dsl: Dr
|
|||||||
notaryCustomOverrides = defaultParameters.notaryCustomOverrides,
|
notaryCustomOverrides = defaultParameters.notaryCustomOverrides,
|
||||||
inMemoryDB = defaultParameters.inMemoryDB,
|
inMemoryDB = defaultParameters.inMemoryDB,
|
||||||
cordappsForAllNodes = uncheckedCast(defaultParameters.cordappsForAllNodes),
|
cordappsForAllNodes = uncheckedCast(defaultParameters.cordappsForAllNodes),
|
||||||
environmentVariables = defaultParameters.environmentVariables
|
environmentVariables = defaultParameters.environmentVariables,
|
||||||
|
djvmBootstrapSource = defaultParameters.djvmBootstrapSource,
|
||||||
|
djvmCordaSource = defaultParameters.djvmCordaSource
|
||||||
),
|
),
|
||||||
coerce = { it },
|
coerce = { it },
|
||||||
dsl = dsl
|
dsl = dsl
|
||||||
@ -257,7 +259,9 @@ data class DriverParameters(
|
|||||||
val notaryCustomOverrides: Map<String, Any?> = emptyMap(),
|
val notaryCustomOverrides: Map<String, Any?> = emptyMap(),
|
||||||
val inMemoryDB: Boolean = true,
|
val inMemoryDB: Boolean = true,
|
||||||
val cordappsForAllNodes: Collection<TestCordapp>? = null,
|
val cordappsForAllNodes: Collection<TestCordapp>? = null,
|
||||||
val environmentVariables : Map<String, String> = emptyMap()
|
val environmentVariables : Map<String, String> = emptyMap(),
|
||||||
|
val djvmBootstrapSource: Path? = null,
|
||||||
|
val djvmCordaSource: List<Path> = emptyList()
|
||||||
) {
|
) {
|
||||||
constructor(cordappsForAllNodes: Collection<TestCordapp>) : this(isDebug = false, cordappsForAllNodes = cordappsForAllNodes)
|
constructor(cordappsForAllNodes: Collection<TestCordapp>) : this(isDebug = false, cordappsForAllNodes = cordappsForAllNodes)
|
||||||
|
|
||||||
|
@ -2,10 +2,7 @@ package net.corda.testing.node.internal
|
|||||||
|
|
||||||
import co.paralleluniverse.fibers.instrument.JavaAgent
|
import co.paralleluniverse.fibers.instrument.JavaAgent
|
||||||
import com.google.common.util.concurrent.ThreadFactoryBuilder
|
import com.google.common.util.concurrent.ThreadFactoryBuilder
|
||||||
import com.typesafe.config.Config
|
import com.typesafe.config.*
|
||||||
import com.typesafe.config.ConfigFactory
|
|
||||||
import com.typesafe.config.ConfigRenderOptions
|
|
||||||
import com.typesafe.config.ConfigValueFactory
|
|
||||||
import net.corda.client.rpc.CordaRPCClient
|
import net.corda.client.rpc.CordaRPCClient
|
||||||
import net.corda.cliutils.CommonCliConstants.BASE_DIR
|
import net.corda.cliutils.CommonCliConstants.BASE_DIR
|
||||||
import net.corda.core.concurrent.CordaFuture
|
import net.corda.core.concurrent.CordaFuture
|
||||||
@ -92,7 +89,9 @@ class DriverDSLImpl(
|
|||||||
val notaryCustomOverrides: Map<String, Any?>,
|
val notaryCustomOverrides: Map<String, Any?>,
|
||||||
val inMemoryDB: Boolean,
|
val inMemoryDB: Boolean,
|
||||||
val cordappsForAllNodes: Collection<TestCordappInternal>?,
|
val cordappsForAllNodes: Collection<TestCordappInternal>?,
|
||||||
val environmentVariables : Map<String, String>
|
val environmentVariables : Map<String, String>,
|
||||||
|
val djvmBootstrapSource: Path?,
|
||||||
|
val djvmCordaSource: List<Path>
|
||||||
) : InternalDriverDSL {
|
) : InternalDriverDSL {
|
||||||
|
|
||||||
private var _executorService: ScheduledExecutorService? = null
|
private var _executorService: ScheduledExecutorService? = null
|
||||||
@ -129,7 +128,7 @@ class DriverDSLImpl(
|
|||||||
if (inMemoryDB && corda.dataSourceProperties.getProperty("dataSource.url").startsWith("jdbc:h2:")) {
|
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"
|
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)
|
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 {
|
} else {
|
||||||
this
|
this
|
||||||
}
|
}
|
||||||
@ -236,11 +235,13 @@ class DriverDSLImpl(
|
|||||||
NodeConfiguration::flowOverrides.name to flowOverrideConfig.toConfig().root().unwrapped(),
|
NodeConfiguration::flowOverrides.name to flowOverrideConfig.toConfig().root().unwrapped(),
|
||||||
NodeConfiguration::additionalNodeInfoPollingFrequencyMsec.name to 1000
|
NodeConfiguration::additionalNodeInfoPollingFrequencyMsec.name to 1000
|
||||||
) + czUrlConfig + jmxConfig + parameters.customOverrides
|
) + czUrlConfig + jmxConfig + parameters.customOverrides
|
||||||
val config = NodeConfig(ConfigHelper.loadConfig(
|
val config = NodeConfig(
|
||||||
|
ConfigHelper.loadConfig(
|
||||||
baseDirectory = baseDirectory(name),
|
baseDirectory = baseDirectory(name),
|
||||||
allowMissingConfig = true,
|
allowMissingConfig = true,
|
||||||
configOverrides = if (overrides.hasPath("devMode")) overrides else overrides + mapOf("devMode" to true)
|
configOverrides = if (overrides.hasPath("devMode")) overrides else overrides + mapOf("devMode" to true)
|
||||||
)).checkAndOverrideForInMemoryDB()
|
).withDJVMConfig(djvmBootstrapSource, djvmCordaSource)
|
||||||
|
).checkAndOverrideForInMemoryDB()
|
||||||
return startNodeInternal(config, webAddress, localNetworkMap, parameters)
|
return startNodeInternal(config, webAddress, localNetworkMap, parameters)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,11 +262,13 @@ class DriverDSLImpl(
|
|||||||
),
|
),
|
||||||
"additionalNodeInfoPollingFrequencyMsec" to 1000,
|
"additionalNodeInfoPollingFrequencyMsec" to 1000,
|
||||||
"devMode" to false) + customOverrides
|
"devMode" to false) + customOverrides
|
||||||
val config = NodeConfig(ConfigHelper.loadConfig(
|
val config = NodeConfig(
|
||||||
|
ConfigHelper.loadConfig(
|
||||||
baseDirectory = baseDirectory,
|
baseDirectory = baseDirectory,
|
||||||
allowMissingConfig = true,
|
allowMissingConfig = true,
|
||||||
configOverrides = overrides
|
configOverrides = overrides
|
||||||
)).checkAndOverrideForInMemoryDB()
|
).withDJVMConfig(djvmBootstrapSource, djvmCordaSource)
|
||||||
|
).checkAndOverrideForInMemoryDB()
|
||||||
|
|
||||||
val versionInfo = VersionInfo(PLATFORM_VERSION, "1", "1", "1")
|
val versionInfo = VersionInfo(PLATFORM_VERSION, "1", "1", "1")
|
||||||
config.corda.certificatesDirectory.createDirectories()
|
config.corda.certificatesDirectory.createDirectories()
|
||||||
@ -711,6 +714,25 @@ class DriverDSLImpl(
|
|||||||
Permissions.invokeRpc(CordaRPCOps::killFlow)
|
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<Path>): Config {
|
||||||
|
return withOptionalValue("devModeOptions.djvm.bootstrapSource", bootstrapSource) { path -> valueFor(path.toString()) }
|
||||||
|
.withValue("devModeOptions.djvm.cordaSource", valueFor(cordaSource.map(Path::toString)))
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun <T> Config.withOptionalValue(key: String, obj: T?, body: (T) -> ConfigValue): Config {
|
||||||
|
return if (obj == null) {
|
||||||
|
this
|
||||||
|
} else {
|
||||||
|
withValue(key, body(obj))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <T> valueFor(any: T): ConfigValue = ConfigValueFactory.fromAnyRef(any)
|
||||||
|
|
||||||
private fun <A> oneOf(array: Array<A>) = array[Random().nextInt(array.size)]
|
private fun <A> oneOf(array: Array<A>) = array[Random().nextInt(array.size)]
|
||||||
|
|
||||||
private fun startInProcessNode(
|
private fun startInProcessNode(
|
||||||
@ -767,16 +789,17 @@ class DriverDSLImpl(
|
|||||||
systemProperties += overriddenSystemProperties
|
systemProperties += overriddenSystemProperties
|
||||||
|
|
||||||
// See experimental/quasar-hook/README.md for how to generate.
|
// 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.fasterxml**;com.google**;com.ibm**;com.intellij**;com.jcabi**;com.nhaarman**;com.opengamma**;" +
|
||||||
"com.typesafe**;com.zaxxer**;de.javakaffee**;groovy**;groovyjarjarantlr**;groovyjarjarasm**;io.atomix**;" +
|
"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.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.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**;" +
|
"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**;)"
|
"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}" } +
|
val extraJvmArguments = systemProperties.removeResolvedClasspath().map { "-D${it.key}=${it.value}" } +
|
||||||
"-javaagent:$quasarJarPath=$excludePattern"
|
"-javaagent:$quasarJarPath=$excludePackagePattern$excludeClassloaderPattern"
|
||||||
|
|
||||||
val loggingLevel = when {
|
val loggingLevel = when {
|
||||||
logLevelOverride != null -> logLevelOverride
|
logLevelOverride != null -> logLevelOverride
|
||||||
@ -1030,7 +1053,9 @@ fun <DI : DriverDSL, D : InternalDriverDSL, A> genericDriver(
|
|||||||
notaryCustomOverrides = defaultParameters.notaryCustomOverrides,
|
notaryCustomOverrides = defaultParameters.notaryCustomOverrides,
|
||||||
inMemoryDB = defaultParameters.inMemoryDB,
|
inMemoryDB = defaultParameters.inMemoryDB,
|
||||||
cordappsForAllNodes = uncheckedCast(defaultParameters.cordappsForAllNodes),
|
cordappsForAllNodes = uncheckedCast(defaultParameters.cordappsForAllNodes),
|
||||||
environmentVariables = defaultParameters.environmentVariables
|
environmentVariables = defaultParameters.environmentVariables,
|
||||||
|
djvmBootstrapSource = defaultParameters.djvmBootstrapSource,
|
||||||
|
djvmCordaSource = defaultParameters.djvmCordaSource
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
val shutdownHook = addShutdownHook(driverDsl::shutdown)
|
val shutdownHook = addShutdownHook(driverDsl::shutdown)
|
||||||
@ -1126,6 +1151,8 @@ fun <A> internalDriver(
|
|||||||
inMemoryDB: Boolean = DriverParameters().inMemoryDB,
|
inMemoryDB: Boolean = DriverParameters().inMemoryDB,
|
||||||
cordappsForAllNodes: Collection<TestCordappInternal>? = null,
|
cordappsForAllNodes: Collection<TestCordappInternal>? = null,
|
||||||
environmentVariables: Map<String, String> = emptyMap(),
|
environmentVariables: Map<String, String> = emptyMap(),
|
||||||
|
djvmBootstrapSource: Path? = null,
|
||||||
|
djvmCordaSource: List<Path> = emptyList(),
|
||||||
dsl: DriverDSLImpl.() -> A
|
dsl: DriverDSLImpl.() -> A
|
||||||
): A {
|
): A {
|
||||||
return genericDriver(
|
return genericDriver(
|
||||||
@ -1146,7 +1173,9 @@ fun <A> internalDriver(
|
|||||||
notaryCustomOverrides = notaryCustomOverrides,
|
notaryCustomOverrides = notaryCustomOverrides,
|
||||||
inMemoryDB = inMemoryDB,
|
inMemoryDB = inMemoryDB,
|
||||||
cordappsForAllNodes = cordappsForAllNodes,
|
cordappsForAllNodes = cordappsForAllNodes,
|
||||||
environmentVariables = environmentVariables
|
environmentVariables = environmentVariables,
|
||||||
|
djvmBootstrapSource = djvmBootstrapSource,
|
||||||
|
djvmCordaSource = djvmCordaSource
|
||||||
),
|
),
|
||||||
coerce = { it },
|
coerce = { it },
|
||||||
dsl = dsl
|
dsl = dsl
|
||||||
|
@ -123,6 +123,8 @@ fun <A> rpcDriver(
|
|||||||
inMemoryDB: Boolean = true,
|
inMemoryDB: Boolean = true,
|
||||||
cordappsForAllNodes: Collection<TestCordappInternal>? = null,
|
cordappsForAllNodes: Collection<TestCordappInternal>? = null,
|
||||||
environmentVariables: Map<String, String> = emptyMap(),
|
environmentVariables: Map<String, String> = emptyMap(),
|
||||||
|
djvmBootstrapSource: Path? = null,
|
||||||
|
djvmCordaSource: List<Path> = emptyList(),
|
||||||
dsl: RPCDriverDSL.() -> A
|
dsl: RPCDriverDSL.() -> A
|
||||||
): A {
|
): A {
|
||||||
return genericDriver(
|
return genericDriver(
|
||||||
@ -144,7 +146,9 @@ fun <A> rpcDriver(
|
|||||||
notaryCustomOverrides = notaryCustomOverrides,
|
notaryCustomOverrides = notaryCustomOverrides,
|
||||||
inMemoryDB = inMemoryDB,
|
inMemoryDB = inMemoryDB,
|
||||||
cordappsForAllNodes = cordappsForAllNodes,
|
cordappsForAllNodes = cordappsForAllNodes,
|
||||||
environmentVariables = environmentVariables
|
environmentVariables = environmentVariables,
|
||||||
|
djvmBootstrapSource = djvmBootstrapSource,
|
||||||
|
djvmCordaSource = djvmCordaSource
|
||||||
), externalTrace
|
), externalTrace
|
||||||
),
|
),
|
||||||
coerce = { it },
|
coerce = { it },
|
||||||
|
Loading…
x
Reference in New Issue
Block a user