mirror of
https://github.com/corda/corda.git
synced 2024-12-19 04:57:58 +00:00
Another approach to fixing deployNodes task and network parameters generation (#2066)
* Generate networkParameteres for Cordformation. Fix deployNodes task in Cordformation to generate NetworkParameters before running the nodes. Add TestNetworkParametersGenerator utility loaded after node infos generation step. * Get rid of bouncy castle provider dependency For cordform-common. It caused problems with loading our custom X509EdDSAEngine for generation of network parameters in deployNodes task.
This commit is contained in:
parent
572c4af40c
commit
c9f3e98795
@ -1,4 +1,4 @@
|
|||||||
gradlePluginsVersion=2.0.9
|
gradlePluginsVersion=3.0.0-NETWORKMAP
|
||||||
kotlinVersion=1.1.60
|
kotlinVersion=1.1.60
|
||||||
guavaVersion=21.0
|
guavaVersion=21.0
|
||||||
bouncycastleVersion=1.57
|
bouncycastleVersion=1.57
|
||||||
|
@ -13,9 +13,6 @@ group 'net.corda.plugins'
|
|||||||
dependencies {
|
dependencies {
|
||||||
// TypeSafe Config: for simple and human friendly config files.
|
// TypeSafe Config: for simple and human friendly config files.
|
||||||
compile "com.typesafe:config:$typesafe_config_version"
|
compile "com.typesafe:config:$typesafe_config_version"
|
||||||
|
|
||||||
// Bouncy Castle: for X.500 distinguished name manipulation
|
|
||||||
compile "org.bouncycastle:bcprov-jdk15on:$bouncycastle_version"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
publish {
|
publish {
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package net.corda.cordform;
|
package net.corda.cordform;
|
||||||
|
|
||||||
import org.bouncycastle.asn1.x500.X500Name;
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
|
||||||
public interface CordformContext {
|
public interface CordformContext {
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
package net.corda.cordform;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public interface NetworkParametersGenerator {
|
||||||
|
/**
|
||||||
|
* Run generation of network parameters for [Cordformation]. Nodes need to have already their own [NodeInfo] files in their
|
||||||
|
* base directories, these files will be used to extract notary identities.
|
||||||
|
*
|
||||||
|
* @param nodesDirs - nodes directories that will be used for network parameters generation. Network parameters
|
||||||
|
* file will be dropped into each directory on this list.
|
||||||
|
*/
|
||||||
|
void run(List<Path> nodesDirs);
|
||||||
|
}
|
@ -3,15 +3,14 @@ package net.corda.plugins
|
|||||||
import groovy.lang.Closure
|
import groovy.lang.Closure
|
||||||
import net.corda.cordform.CordformDefinition
|
import net.corda.cordform.CordformDefinition
|
||||||
import net.corda.cordform.CordformNode
|
import net.corda.cordform.CordformNode
|
||||||
|
import net.corda.cordform.NetworkParametersGenerator
|
||||||
import org.apache.tools.ant.filters.FixCrLfFilter
|
import org.apache.tools.ant.filters.FixCrLfFilter
|
||||||
import org.gradle.api.DefaultTask
|
import org.gradle.api.DefaultTask
|
||||||
import org.gradle.api.GradleException
|
import org.gradle.api.GradleException
|
||||||
import org.gradle.api.plugins.JavaPluginConvention
|
import org.gradle.api.plugins.JavaPluginConvention
|
||||||
import org.gradle.api.tasks.SourceSet.MAIN_SOURCE_SET_NAME
|
import org.gradle.api.tasks.SourceSet.MAIN_SOURCE_SET_NAME
|
||||||
import org.gradle.api.tasks.TaskAction
|
import org.gradle.api.tasks.TaskAction
|
||||||
import java.io.File
|
|
||||||
import java.net.URLClassLoader
|
import java.net.URLClassLoader
|
||||||
import java.nio.file.Files
|
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.nio.file.Paths
|
import java.nio.file.Paths
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
@ -28,6 +27,7 @@ open class Cordform : DefaultTask() {
|
|||||||
*/
|
*/
|
||||||
@Suppress("MemberVisibilityCanPrivate")
|
@Suppress("MemberVisibilityCanPrivate")
|
||||||
var definitionClass: String? = null
|
var definitionClass: String? = null
|
||||||
|
private val networkParametersGenClass: String = "net.corda.nodeapi.internal.TestNetworkParametersGenerator"
|
||||||
private var directory = Paths.get("build", "nodes")
|
private var directory = Paths.get("build", "nodes")
|
||||||
private val nodes = mutableListOf<Node>()
|
private val nodes = mutableListOf<Node>()
|
||||||
|
|
||||||
@ -113,6 +113,19 @@ open class Cordform : DefaultTask() {
|
|||||||
.newInstance()
|
.newInstance()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The parametersGenerator needn't be compiled until just before our build method, so we load it manually via sourceSets.main.runtimeClasspath.
|
||||||
|
*/
|
||||||
|
private fun loadParametersGenerator(): NetworkParametersGenerator {
|
||||||
|
val plugin = project.convention.getPlugin(JavaPluginConvention::class.java)
|
||||||
|
val classpath = plugin.sourceSets.getByName(MAIN_SOURCE_SET_NAME).runtimeClasspath
|
||||||
|
val urls = classpath.files.map { it.toURI().toURL() }.toTypedArray()
|
||||||
|
return URLClassLoader(urls, NetworkParametersGenerator::class.java.classLoader)
|
||||||
|
.loadClass(networkParametersGenClass)
|
||||||
|
.asSubclass(NetworkParametersGenerator::class.java)
|
||||||
|
.newInstance()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This task action will create and install the nodes based on the node configurations added.
|
* This task action will create and install the nodes based on the node configurations added.
|
||||||
*/
|
*/
|
||||||
@ -124,6 +137,7 @@ open class Cordform : DefaultTask() {
|
|||||||
installRunScript()
|
installRunScript()
|
||||||
nodes.forEach(Node::build)
|
nodes.forEach(Node::build)
|
||||||
generateAndInstallNodeInfos()
|
generateAndInstallNodeInfos()
|
||||||
|
generateAndInstallNetworkParameters()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initializeConfiguration() {
|
private fun initializeConfiguration() {
|
||||||
@ -142,6 +156,12 @@ open class Cordform : DefaultTask() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun generateAndInstallNetworkParameters() {
|
||||||
|
project.logger.info("Generating and installing network parameters")
|
||||||
|
val networkParamsGenerator = loadParametersGenerator()
|
||||||
|
networkParamsGenerator.run(nodes.map { it.fullPath() })
|
||||||
|
}
|
||||||
|
|
||||||
private fun generateAndInstallNodeInfos() {
|
private fun generateAndInstallNodeInfos() {
|
||||||
generateNodeInfos()
|
generateNodeInfos()
|
||||||
installNodeInfos()
|
installNodeInfos()
|
||||||
@ -149,7 +169,7 @@ open class Cordform : DefaultTask() {
|
|||||||
|
|
||||||
private fun generateNodeInfos() {
|
private fun generateNodeInfos() {
|
||||||
project.logger.info("Generating node infos")
|
project.logger.info("Generating node infos")
|
||||||
var nodeProcesses = buildNodeProcesses()
|
val nodeProcesses = buildNodeProcesses()
|
||||||
try {
|
try {
|
||||||
validateNodeProcessess(nodeProcesses)
|
validateNodeProcessess(nodeProcesses)
|
||||||
} finally {
|
} finally {
|
||||||
@ -158,9 +178,10 @@ open class Cordform : DefaultTask() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun buildNodeProcesses(): Map<Node, Process> {
|
private fun buildNodeProcesses(): Map<Node, Process> {
|
||||||
return nodes
|
val command = generateNodeInfoCommand()
|
||||||
.map { buildNodeProcess(it) }
|
return nodes.map {
|
||||||
.toMap()
|
it.makeLogDirectory()
|
||||||
|
buildProcess(it, command, "generate-info.log") }.toMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun validateNodeProcessess(nodeProcesses: Map<Node, Process>) {
|
private fun validateNodeProcessess(nodeProcesses: Map<Node, Process>) {
|
||||||
@ -175,14 +196,13 @@ open class Cordform : DefaultTask() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildNodeProcess(node: Node): Pair<Node, Process> {
|
private fun buildProcess(node: Node, command: List<String>, logFile: String): Pair<Node, Process> {
|
||||||
node.makeLogDirectory()
|
val process = ProcessBuilder(command)
|
||||||
var process = ProcessBuilder(generateNodeInfoCommand())
|
|
||||||
.directory(node.fullPath().toFile())
|
.directory(node.fullPath().toFile())
|
||||||
.redirectErrorStream(true)
|
.redirectErrorStream(true)
|
||||||
// InheritIO causes hangs on windows due the gradle buffer also not being flushed.
|
// InheritIO causes hangs on windows due the gradle buffer also not being flushed.
|
||||||
// Must redirect to output or logger (node log is still written, this is just startup banner)
|
// Must redirect to output or logger (node log is still written, this is just startup banner)
|
||||||
.redirectOutput(node.logFile().toFile())
|
.redirectOutput(node.logFile(logFile).toFile())
|
||||||
.addEnvironment("CAPSULE_CACHE_DIR", Node.capsuleCacheDir)
|
.addEnvironment("CAPSULE_CACHE_DIR", Node.capsuleCacheDir)
|
||||||
.start()
|
.start()
|
||||||
return Pair(node, process)
|
return Pair(node, process)
|
||||||
@ -224,6 +244,6 @@ open class Cordform : DefaultTask() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private fun Node.logFile(): Path = this.logDirectory().resolve("generate-info.log")
|
private fun Node.logFile(name: String): Path = this.logDirectory().resolve(name)
|
||||||
private fun ProcessBuilder.addEnvironment(key: String, value: String) = this.apply { environment().put(key, value) }
|
private fun ProcessBuilder.addEnvironment(key: String, value: String) = this.apply { environment().put(key, value) }
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,6 @@ package net.corda.plugins
|
|||||||
|
|
||||||
import com.typesafe.config.*
|
import com.typesafe.config.*
|
||||||
import net.corda.cordform.CordformNode
|
import net.corda.cordform.CordformNode
|
||||||
import org.bouncycastle.asn1.x500.X500Name
|
|
||||||
import org.bouncycastle.asn1.x500.RDN
|
|
||||||
import org.bouncycastle.asn1.x500.style.BCStyle
|
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.nio.charset.StandardCharsets
|
import java.nio.charset.StandardCharsets
|
||||||
@ -122,18 +119,10 @@ class Node(private val project: Project) : CordformNode() {
|
|||||||
project.logger.error("Node has a null name - cannot create node")
|
project.logger.error("Node has a null name - cannot create node")
|
||||||
throw IllegalStateException("Node has a null name - cannot create node")
|
throw IllegalStateException("Node has a null name - cannot create node")
|
||||||
}
|
}
|
||||||
|
// Parsing O= part directly because importing BouncyCastle provider in Cordformation causes problems
|
||||||
val dirName = try {
|
// with loading our custom X509EdDSAEngine.
|
||||||
val o = X500Name(name).getRDNs(BCStyle.O)
|
val organizationName = name.trim().split(",").firstOrNull { it.startsWith("O=") }?.substringAfter("=")
|
||||||
if (o.size > 0) {
|
val dirName = organizationName ?: name
|
||||||
o.first().first.value.toString()
|
|
||||||
} else {
|
|
||||||
name
|
|
||||||
}
|
|
||||||
} catch(_ : IllegalArgumentException) {
|
|
||||||
// Can't parse as an X500 name, use the full string
|
|
||||||
name
|
|
||||||
}
|
|
||||||
nodeDir = File(rootDir.toFile(), dirName)
|
nodeDir = File(rootDir.toFile(), dirName)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,7 +140,7 @@ class Node(private val project: Project) : CordformNode() {
|
|||||||
* Installs the corda fat JAR to the node directory.
|
* Installs the corda fat JAR to the node directory.
|
||||||
*/
|
*/
|
||||||
private fun installCordaJar() {
|
private fun installCordaJar() {
|
||||||
val cordaJar = verifyAndGetCordaJar()
|
val cordaJar = verifyAndGetRuntimeJar("corda")
|
||||||
project.copy {
|
project.copy {
|
||||||
it.apply {
|
it.apply {
|
||||||
from(cordaJar)
|
from(cordaJar)
|
||||||
@ -166,7 +155,7 @@ class Node(private val project: Project) : CordformNode() {
|
|||||||
* Installs the corda webserver JAR to the node directory
|
* Installs the corda webserver JAR to the node directory
|
||||||
*/
|
*/
|
||||||
private fun installWebserverJar() {
|
private fun installWebserverJar() {
|
||||||
val webJar = verifyAndGetWebserverJar()
|
val webJar = verifyAndGetRuntimeJar("corda-webserver")
|
||||||
project.copy {
|
project.copy {
|
||||||
it.apply {
|
it.apply {
|
||||||
from(webJar)
|
from(webJar)
|
||||||
@ -250,34 +239,17 @@ class Node(private val project: Project) : CordformNode() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the corda JAR amongst the dependencies.
|
* Find the given JAR amongst the dependencies
|
||||||
|
* @param jarName JAR name without the version part, for example for corda-2.0-SNAPSHOT.jar provide only "corda" as jarName
|
||||||
*
|
*
|
||||||
* @return A file representing the Corda JAR.
|
* @return A file representing found JAR
|
||||||
*/
|
*/
|
||||||
private fun verifyAndGetCordaJar(): File {
|
private fun verifyAndGetRuntimeJar(jarName: String): File {
|
||||||
val maybeCordaJAR = project.configuration("runtime").filter {
|
|
||||||
it.toString().contains("corda-$releaseVersion.jar") || it.toString().contains("corda-enterprise-$releaseVersion.jar")
|
|
||||||
}
|
|
||||||
if (maybeCordaJAR.isEmpty) {
|
|
||||||
throw RuntimeException("No Corda Capsule JAR found. Have you deployed the Corda project to Maven? Looked for \"corda-$releaseVersion.jar\"")
|
|
||||||
} else {
|
|
||||||
val cordaJar = maybeCordaJAR.singleFile
|
|
||||||
assert(cordaJar.isFile)
|
|
||||||
return cordaJar
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find the corda JAR amongst the dependencies
|
|
||||||
*
|
|
||||||
* @return A file representing the Corda webserver JAR
|
|
||||||
*/
|
|
||||||
private fun verifyAndGetWebserverJar(): File {
|
|
||||||
val maybeJar = project.configuration("runtime").filter {
|
val maybeJar = project.configuration("runtime").filter {
|
||||||
it.toString().contains("corda-webserver-$releaseVersion.jar")
|
"$jarName-$releaseVersion.jar" in it.toString() || "$jarName-enterprise-$releaseVersion.jar" in it.toString()
|
||||||
}
|
}
|
||||||
if (maybeJar.isEmpty) {
|
if (maybeJar.isEmpty) {
|
||||||
throw RuntimeException("No Corda Webserver JAR found. Have you deployed the Corda project to Maven? Looked for \"corda-webserver-$releaseVersion.jar\"")
|
throw IllegalStateException("No $jarName JAR found. Have you deployed the Corda project to Maven? Looked for \"$jarName-$releaseVersion.jar\"")
|
||||||
} else {
|
} else {
|
||||||
val jar = maybeJar.singleFile
|
val jar = maybeJar.singleFile
|
||||||
assert(jar.isFile)
|
assert(jar.isFile)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package net.corda.testing.common.internal
|
package net.corda.nodeapi.internal
|
||||||
|
|
||||||
import net.corda.core.crypto.SignedData
|
import net.corda.core.crypto.SignedData
|
||||||
import net.corda.core.crypto.entropyToKeyPair
|
import net.corda.core.crypto.entropyToKeyPair
|
@ -0,0 +1,115 @@
|
|||||||
|
package net.corda.nodeapi.internal
|
||||||
|
|
||||||
|
import com.typesafe.config.ConfigFactory
|
||||||
|
import net.corda.cordform.CordformNode
|
||||||
|
import net.corda.cordform.NetworkParametersGenerator
|
||||||
|
import net.corda.core.crypto.SignedData
|
||||||
|
import net.corda.core.identity.CordaX500Name
|
||||||
|
import net.corda.core.internal.div
|
||||||
|
import net.corda.core.internal.list
|
||||||
|
import net.corda.core.internal.readAll
|
||||||
|
import net.corda.core.node.NodeInfo
|
||||||
|
import net.corda.core.serialization.SerializationContext
|
||||||
|
import net.corda.core.serialization.deserialize
|
||||||
|
import net.corda.core.serialization.internal.SerializationEnvironmentImpl
|
||||||
|
import net.corda.core.serialization.internal._contextSerializationEnv
|
||||||
|
import net.corda.core.utilities.ByteSequence
|
||||||
|
import net.corda.core.utilities.contextLogger
|
||||||
|
import net.corda.core.utilities.days
|
||||||
|
import net.corda.nodeapi.internal.serialization.*
|
||||||
|
import net.corda.nodeapi.internal.serialization.amqp.AMQPServerSerializationScheme
|
||||||
|
import net.corda.nodeapi.internal.serialization.kryo.AbstractKryoSerializationScheme
|
||||||
|
import net.corda.nodeapi.internal.serialization.kryo.KryoHeaderV0_1
|
||||||
|
import java.nio.file.Path
|
||||||
|
import java.time.Instant
|
||||||
|
import kotlin.streams.toList
|
||||||
|
|
||||||
|
// This class is used by deployNodes task to generate NetworkParameters in [Cordformation].
|
||||||
|
@Suppress("UNUSED")
|
||||||
|
class TestNetworkParametersGenerator : NetworkParametersGenerator {
|
||||||
|
companion object {
|
||||||
|
private val logger = contextLogger()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun run(nodesDirs: List<Path>) {
|
||||||
|
logger.info("NetworkParameters generation using node directories: $nodesDirs")
|
||||||
|
try {
|
||||||
|
initialiseSerialization()
|
||||||
|
val notaryInfos = loadAndGatherNotaryIdentities(nodesDirs)
|
||||||
|
val copier = NetworkParametersCopier(NetworkParameters(
|
||||||
|
minimumPlatformVersion = 1,
|
||||||
|
notaries = notaryInfos,
|
||||||
|
modifiedTime = Instant.now(),
|
||||||
|
eventHorizon = 10000.days,
|
||||||
|
maxMessageSize = 40000,
|
||||||
|
maxTransactionSize = 40000,
|
||||||
|
epoch = 1
|
||||||
|
))
|
||||||
|
nodesDirs.forEach { copier.install(it) }
|
||||||
|
} finally {
|
||||||
|
_contextSerializationEnv.set(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadAndGatherNotaryIdentities(nodesDirs: List<Path>): List<NotaryInfo> {
|
||||||
|
val infos = getAllNodeInfos(nodesDirs)
|
||||||
|
val configs = nodesDirs.map { ConfigFactory.parseFile((it / "node.conf").toFile()) }
|
||||||
|
val notaryConfigs = configs.filter { it.hasPath("notary") }
|
||||||
|
val notaries = notaryConfigs.associateBy(
|
||||||
|
{ CordaX500Name.parse(it.getString("myLegalName")) },
|
||||||
|
{ it.getConfig("notary").getBoolean("validating") }
|
||||||
|
)
|
||||||
|
// Now get the notary identities based on names passed from configs. There is one problem, for distributed notaries
|
||||||
|
// in config we specify only node's main name, the notary identity isn't passed there. It's read from keystore on
|
||||||
|
// node startup, so we have to look it up from node info as a second identity, which is ugly.
|
||||||
|
return infos.mapNotNull {
|
||||||
|
info -> notaries[info.legalIdentities[0].name]?.let { NotaryInfo(info.notaryIdentity(), it) }
|
||||||
|
}.distinct()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads latest NodeInfo files stored in node's base directory.
|
||||||
|
* Scans main directory and [CordformNode.NODE_INFO_DIRECTORY].
|
||||||
|
* Signatures are checked before returning a value. The latest value stored for a given name is returned.
|
||||||
|
*
|
||||||
|
* @return list of latest [NodeInfo]s
|
||||||
|
*/
|
||||||
|
private fun getAllNodeInfos(nodesDirs: List<Path>): List<NodeInfo> {
|
||||||
|
val nodeInfoFiles = nodesDirs.map { dir -> dir.list { it.filter { "nodeInfo-" in it.toString() }.toList()[0] } } // We take the first one only
|
||||||
|
return nodeInfoFiles.mapNotNull { processFile(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun processFile(file: Path): NodeInfo? {
|
||||||
|
return try {
|
||||||
|
logger.info("Reading NodeInfo from file: $file")
|
||||||
|
val signedData = file.readAll().deserialize<SignedData<NodeInfo>>()
|
||||||
|
signedData.verified()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logger.warn("Exception parsing NodeInfo from file. $file", e)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun NodeInfo.notaryIdentity() = if (legalIdentities.size == 2) legalIdentities[1] else legalIdentities[0]
|
||||||
|
|
||||||
|
// We need to to set serialization env, because generation of parameters is run from Cordform.
|
||||||
|
// KryoServerSerializationScheme is not accessible from nodeapi.
|
||||||
|
private fun initialiseSerialization() {
|
||||||
|
val context = if (java.lang.Boolean.getBoolean("net.corda.testing.amqp.enable")) AMQP_P2P_CONTEXT else KRYO_P2P_CONTEXT
|
||||||
|
_contextSerializationEnv.set(SerializationEnvironmentImpl(
|
||||||
|
SerializationFactoryImpl().apply {
|
||||||
|
registerScheme(KryoParametersSerializationScheme)
|
||||||
|
registerScheme(AMQPServerSerializationScheme())
|
||||||
|
},
|
||||||
|
context))
|
||||||
|
}
|
||||||
|
|
||||||
|
private object KryoParametersSerializationScheme : AbstractKryoSerializationScheme() {
|
||||||
|
override fun canDeserializeVersion(byteSequence: ByteSequence, target: SerializationContext.UseCase): Boolean {
|
||||||
|
return byteSequence == KryoHeaderV0_1 && target == SerializationContext.UseCase.P2P
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun rpcClientKryoPool(context: SerializationContext) = throw UnsupportedOperationException()
|
||||||
|
override fun rpcServerKryoPool(context: SerializationContext) = throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
}
|
@ -27,7 +27,7 @@ import net.corda.node.services.transactions.minCorrectReplicas
|
|||||||
import net.corda.node.utilities.ServiceIdentityGenerator
|
import net.corda.node.utilities.ServiceIdentityGenerator
|
||||||
import net.corda.nodeapi.internal.NotaryInfo
|
import net.corda.nodeapi.internal.NotaryInfo
|
||||||
import net.corda.testing.chooseIdentity
|
import net.corda.testing.chooseIdentity
|
||||||
import net.corda.testing.common.internal.NetworkParametersCopier
|
import net.corda.nodeapi.internal.NetworkParametersCopier
|
||||||
import net.corda.testing.common.internal.testNetworkParameters
|
import net.corda.testing.common.internal.testNetworkParameters
|
||||||
import net.corda.testing.contracts.DummyContract
|
import net.corda.testing.contracts.DummyContract
|
||||||
import net.corda.testing.dummyCommand
|
import net.corda.testing.dummyCommand
|
||||||
|
@ -63,6 +63,7 @@ import org.apache.activemq.artemis.utils.ReusableLatch
|
|||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
import java.io.NotSerializableException
|
||||||
import java.lang.reflect.InvocationTargetException
|
import java.lang.reflect.InvocationTargetException
|
||||||
import java.security.KeyPair
|
import java.security.KeyPair
|
||||||
import java.security.KeyStoreException
|
import java.security.KeyStoreException
|
||||||
|
@ -27,6 +27,7 @@ class RPCMessagingClient(private val config: SSLConfiguration, serverAddress: Ne
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun stop() = synchronized(this) {
|
fun stop() = synchronized(this) {
|
||||||
|
rpcServer?.close()
|
||||||
artemis.stop()
|
artemis.stop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ dependencies {
|
|||||||
// Specify your cordapp's dependencies below, including dependent cordapps
|
// Specify your cordapp's dependencies below, including dependent cordapps
|
||||||
compile group: 'commons-io', name: 'commons-io', version: '2.5'
|
compile group: 'commons-io', name: 'commons-io', version: '2.5'
|
||||||
|
|
||||||
testCompile project(':node-driver')
|
cordaCompile project(':node-driver')
|
||||||
testCompile "junit:junit:$junit_version"
|
testCompile "junit:junit:$junit_version"
|
||||||
testCompile "org.assertj:assertj-core:${assertj_version}"
|
testCompile "org.assertj:assertj-core:${assertj_version}"
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ fun <A> springDriver(
|
|||||||
useTestClock: Boolean = defaultParameters.useTestClock,
|
useTestClock: Boolean = defaultParameters.useTestClock,
|
||||||
initialiseSerialization: Boolean = defaultParameters.initialiseSerialization,
|
initialiseSerialization: Boolean = defaultParameters.initialiseSerialization,
|
||||||
startNodesInProcess: Boolean = defaultParameters.startNodesInProcess,
|
startNodesInProcess: Boolean = defaultParameters.startNodesInProcess,
|
||||||
notarySpecs: List<NotarySpec>,
|
notarySpecs: List<NotarySpec> = defaultParameters.notarySpecs,
|
||||||
extraCordappPackagesToScan: List<String> = defaultParameters.extraCordappPackagesToScan,
|
extraCordappPackagesToScan: List<String> = defaultParameters.extraCordappPackagesToScan,
|
||||||
dsl: SpringDriverExposedDSLInterface.() -> A
|
dsl: SpringDriverExposedDSLInterface.() -> A
|
||||||
) = genericDriver(
|
) = genericDriver(
|
||||||
|
@ -36,7 +36,7 @@ import net.corda.nodeapi.config.toConfig
|
|||||||
import net.corda.nodeapi.internal.NotaryInfo
|
import net.corda.nodeapi.internal.NotaryInfo
|
||||||
import net.corda.nodeapi.internal.addShutdownHook
|
import net.corda.nodeapi.internal.addShutdownHook
|
||||||
import net.corda.testing.*
|
import net.corda.testing.*
|
||||||
import net.corda.testing.common.internal.NetworkParametersCopier
|
import net.corda.nodeapi.internal.NetworkParametersCopier
|
||||||
import net.corda.testing.common.internal.testNetworkParameters
|
import net.corda.testing.common.internal.testNetworkParameters
|
||||||
import net.corda.testing.internal.ProcessUtilities
|
import net.corda.testing.internal.ProcessUtilities
|
||||||
import net.corda.testing.node.ClusterSpec
|
import net.corda.testing.node.ClusterSpec
|
||||||
|
@ -16,7 +16,7 @@ import net.corda.node.services.config.parseAsNodeConfiguration
|
|||||||
import net.corda.node.services.config.plus
|
import net.corda.node.services.config.plus
|
||||||
import net.corda.nodeapi.User
|
import net.corda.nodeapi.User
|
||||||
import net.corda.testing.SerializationEnvironmentRule
|
import net.corda.testing.SerializationEnvironmentRule
|
||||||
import net.corda.testing.common.internal.NetworkParametersCopier
|
import net.corda.nodeapi.internal.NetworkParametersCopier
|
||||||
import net.corda.testing.common.internal.testNetworkParameters
|
import net.corda.testing.common.internal.testNetworkParameters
|
||||||
import net.corda.testing.driver.addressMustNotBeBoundFuture
|
import net.corda.testing.driver.addressMustNotBeBoundFuture
|
||||||
import net.corda.testing.getFreeLocalPorts
|
import net.corda.testing.getFreeLocalPorts
|
||||||
|
@ -40,7 +40,7 @@ import net.corda.node.utilities.CordaPersistence
|
|||||||
import net.corda.node.utilities.ServiceIdentityGenerator
|
import net.corda.node.utilities.ServiceIdentityGenerator
|
||||||
import net.corda.nodeapi.internal.NotaryInfo
|
import net.corda.nodeapi.internal.NotaryInfo
|
||||||
import net.corda.testing.DUMMY_NOTARY
|
import net.corda.testing.DUMMY_NOTARY
|
||||||
import net.corda.testing.common.internal.NetworkParametersCopier
|
import net.corda.nodeapi.internal.NetworkParametersCopier
|
||||||
import net.corda.testing.common.internal.testNetworkParameters
|
import net.corda.testing.common.internal.testNetworkParameters
|
||||||
import net.corda.testing.node.MockServices.Companion.MOCK_VERSION_INFO
|
import net.corda.testing.node.MockServices.Companion.MOCK_VERSION_INFO
|
||||||
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
|
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
|
||||||
|
@ -8,7 +8,7 @@ import net.corda.core.internal.createDirectories
|
|||||||
import net.corda.core.internal.div
|
import net.corda.core.internal.div
|
||||||
import net.corda.core.utilities.NetworkHostAndPort
|
import net.corda.core.utilities.NetworkHostAndPort
|
||||||
import net.corda.core.utilities.contextLogger
|
import net.corda.core.utilities.contextLogger
|
||||||
import net.corda.testing.common.internal.NetworkParametersCopier
|
import net.corda.nodeapi.internal.NetworkParametersCopier
|
||||||
import net.corda.testing.common.internal.testNetworkParameters
|
import net.corda.testing.common.internal.testNetworkParameters
|
||||||
import net.corda.testing.common.internal.asContextEnv
|
import net.corda.testing.common.internal.asContextEnv
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
Loading…
Reference in New Issue
Block a user