mirror of
https://github.com/corda/corda.git
synced 2025-06-18 15:18:16 +00:00
CORDA-1924: Remove references to Cordform definition and cordform-common (#3842)
This commit is contained in:
@ -210,7 +210,6 @@ allprojects {
|
|||||||
mavenCentral()
|
mavenCentral()
|
||||||
jcenter()
|
jcenter()
|
||||||
maven { url 'https://jitpack.io' }
|
maven { url 'https://jitpack.io' }
|
||||||
maven { url "$artifactory_contextUrl/corda-releases" } // cordform-common
|
|
||||||
}
|
}
|
||||||
|
|
||||||
configurations {
|
configurations {
|
||||||
|
@ -6,6 +6,8 @@ release, see :doc:`upgrade-notes`.
|
|||||||
|
|
||||||
Unreleased
|
Unreleased
|
||||||
----------
|
----------
|
||||||
|
* Removed experimental feature `CordformDefinition`
|
||||||
|
|
||||||
* Vault query fix: support query by parent classes of Contract State classes (see https://github.com/corda/corda/issues/3714)
|
* Vault query fix: support query by parent classes of Contract State classes (see https://github.com/corda/corda/issues/3714)
|
||||||
|
|
||||||
* Added ``registerResponderFlow`` method to ``StartedMockNode``, to support isolated testing of responder flow behaviour.
|
* Added ``registerResponderFlow`` method to ``StartedMockNode``, to support isolated testing of responder flow behaviour.
|
||||||
|
@ -22,8 +22,6 @@ dependencies {
|
|||||||
// TODO: Remove this dependency and the code that requires it
|
// TODO: Remove this dependency and the code that requires it
|
||||||
compile "commons-fileupload:commons-fileupload:$fileupload_version"
|
compile "commons-fileupload:commons-fileupload:$fileupload_version"
|
||||||
|
|
||||||
compile "net.corda.plugins:cordform-common:$gradle_plugins_version"
|
|
||||||
|
|
||||||
// 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"
|
||||||
|
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
package net.corda.nodeapi.internal
|
||||||
|
|
||||||
|
// TODO: Add to Corda node.conf to allow customisation
|
||||||
|
const val NODE_INFO_DIRECTORY = "additional-node-infos"
|
@ -2,7 +2,6 @@ package net.corda.nodeapi.internal.network
|
|||||||
|
|
||||||
import com.typesafe.config.Config
|
import com.typesafe.config.Config
|
||||||
import com.typesafe.config.ConfigFactory
|
import com.typesafe.config.ConfigFactory
|
||||||
import net.corda.cordform.CordformNode
|
|
||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.internal.*
|
import net.corda.core.internal.*
|
||||||
@ -46,8 +45,8 @@ import kotlin.streams.toList
|
|||||||
*/
|
*/
|
||||||
// TODO Move this to tools:bootstrapper
|
// TODO Move this to tools:bootstrapper
|
||||||
class NetworkBootstrapper
|
class NetworkBootstrapper
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
internal constructor(private val initSerEnv: Boolean,
|
internal constructor(private val initSerEnv: Boolean,
|
||||||
private val embeddedCordaJar: () -> InputStream,
|
private val embeddedCordaJar: () -> InputStream,
|
||||||
private val nodeInfosGenerator: (List<Path>) -> List<Path>,
|
private val nodeInfosGenerator: (List<Path>) -> List<Path>,
|
||||||
private val contractsJarConverter: (Path) -> ContractsJar) {
|
private val contractsJarConverter: (Path) -> ContractsJar) {
|
||||||
@ -269,7 +268,7 @@ class NetworkBootstrapper
|
|||||||
|
|
||||||
private fun distributeNodeInfos(nodeDirs: List<Path>, nodeInfoFiles: List<Path>) {
|
private fun distributeNodeInfos(nodeDirs: List<Path>, nodeInfoFiles: List<Path>) {
|
||||||
for (nodeDir in nodeDirs) {
|
for (nodeDir in nodeDirs) {
|
||||||
val additionalNodeInfosDir = (nodeDir / CordformNode.NODE_INFO_DIRECTORY).createDirectories()
|
val additionalNodeInfosDir = (nodeDir / NODE_INFO_DIRECTORY).createDirectories()
|
||||||
for (nodeInfoFile in nodeInfoFiles) {
|
for (nodeInfoFile in nodeInfoFiles) {
|
||||||
nodeInfoFile.copyToDirectory(additionalNodeInfosDir, REPLACE_EXISTING)
|
nodeInfoFile.copyToDirectory(additionalNodeInfosDir, REPLACE_EXISTING)
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package net.corda.nodeapi.internal.network
|
package net.corda.nodeapi.internal.network
|
||||||
|
|
||||||
import net.corda.cordform.CordformNode
|
|
||||||
import net.corda.core.internal.*
|
import net.corda.core.internal.*
|
||||||
import net.corda.core.utilities.contextLogger
|
import net.corda.core.utilities.contextLogger
|
||||||
|
import net.corda.nodeapi.internal.NODE_INFO_DIRECTORY
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.Scheduler
|
import rx.Scheduler
|
||||||
import rx.Subscription
|
import rx.Subscription
|
||||||
@ -96,7 +96,8 @@ class NodeInfoFilesCopier(scheduler: Scheduler = Schedulers.io()) : AutoCloseabl
|
|||||||
private fun poll() {
|
private fun poll() {
|
||||||
nodeDataMapBox.locked {
|
nodeDataMapBox.locked {
|
||||||
for (nodeData in values) {
|
for (nodeData in values) {
|
||||||
nodeData.nodeDir.list { paths -> paths
|
nodeData.nodeDir.list { paths ->
|
||||||
|
paths
|
||||||
.filter { it.isRegularFile() }
|
.filter { it.isRegularFile() }
|
||||||
.filter { it.fileName.toString().startsWith(NODE_INFO_FILE_NAME_PREFIX) }
|
.filter { it.fileName.toString().startsWith(NODE_INFO_FILE_NAME_PREFIX) }
|
||||||
.forEach { processPath(nodeData, it) }
|
.forEach { processPath(nodeData, it) }
|
||||||
@ -149,7 +150,7 @@ class NodeInfoFilesCopier(scheduler: Scheduler = Schedulers.io()) : AutoCloseabl
|
|||||||
* Convenience holder for all the paths and files relative to a single node.
|
* Convenience holder for all the paths and files relative to a single node.
|
||||||
*/
|
*/
|
||||||
private class NodeData(val nodeDir: Path) {
|
private class NodeData(val nodeDir: Path) {
|
||||||
val additionalNodeInfoDirectory: Path = nodeDir.resolve(CordformNode.NODE_INFO_DIRECTORY)
|
val additionalNodeInfoDirectory: Path = nodeDir.resolve(NODE_INFO_DIRECTORY)
|
||||||
// Map from Path to its lastModifiedTime.
|
// Map from Path to its lastModifiedTime.
|
||||||
val previouslySeenFiles = mutableMapOf<Path, FileTime>()
|
val previouslySeenFiles = mutableMapOf<Path, FileTime>()
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package net.corda.nodeapi.internal.network
|
package net.corda.nodeapi.internal.network
|
||||||
|
|
||||||
import com.typesafe.config.ConfigFactory
|
import com.typesafe.config.ConfigFactory
|
||||||
import net.corda.cordform.CordformNode.NODE_INFO_DIRECTORY
|
|
||||||
import net.corda.core.crypto.secureRandomBytes
|
import net.corda.core.crypto.secureRandomBytes
|
||||||
import net.corda.core.crypto.sha256
|
import net.corda.core.crypto.sha256
|
||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
@ -11,6 +10,7 @@ import net.corda.core.node.NodeInfo
|
|||||||
import net.corda.core.serialization.serialize
|
import net.corda.core.serialization.serialize
|
||||||
import net.corda.node.services.config.NotaryConfig
|
import net.corda.node.services.config.NotaryConfig
|
||||||
import net.corda.nodeapi.internal.DEV_ROOT_CA
|
import net.corda.nodeapi.internal.DEV_ROOT_CA
|
||||||
|
import net.corda.nodeapi.internal.NODE_INFO_DIRECTORY
|
||||||
import net.corda.nodeapi.internal.SignedNodeInfo
|
import net.corda.nodeapi.internal.SignedNodeInfo
|
||||||
import net.corda.nodeapi.internal.config.parseAs
|
import net.corda.nodeapi.internal.config.parseAs
|
||||||
import net.corda.nodeapi.internal.config.toConfig
|
import net.corda.nodeapi.internal.config.toConfig
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package net.corda.nodeapi.internal.network
|
package net.corda.nodeapi.internal.network
|
||||||
|
|
||||||
import net.corda.cordform.CordformNode
|
|
||||||
import net.corda.core.internal.div
|
import net.corda.core.internal.div
|
||||||
import net.corda.core.internal.list
|
import net.corda.core.internal.list
|
||||||
import net.corda.core.internal.write
|
import net.corda.core.internal.write
|
||||||
import net.corda.nodeapi.eventually
|
import net.corda.nodeapi.eventually
|
||||||
|
import net.corda.nodeapi.internal.NODE_INFO_DIRECTORY
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
@ -34,12 +34,12 @@ class NodeInfoFilesCopierTest {
|
|||||||
private val rootPath get() = folder.root.toPath()
|
private val rootPath get() = folder.root.toPath()
|
||||||
private val scheduler = TestScheduler()
|
private val scheduler = TestScheduler()
|
||||||
|
|
||||||
private fun nodeDir(nodeBaseDir : String) = rootPath.resolve(nodeBaseDir).resolve(ORGANIZATION.toLowerCase())
|
private fun nodeDir(nodeBaseDir: String) = rootPath.resolve(nodeBaseDir).resolve(ORGANIZATION.toLowerCase())
|
||||||
|
|
||||||
private val node1RootPath by lazy { nodeDir(NODE_1_PATH) }
|
private val node1RootPath by lazy { nodeDir(NODE_1_PATH) }
|
||||||
private val node2RootPath by lazy { nodeDir(NODE_2_PATH) }
|
private val node2RootPath by lazy { nodeDir(NODE_2_PATH) }
|
||||||
private val node1AdditionalNodeInfoPath by lazy { node1RootPath.resolve(CordformNode.NODE_INFO_DIRECTORY) }
|
private val node1AdditionalNodeInfoPath by lazy { node1RootPath.resolve(NODE_INFO_DIRECTORY) }
|
||||||
private val node2AdditionalNodeInfoPath by lazy { node2RootPath.resolve(CordformNode.NODE_INFO_DIRECTORY) }
|
private val node2AdditionalNodeInfoPath by lazy { node2RootPath.resolve(NODE_INFO_DIRECTORY) }
|
||||||
|
|
||||||
private lateinit var nodeInfoFilesCopier: NodeInfoFilesCopier
|
private lateinit var nodeInfoFilesCopier: NodeInfoFilesCopier
|
||||||
|
|
||||||
|
@ -71,7 +71,6 @@ dependencies {
|
|||||||
compile project(":confidential-identities")
|
compile project(":confidential-identities")
|
||||||
compile project(':client:rpc')
|
compile project(':client:rpc')
|
||||||
compile project(':tools:shell')
|
compile project(':tools:shell')
|
||||||
compile "net.corda.plugins:cordform-common:$gradle_plugins_version"
|
|
||||||
|
|
||||||
// Log4J: logging framework (with SLF4J bindings)
|
// Log4J: logging framework (with SLF4J bindings)
|
||||||
compile "org.apache.logging.log4j:log4j-slf4j-impl:${log4j_version}"
|
compile "org.apache.logging.log4j:log4j-slf4j-impl:${log4j_version}"
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package net.corda.node.services.network
|
package net.corda.node.services.network
|
||||||
|
|
||||||
import net.corda.cordform.CordformNode
|
|
||||||
import net.corda.core.concurrent.CordaFuture
|
import net.corda.core.concurrent.CordaFuture
|
||||||
import net.corda.core.crypto.random63BitValue
|
import net.corda.core.crypto.random63BitValue
|
||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
@ -12,6 +11,7 @@ import net.corda.core.serialization.serialize
|
|||||||
import net.corda.core.utilities.getOrThrow
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.core.utilities.seconds
|
import net.corda.core.utilities.seconds
|
||||||
import net.corda.node.services.config.configureDevKeyAndTrustStores
|
import net.corda.node.services.config.configureDevKeyAndTrustStores
|
||||||
|
import net.corda.nodeapi.internal.NODE_INFO_DIRECTORY
|
||||||
import net.corda.nodeapi.internal.config.NodeSSLConfiguration
|
import net.corda.nodeapi.internal.config.NodeSSLConfiguration
|
||||||
import net.corda.nodeapi.internal.network.NETWORK_PARAMS_FILE_NAME
|
import net.corda.nodeapi.internal.network.NETWORK_PARAMS_FILE_NAME
|
||||||
import net.corda.nodeapi.internal.network.NETWORK_PARAMS_UPDATE_FILE_NAME
|
import net.corda.nodeapi.internal.network.NETWORK_PARAMS_UPDATE_FILE_NAME
|
||||||
@ -235,7 +235,7 @@ class NetworkMapTest(var initFunc: (URL, NetworkMapServer) -> CompatibilityZoneP
|
|||||||
|
|
||||||
private fun NodeHandle.onlySees(vararg nodes: NodeInfo) {
|
private fun NodeHandle.onlySees(vararg nodes: NodeInfo) {
|
||||||
// Make sure the nodes aren't getting the node infos from their additional directories
|
// Make sure the nodes aren't getting the node infos from their additional directories
|
||||||
val nodeInfosDir = baseDirectory / CordformNode.NODE_INFO_DIRECTORY
|
val nodeInfosDir = baseDirectory / NODE_INFO_DIRECTORY
|
||||||
if (nodeInfosDir.exists()) {
|
if (nodeInfosDir.exists()) {
|
||||||
assertThat(nodeInfosDir.list()).isEmpty()
|
assertThat(nodeInfosDir.list()).isEmpty()
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package net.corda.node.services.network
|
package net.corda.node.services.network
|
||||||
|
|
||||||
import net.corda.cordform.CordformNode
|
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.internal.*
|
import net.corda.core.internal.*
|
||||||
import net.corda.core.node.NodeInfo
|
import net.corda.core.node.NodeInfo
|
||||||
@ -11,6 +10,7 @@ import net.corda.core.utilities.contextLogger
|
|||||||
import net.corda.core.utilities.debug
|
import net.corda.core.utilities.debug
|
||||||
import net.corda.core.utilities.seconds
|
import net.corda.core.utilities.seconds
|
||||||
import net.corda.node.serialization.amqp.AMQPServerSerializationScheme
|
import net.corda.node.serialization.amqp.AMQPServerSerializationScheme
|
||||||
|
import net.corda.nodeapi.internal.NODE_INFO_DIRECTORY
|
||||||
import net.corda.nodeapi.internal.NodeInfoAndSigned
|
import net.corda.nodeapi.internal.NodeInfoAndSigned
|
||||||
import net.corda.nodeapi.internal.SignedNodeInfo
|
import net.corda.nodeapi.internal.SignedNodeInfo
|
||||||
import net.corda.nodeapi.internal.network.NodeInfoFilesCopier
|
import net.corda.nodeapi.internal.network.NodeInfoFilesCopier
|
||||||
@ -64,7 +64,8 @@ class NodeInfoWatcher(private val nodePath: Path,
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal data class NodeInfoFromFile(val nodeInfohash: SecureHash, val lastModified: FileTime)
|
internal data class NodeInfoFromFile(val nodeInfohash: SecureHash, val lastModified: FileTime)
|
||||||
private val nodeInfosDir = nodePath / CordformNode.NODE_INFO_DIRECTORY
|
|
||||||
|
private val nodeInfosDir = nodePath / NODE_INFO_DIRECTORY
|
||||||
private val nodeInfoFilesMap = HashMap<Path, NodeInfoFromFile>()
|
private val nodeInfoFilesMap = HashMap<Path, NodeInfoFromFile>()
|
||||||
val processedNodeInfoHashes: Set<SecureHash> get() = nodeInfoFilesMap.values.map { it.nodeInfohash }.toSet()
|
val processedNodeInfoHashes: Set<SecureHash> get() = nodeInfoFilesMap.values.map { it.nodeInfohash }.toSet()
|
||||||
|
|
||||||
@ -74,7 +75,7 @@ class NodeInfoWatcher(private val nodePath: Path,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read all the files contained in [nodePath] / [CordformNode.NODE_INFO_DIRECTORY] and keep watching
|
* Read all the files contained in [nodePath] / [NODE_INFO_DIRECTORY] and keep watching
|
||||||
* the folder for further updates.
|
* the folder for further updates.
|
||||||
*
|
*
|
||||||
* We simply list the directory content every 5 seconds, the Java implementation of WatchService has been proven to
|
* We simply list the directory content every 5 seconds, the Java implementation of WatchService has been proven to
|
||||||
|
@ -3,7 +3,6 @@ package net.corda.node.services.network
|
|||||||
import com.google.common.jimfs.Configuration.unix
|
import com.google.common.jimfs.Configuration.unix
|
||||||
import com.google.common.jimfs.Jimfs
|
import com.google.common.jimfs.Jimfs
|
||||||
import com.nhaarman.mockito_kotlin.*
|
import com.nhaarman.mockito_kotlin.*
|
||||||
import net.corda.cordform.CordformNode.NODE_INFO_DIRECTORY
|
|
||||||
import net.corda.core.crypto.Crypto
|
import net.corda.core.crypto.Crypto
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.crypto.sign
|
import net.corda.core.crypto.sign
|
||||||
@ -15,6 +14,7 @@ import net.corda.core.node.NodeInfo
|
|||||||
import net.corda.core.serialization.serialize
|
import net.corda.core.serialization.serialize
|
||||||
import net.corda.core.utilities.millis
|
import net.corda.core.utilities.millis
|
||||||
import net.corda.node.services.api.NetworkMapCacheInternal
|
import net.corda.node.services.api.NetworkMapCacheInternal
|
||||||
|
import net.corda.nodeapi.internal.NODE_INFO_DIRECTORY
|
||||||
import net.corda.nodeapi.internal.NodeInfoAndSigned
|
import net.corda.nodeapi.internal.NodeInfoAndSigned
|
||||||
import net.corda.nodeapi.internal.network.NETWORK_PARAMS_UPDATE_FILE_NAME
|
import net.corda.nodeapi.internal.network.NETWORK_PARAMS_UPDATE_FILE_NAME
|
||||||
import net.corda.nodeapi.internal.network.NodeInfoFilesCopier
|
import net.corda.nodeapi.internal.network.NodeInfoFilesCopier
|
||||||
|
@ -2,11 +2,11 @@ package net.corda.node.services.network
|
|||||||
|
|
||||||
import com.google.common.jimfs.Configuration
|
import com.google.common.jimfs.Configuration
|
||||||
import com.google.common.jimfs.Jimfs
|
import com.google.common.jimfs.Jimfs
|
||||||
import net.corda.cordform.CordformNode
|
|
||||||
import net.corda.core.internal.createDirectories
|
import net.corda.core.internal.createDirectories
|
||||||
import net.corda.core.internal.div
|
import net.corda.core.internal.div
|
||||||
import net.corda.core.internal.size
|
import net.corda.core.internal.size
|
||||||
import net.corda.core.node.services.KeyManagementService
|
import net.corda.core.node.services.KeyManagementService
|
||||||
|
import net.corda.nodeapi.internal.NODE_INFO_DIRECTORY
|
||||||
import net.corda.nodeapi.internal.NodeInfoAndSigned
|
import net.corda.nodeapi.internal.NodeInfoAndSigned
|
||||||
import net.corda.nodeapi.internal.network.NodeInfoFilesCopier
|
import net.corda.nodeapi.internal.network.NodeInfoFilesCopier
|
||||||
import net.corda.testing.core.ALICE_NAME
|
import net.corda.testing.core.ALICE_NAME
|
||||||
@ -51,7 +51,7 @@ class NodeInfoWatcherTest {
|
|||||||
val identityService = makeTestIdentityService()
|
val identityService = makeTestIdentityService()
|
||||||
keyManagementService = MockKeyManagementService(identityService)
|
keyManagementService = MockKeyManagementService(identityService)
|
||||||
nodeInfoWatcher = NodeInfoWatcher(tempFolder.root.toPath(), scheduler)
|
nodeInfoWatcher = NodeInfoWatcher(tempFolder.root.toPath(), scheduler)
|
||||||
nodeInfoPath = tempFolder.root.toPath() / CordformNode.NODE_INFO_DIRECTORY
|
nodeInfoPath = tempFolder.root.toPath() / NODE_INFO_DIRECTORY
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -7,21 +7,6 @@ apply plugin: 'net.corda.plugins.cordapp'
|
|||||||
apply plugin: 'net.corda.plugins.cordformation'
|
apply plugin: 'net.corda.plugins.cordformation'
|
||||||
apply plugin: 'maven-publish'
|
apply plugin: 'maven-publish'
|
||||||
|
|
||||||
sourceSets {
|
|
||||||
integrationTest {
|
|
||||||
kotlin {
|
|
||||||
compileClasspath += main.output + test.output
|
|
||||||
runtimeClasspath += main.output + test.output
|
|
||||||
srcDir file('src/integration-test/kotlin')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
configurations {
|
|
||||||
integrationTestCompile.extendsFrom testCompile
|
|
||||||
integrationTestRuntime.extendsFrom testRuntime
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||||
|
|
||||||
@ -48,13 +33,46 @@ dependencies {
|
|||||||
}
|
}
|
||||||
|
|
||||||
task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
||||||
// CordformationDefinition is an experimental feature
|
nodeDefaults {
|
||||||
definitionClass = 'net.corda.bank.BankOfCordaCordform'
|
cordapp project(':finance')
|
||||||
}
|
}
|
||||||
|
node {
|
||||||
task integrationTest(type: Test, dependsOn: []) {
|
name "O=Notary Service,L=Zurich,C=CH"
|
||||||
testClassesDirs = sourceSets.integrationTest.output.classesDirs
|
notary = [validating: true]
|
||||||
classpath = sourceSets.integrationTest.runtimeClasspath
|
p2pPort 10002
|
||||||
|
rpcSettings {
|
||||||
|
address "localhost:10003"
|
||||||
|
adminAddress "localhost:10004"
|
||||||
|
}
|
||||||
|
extraConfig = [h2Settings: [address: "localhost:10016"]]
|
||||||
|
}
|
||||||
|
node {
|
||||||
|
name "O=BankOfCorda,L=London,C=GB"
|
||||||
|
p2pPort 10005
|
||||||
|
rpcSettings {
|
||||||
|
address "localhost:10006"
|
||||||
|
adminAddress "localhost:10015"
|
||||||
|
}
|
||||||
|
webPort 10007
|
||||||
|
rpcUsers = [[user: "bankUser", password: "test", permissions: ["ALL"]]]
|
||||||
|
extraConfig = [
|
||||||
|
custom : [issuableCurrencies: ["USD"]],
|
||||||
|
h2Settings: [address: "localhost:10017"]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
node {
|
||||||
|
name "O=BigCorporation,L=New York,C=US"
|
||||||
|
p2pPort 10008
|
||||||
|
rpcSettings {
|
||||||
|
address "localhost:10009"
|
||||||
|
adminAddress "localhost:10011"
|
||||||
|
}
|
||||||
|
webPort 10010
|
||||||
|
rpcUsers = [[user: "bigCorpUser", password: "test", permissions: ["ALL"]]]
|
||||||
|
extraConfig = [
|
||||||
|
h2Settings: [address: "localhost:10018"]
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
idea {
|
idea {
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
package net.corda.bank
|
|
||||||
|
|
||||||
import net.corda.client.rpc.CordaRPCClient
|
|
||||||
import net.corda.core.contracts.withoutIssuer
|
|
||||||
import net.corda.core.utilities.NetworkHostAndPort
|
|
||||||
import net.corda.finance.DOLLARS
|
|
||||||
import net.corda.finance.contracts.asset.Cash
|
|
||||||
import net.corda.finance.utils.sumCash
|
|
||||||
import net.corda.testing.core.BOC_NAME
|
|
||||||
import net.corda.testing.node.internal.demorun.nodeRunner
|
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
|
||||||
import org.junit.Test
|
|
||||||
|
|
||||||
class BankOfCordaCordformTest {
|
|
||||||
@Test
|
|
||||||
fun `run demo`() {
|
|
||||||
BankOfCordaCordform().nodeRunner().scanPackages(listOf("net.corda.finance")).deployAndRunNodesAndThen {
|
|
||||||
IssueCash.requestRpcIssue(20000.DOLLARS)
|
|
||||||
CordaRPCClient(NetworkHostAndPort("localhost", BOC_RPC_PORT)).use(BOC_RPC_USER, BOC_RPC_PWD) {
|
|
||||||
assertThat(it.proxy.vaultQuery(Cash.State::class.java).states).isEmpty() // All of the issued cash is transferred
|
|
||||||
}
|
|
||||||
CordaRPCClient(NetworkHostAndPort("localhost", BIGCORP_RPC_PORT)).use(BIGCORP_RPC_USER, BIGCORP_RPC_PWD) {
|
|
||||||
val cashStates = it.proxy.vaultQuery(Cash.State::class.java).states.map { it.state.data }
|
|
||||||
val knownOwner = it.proxy.wellKnownPartyFromAnonymous(cashStates.map { it.owner }.toSet().single())
|
|
||||||
assertThat(knownOwner?.name).isEqualTo(BIGCORP_NAME)
|
|
||||||
val totalCash = cashStates.sumCash()
|
|
||||||
assertThat(totalCash.token.issuer.party.nameOrNull()).isEqualTo(BOC_NAME)
|
|
||||||
assertThat(totalCash.withoutIssuer()).isEqualTo(20000.DOLLARS)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,149 +0,0 @@
|
|||||||
package net.corda.bank
|
|
||||||
|
|
||||||
import joptsimple.OptionParser
|
|
||||||
import net.corda.bank.api.BankOfCordaClientApi
|
|
||||||
import net.corda.bank.api.BankOfCordaWebApi.IssueRequestParams
|
|
||||||
import net.corda.cordform.CordappDependency
|
|
||||||
import net.corda.cordform.CordformContext
|
|
||||||
import net.corda.cordform.CordformDefinition
|
|
||||||
import net.corda.core.contracts.Amount
|
|
||||||
import net.corda.core.identity.CordaX500Name
|
|
||||||
import net.corda.core.internal.VisibleForTesting
|
|
||||||
import net.corda.core.transactions.SignedTransaction
|
|
||||||
import net.corda.core.utilities.NetworkHostAndPort
|
|
||||||
import net.corda.node.services.Permissions.Companion.all
|
|
||||||
import net.corda.node.services.config.NotaryConfig
|
|
||||||
import net.corda.testing.node.internal.demorun.*
|
|
||||||
import net.corda.testing.core.BOC_NAME
|
|
||||||
import net.corda.testing.node.User
|
|
||||||
import java.util.*
|
|
||||||
import kotlin.system.exitProcess
|
|
||||||
|
|
||||||
val BIGCORP_NAME = CordaX500Name(organisation = "BigCorporation", locality = "New York", country = "US")
|
|
||||||
private val NOTARY_NAME = CordaX500Name(organisation = "Notary Service", locality = "Zurich", country = "CH")
|
|
||||||
const val BOC_RPC_PORT = 10006
|
|
||||||
const val BIGCORP_RPC_PORT = 10009
|
|
||||||
private const val BOC_RPC_ADMIN_PORT = 10015
|
|
||||||
private const val BOC_WEB_PORT = 10007
|
|
||||||
|
|
||||||
const val BOC_RPC_USER = "bankUser"
|
|
||||||
const val BOC_RPC_PWD = "test"
|
|
||||||
|
|
||||||
const val BIGCORP_RPC_USER = "bigCorpUser"
|
|
||||||
const val BIGCORP_RPC_PWD = "test"
|
|
||||||
|
|
||||||
class BankOfCordaCordform : CordformDefinition() {
|
|
||||||
|
|
||||||
init {
|
|
||||||
node {
|
|
||||||
name(NOTARY_NAME)
|
|
||||||
notary(NotaryConfig(validating = true))
|
|
||||||
p2pPort(10002)
|
|
||||||
rpcSettings {
|
|
||||||
address("localhost:10003")
|
|
||||||
adminAddress("localhost:10004")
|
|
||||||
}
|
|
||||||
devMode(true)
|
|
||||||
extraConfig = mapOf("h2Settings" to mapOf("address" to "localhost:10016"))
|
|
||||||
}
|
|
||||||
node {
|
|
||||||
name(BOC_NAME)
|
|
||||||
extraConfig = mapOf("custom" to mapOf("issuableCurrencies" to listOf("USD")),
|
|
||||||
"h2Settings" to mapOf("address" to "localhost:10017"))
|
|
||||||
p2pPort(10005)
|
|
||||||
rpcSettings {
|
|
||||||
address("localhost:$BOC_RPC_PORT")
|
|
||||||
adminAddress("localhost:$BOC_RPC_ADMIN_PORT")
|
|
||||||
}
|
|
||||||
webPort(BOC_WEB_PORT)
|
|
||||||
rpcUsers(User(BOC_RPC_USER, BOC_RPC_PWD, setOf(all())))
|
|
||||||
devMode(true)
|
|
||||||
}
|
|
||||||
node {
|
|
||||||
name(BIGCORP_NAME)
|
|
||||||
p2pPort(10008)
|
|
||||||
rpcSettings {
|
|
||||||
address("localhost:$BIGCORP_RPC_PORT")
|
|
||||||
adminAddress("localhost:10011")
|
|
||||||
}
|
|
||||||
webPort(10010)
|
|
||||||
rpcUsers(User(BIGCORP_RPC_USER, BIGCORP_RPC_PWD, setOf(all())))
|
|
||||||
devMode(true)
|
|
||||||
extraConfig = mapOf("h2Settings" to mapOf("address" to "localhost:10018"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setup(context: CordformContext) = Unit
|
|
||||||
|
|
||||||
override fun getCordappDependencies(): List<CordappDependency> {
|
|
||||||
return listOf(CordappDependency(":finance"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object DeployNodes {
|
|
||||||
@JvmStatic
|
|
||||||
fun main(args: Array<String>) {
|
|
||||||
BankOfCordaCordform().nodeRunner().scanPackages(listOf("net.corda.finance")).deployAndRunNodes()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object IssueCash {
|
|
||||||
@JvmStatic
|
|
||||||
fun main(args: Array<String>) {
|
|
||||||
val parser = OptionParser()
|
|
||||||
val roleArg = parser.accepts("role").withRequiredArg().ofType(Role::class.java).describedAs("[ISSUER|ISSUE_CASH_RPC|ISSUE_CASH_WEB]")
|
|
||||||
val quantity = parser.accepts("quantity").withOptionalArg().ofType(Long::class.java)
|
|
||||||
val currency = parser.accepts("currency").withOptionalArg().ofType(String::class.java).describedAs("[GBP|USD|CHF|EUR]")
|
|
||||||
val options = try {
|
|
||||||
parser.parse(*args)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
println(e.message)
|
|
||||||
printHelp(parser)
|
|
||||||
exitProcess(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
val role = options.valueOf(roleArg)!!
|
|
||||||
val amount = Amount(options.valueOf(quantity), Currency.getInstance(options.valueOf(currency)))
|
|
||||||
when (role) {
|
|
||||||
Role.ISSUE_CASH_RPC -> {
|
|
||||||
println("Requesting Cash via RPC ...")
|
|
||||||
val result = requestRpcIssue(amount)
|
|
||||||
println("Success!! Your transaction receipt is ${result.tx.id}")
|
|
||||||
}
|
|
||||||
Role.ISSUE_CASH_WEB -> {
|
|
||||||
println("Requesting Cash via Web ...")
|
|
||||||
requestWebIssue(amount)
|
|
||||||
println("Successfully processed Cash Issue request")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
fun requestRpcIssue(amount: Amount<Currency>): SignedTransaction {
|
|
||||||
return BankOfCordaClientApi.requestRPCIssue(NetworkHostAndPort("localhost", BOC_RPC_PORT), createParams(amount, NOTARY_NAME))
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun requestWebIssue(amount: Amount<Currency>) {
|
|
||||||
BankOfCordaClientApi.requestWebIssue(NetworkHostAndPort("localhost", BOC_WEB_PORT), createParams(amount, NOTARY_NAME))
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createParams(amount: Amount<Currency>, notaryName: CordaX500Name): IssueRequestParams {
|
|
||||||
return IssueRequestParams(amount, BIGCORP_NAME, "1", BOC_NAME, notaryName)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun printHelp(parser: OptionParser) {
|
|
||||||
println("""
|
|
||||||
Usage: bank-of-corda --role ISSUER
|
|
||||||
bank-of-corda --role (ISSUE_CASH_RPC|ISSUE_CASH_WEB) --quantity <quantity> --currency <currency>
|
|
||||||
|
|
||||||
Please refer to the documentation in docs/build/index.html for more info.
|
|
||||||
|
|
||||||
""".trimIndent())
|
|
||||||
parser.printHelpOn(System.out)
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class Role {
|
|
||||||
ISSUE_CASH_RPC,
|
|
||||||
ISSUE_CASH_WEB,
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,77 @@
|
|||||||
|
package net.corda.bank
|
||||||
|
|
||||||
|
import joptsimple.OptionParser
|
||||||
|
import net.corda.bank.api.BankOfCordaClientApi
|
||||||
|
import net.corda.bank.api.BankOfCordaWebApi
|
||||||
|
import net.corda.core.contracts.Amount
|
||||||
|
import net.corda.core.identity.CordaX500Name
|
||||||
|
import net.corda.core.internal.VisibleForTesting
|
||||||
|
import net.corda.core.transactions.SignedTransaction
|
||||||
|
import net.corda.core.utilities.NetworkHostAndPort
|
||||||
|
import net.corda.testing.core.BOC_NAME
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
|
object IssueCash {
|
||||||
|
private val NOTARY_NAME = CordaX500Name(organisation = "Notary Service", locality = "Zurich", country = "CH")
|
||||||
|
private val BIGCORP_NAME = CordaX500Name(organisation = "BigCorporation", locality = "New York", country = "US")
|
||||||
|
private const val BOC_RPC_PORT = 10006
|
||||||
|
private const val BOC_WEB_PORT = 10007
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
val parser = OptionParser()
|
||||||
|
val roleArg = parser.accepts("role").withRequiredArg().ofType(Role::class.java).describedAs("[ISSUER|ISSUE_CASH_RPC|ISSUE_CASH_WEB]")
|
||||||
|
val quantity = parser.accepts("quantity").withOptionalArg().ofType(Long::class.java)
|
||||||
|
val currency = parser.accepts("currency").withOptionalArg().ofType(String::class.java).describedAs("[GBP|USD|CHF|EUR]")
|
||||||
|
val options = try {
|
||||||
|
parser.parse(*args)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
println(e.message)
|
||||||
|
printHelp(parser)
|
||||||
|
exitProcess(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
val role = options.valueOf(roleArg)!!
|
||||||
|
val amount = Amount(options.valueOf(quantity), Currency.getInstance(options.valueOf(currency)))
|
||||||
|
when (role) {
|
||||||
|
Role.ISSUE_CASH_RPC -> {
|
||||||
|
println("Requesting Cash via RPC ...")
|
||||||
|
val result = requestRpcIssue(amount)
|
||||||
|
println("Success!! Your transaction receipt is ${result.tx.id}")
|
||||||
|
}
|
||||||
|
Role.ISSUE_CASH_WEB -> {
|
||||||
|
println("Requesting Cash via Web ...")
|
||||||
|
requestWebIssue(amount)
|
||||||
|
println("Successfully processed Cash Issue request")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
fun requestRpcIssue(amount: Amount<Currency>): SignedTransaction {
|
||||||
|
return BankOfCordaClientApi.requestRPCIssue(NetworkHostAndPort("localhost", BOC_RPC_PORT), createParams(amount, NOTARY_NAME))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun requestWebIssue(amount: Amount<Currency>) {
|
||||||
|
BankOfCordaClientApi.requestWebIssue(NetworkHostAndPort("localhost", BOC_WEB_PORT), createParams(amount, NOTARY_NAME))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createParams(amount: Amount<Currency>, notaryName: CordaX500Name): BankOfCordaWebApi.IssueRequestParams {
|
||||||
|
return BankOfCordaWebApi.IssueRequestParams(amount, BIGCORP_NAME, "1", BOC_NAME, notaryName)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun printHelp(parser: OptionParser) {
|
||||||
|
println("""
|
||||||
|
Usage: bank-of-corda --role ISSUER
|
||||||
|
bank-of-corda --role (ISSUE_CASH_RPC|ISSUE_CASH_WEB) --quantity <quantity> --currency <currency>
|
||||||
|
Please refer to the documentation in docs/build/index.html for more info.
|
||||||
|
""".trimIndent())
|
||||||
|
parser.printHelpOn(System.out)
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class Role {
|
||||||
|
ISSUE_CASH_RPC,
|
||||||
|
ISSUE_CASH_WEB,
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,5 @@
|
|||||||
package net.corda.bank.api
|
package net.corda.bank.api
|
||||||
|
|
||||||
import net.corda.bank.BOC_RPC_PWD
|
|
||||||
import net.corda.bank.BOC_RPC_USER
|
|
||||||
import net.corda.bank.api.BankOfCordaWebApi.IssueRequestParams
|
import net.corda.bank.api.BankOfCordaWebApi.IssueRequestParams
|
||||||
import net.corda.client.rpc.CordaRPCClient
|
import net.corda.client.rpc.CordaRPCClient
|
||||||
import net.corda.core.messaging.startFlow
|
import net.corda.core.messaging.startFlow
|
||||||
@ -16,6 +14,9 @@ import net.corda.testing.http.HttpApi
|
|||||||
* Interface for communicating with Bank of Corda node
|
* Interface for communicating with Bank of Corda node
|
||||||
*/
|
*/
|
||||||
object BankOfCordaClientApi {
|
object BankOfCordaClientApi {
|
||||||
|
const val BOC_RPC_USER = "bankUser"
|
||||||
|
const val BOC_RPC_PWD = "test"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HTTP API
|
* HTTP API
|
||||||
*/
|
*/
|
||||||
@ -40,7 +41,8 @@ object BankOfCordaClientApi {
|
|||||||
// Resolve parties via RPC
|
// Resolve parties via RPC
|
||||||
val issueToParty = rpc.wellKnownPartyFromX500Name(params.issueToPartyName)
|
val issueToParty = rpc.wellKnownPartyFromX500Name(params.issueToPartyName)
|
||||||
?: throw IllegalStateException("Unable to locate ${params.issueToPartyName} in Network Map Service")
|
?: throw IllegalStateException("Unable to locate ${params.issueToPartyName} in Network Map Service")
|
||||||
val notaryLegalIdentity = rpc.notaryIdentities().firstOrNull { it.name == params.notaryName } ?: throw IllegalStateException("Couldn't locate notary ${params.notaryName} in NetworkMapCache")
|
val notaryLegalIdentity = rpc.notaryIdentities().firstOrNull { it.name == params.notaryName }
|
||||||
|
?: throw IllegalStateException("Couldn't locate notary ${params.notaryName} in NetworkMapCache")
|
||||||
|
|
||||||
val anonymous = true
|
val anonymous = true
|
||||||
val issuerBankPartyRef = OpaqueBytes.of(params.issuerBankPartyRef.toByte())
|
val issuerBankPartyRef = OpaqueBytes.of(params.issuerBankPartyRef.toByte())
|
||||||
|
@ -49,19 +49,229 @@ publishing {
|
|||||||
task deployNodes(dependsOn: ['deployNodesSingle', 'deployNodesRaft', 'deployNodesBFT', 'deployNodesCustom'])
|
task deployNodes(dependsOn: ['deployNodesSingle', 'deployNodesRaft', 'deployNodesBFT', 'deployNodesCustom'])
|
||||||
|
|
||||||
task deployNodesSingle(type: Cordform, dependsOn: 'jar') {
|
task deployNodesSingle(type: Cordform, dependsOn: 'jar') {
|
||||||
definitionClass = 'net.corda.notarydemo.SingleNotaryCordform'
|
directory file("$buildDir/nodes/nodesSingle")
|
||||||
|
nodeDefaults {
|
||||||
|
extraConfig = [h2Settings: [address: "localhost:0"]]
|
||||||
|
}
|
||||||
|
node {
|
||||||
|
name "O=Alice Corp,L=Madrid,C=ES"
|
||||||
|
p2pPort 10002
|
||||||
|
rpcSettings {
|
||||||
|
address "localhost:10003"
|
||||||
|
adminAddress "localhost:10103"
|
||||||
|
}
|
||||||
|
rpcUsers = [[user: "demou", password: "demop", permissions: ["ALL"]]]
|
||||||
|
}
|
||||||
|
node {
|
||||||
|
name "O=Bob Plc,L=Rome,C=IT"
|
||||||
|
p2pPort 10005
|
||||||
|
rpcSettings {
|
||||||
|
address "localhost:10006"
|
||||||
|
adminAddress "localhost:10106"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node {
|
||||||
|
name "O=Notary Service,L=Zurich,C=CH"
|
||||||
|
p2pPort 10009
|
||||||
|
rpcSettings {
|
||||||
|
address "localhost:10010"
|
||||||
|
adminAddress "localhost:10110"
|
||||||
|
}
|
||||||
|
notary = [validating: true]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
task deployNodesCustom(type: Cordform, dependsOn: 'jar') {
|
task deployNodesCustom(type: Cordform, dependsOn: 'jar') {
|
||||||
definitionClass = 'net.corda.notarydemo.CustomNotaryCordform'
|
directory file("$buildDir/nodes/nodesCustom")
|
||||||
|
nodeDefaults {
|
||||||
|
extraConfig = [h2Settings: [address: "localhost:0"]]
|
||||||
|
}
|
||||||
|
node {
|
||||||
|
name "O=Alice Corp,L=Madrid,C=ES"
|
||||||
|
p2pPort 10002
|
||||||
|
rpcSettings {
|
||||||
|
address "localhost:10003"
|
||||||
|
adminAddress "localhost:10103"
|
||||||
|
}
|
||||||
|
rpcUsers = [[user: "demou", password: "demop", permissions: ["ALL"]]]
|
||||||
|
}
|
||||||
|
node {
|
||||||
|
name "O=Bob Plc,L=Rome,C=IT"
|
||||||
|
p2pPort 10005
|
||||||
|
rpcSettings {
|
||||||
|
address "localhost:10006"
|
||||||
|
adminAddress "localhost:10106"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node {
|
||||||
|
name "O=Notary Service,L=Zurich,C=CH"
|
||||||
|
p2pPort 10009
|
||||||
|
rpcSettings {
|
||||||
|
address "localhost:10010"
|
||||||
|
adminAddress "localhost:10110"
|
||||||
|
}
|
||||||
|
notary = [validating: true, "custom": true]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
task deployNodesRaft(type: Cordform, dependsOn: 'jar') {
|
task deployNodesRaft(type: Cordform, dependsOn: 'jar') {
|
||||||
definitionClass = 'net.corda.notarydemo.RaftNotaryCordform'
|
directory file("$buildDir/nodes/nodesRaft")
|
||||||
|
nodeDefaults {
|
||||||
|
extraConfig = [h2Settings: [address: "localhost:0"]]
|
||||||
|
}
|
||||||
|
node {
|
||||||
|
name "O=Alice Corp,L=Madrid,C=ES"
|
||||||
|
p2pPort 10002
|
||||||
|
rpcSettings {
|
||||||
|
address "localhost:10003"
|
||||||
|
adminAddress "localhost:10103"
|
||||||
|
}
|
||||||
|
rpcUsers = [[user: "demou", password: "demop", permissions: ["ALL"]]]
|
||||||
|
}
|
||||||
|
node {
|
||||||
|
name "O=Bob Plc,L=Rome,C=IT"
|
||||||
|
p2pPort 10005
|
||||||
|
rpcSettings {
|
||||||
|
address "localhost:10006"
|
||||||
|
adminAddress "localhost:10106"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node {
|
||||||
|
name "O=Notary Service 0,L=Zurich,C=CH"
|
||||||
|
p2pPort 10009
|
||||||
|
rpcSettings {
|
||||||
|
address "localhost:10010"
|
||||||
|
adminAddress "localhost:10110"
|
||||||
|
}
|
||||||
|
notary = [
|
||||||
|
validating: true,
|
||||||
|
serviceLegalName: "O=Raft,L=Zurich,C=CH",
|
||||||
|
raft: [
|
||||||
|
nodeAddress: "localhost:10008"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
node {
|
||||||
|
name "O=Notary Service 1,L=Zurich,C=CH"
|
||||||
|
p2pPort 10013
|
||||||
|
rpcSettings {
|
||||||
|
address "localhost:10014"
|
||||||
|
adminAddress "localhost:10114"
|
||||||
|
}
|
||||||
|
notary = [
|
||||||
|
validating: true,
|
||||||
|
serviceLegalName: "O=Raft,L=Zurich,C=CH",
|
||||||
|
raft: [
|
||||||
|
nodeAddress: "localhost:10012",
|
||||||
|
clusterAddresses: ["localhost:10008"]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
node {
|
||||||
|
name "O=Notary Service 2,L=Zurich,C=CH"
|
||||||
|
p2pPort 10017
|
||||||
|
rpcSettings {
|
||||||
|
address "localhost:10018"
|
||||||
|
adminAddress "localhost:10118"
|
||||||
|
}
|
||||||
|
notary = [
|
||||||
|
validating: true,
|
||||||
|
serviceLegalName: "O=Raft,L=Zurich,C=CH",
|
||||||
|
raft: [
|
||||||
|
nodeAddress: "localhost:10016",
|
||||||
|
clusterAddresses: ["localhost:10008"]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
task deployNodesBFT(type: Cordform, dependsOn: 'jar') {
|
task deployNodesBFT(type: Cordform, dependsOn: 'jar') {
|
||||||
definitionClass = 'net.corda.notarydemo.BFTNotaryCordform'
|
def clusterAddresses = ["localhost:11000", "localhost:11010", "localhost:11020", "localhost:11030"]
|
||||||
|
directory file("$buildDir/nodes/nodesBFT")
|
||||||
|
nodeDefaults {
|
||||||
|
extraConfig = [h2Settings: [address: "localhost:0"]]
|
||||||
|
}
|
||||||
|
node {
|
||||||
|
name "O=Alice Corp,L=Madrid,C=ES"
|
||||||
|
p2pPort 10002
|
||||||
|
rpcSettings {
|
||||||
|
address "localhost:10003"
|
||||||
|
adminAddress "localhost:10103"
|
||||||
|
}
|
||||||
|
rpcUsers = [[user: "demou", password: "demop", permissions: ["ALL"]]]
|
||||||
|
}
|
||||||
|
node {
|
||||||
|
name "O=Bob Plc,L=Rome,C=IT"
|
||||||
|
p2pPort 10005
|
||||||
|
rpcSettings {
|
||||||
|
address "localhost:10006"
|
||||||
|
adminAddress "localhost:10106"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node {
|
||||||
|
name "O=Notary Service 0,L=Zurich,C=CH"
|
||||||
|
p2pPort 10009
|
||||||
|
rpcSettings {
|
||||||
|
address "localhost:10010"
|
||||||
|
adminAddress "localhost:10110"
|
||||||
|
}
|
||||||
|
notary = [
|
||||||
|
validating: false,
|
||||||
|
serviceLegalName: "O=BFT,L=Zurich,C=CH",
|
||||||
|
bftSMaRt: [
|
||||||
|
replicaId: 0,
|
||||||
|
clusterAddresses: clusterAddresses
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
node {
|
||||||
|
name "O=Notary Service 1,L=Zurich,C=CH"
|
||||||
|
p2pPort 10013
|
||||||
|
rpcSettings {
|
||||||
|
address "localhost:10014"
|
||||||
|
adminAddress "localhost:10114"
|
||||||
|
}
|
||||||
|
notary = [
|
||||||
|
validating: false,
|
||||||
|
serviceLegalName: "O=BFT,L=Zurich,C=CH",
|
||||||
|
bftSMaRt: [
|
||||||
|
replicaId: 0,
|
||||||
|
clusterAddresses: clusterAddresses
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
node {
|
||||||
|
name "O=Notary Service 2,L=Zurich,C=CH"
|
||||||
|
p2pPort 10017
|
||||||
|
rpcSettings {
|
||||||
|
address "localhost:10018"
|
||||||
|
adminAddress "localhost:10118"
|
||||||
|
}
|
||||||
|
notary = [
|
||||||
|
validating: false,
|
||||||
|
serviceLegalName: "O=BFT,L=Zurich,C=CH",
|
||||||
|
bftSMaRt: [
|
||||||
|
replicaId: 0,
|
||||||
|
clusterAddresses: clusterAddresses
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
node {
|
||||||
|
name "O=Notary Service 3,L=Zurich,C=CH"
|
||||||
|
p2pPort 10021
|
||||||
|
rpcSettings {
|
||||||
|
address "localhost:10022"
|
||||||
|
adminAddress "localhost:10122"
|
||||||
|
}
|
||||||
|
notary = [
|
||||||
|
validating: false,
|
||||||
|
serviceLegalName: "O=BFT,L=Zurich,C=CH",
|
||||||
|
bftSMaRt: [
|
||||||
|
replicaId: 0,
|
||||||
|
clusterAddresses: clusterAddresses
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
task notarise(type: JavaExec) {
|
task notarise(type: JavaExec) {
|
||||||
|
@ -1,93 +0,0 @@
|
|||||||
package net.corda.notarydemo
|
|
||||||
|
|
||||||
import net.corda.cordform.CordformContext
|
|
||||||
import net.corda.cordform.CordformDefinition
|
|
||||||
import net.corda.cordform.CordformNode
|
|
||||||
import net.corda.core.identity.CordaX500Name
|
|
||||||
import net.corda.core.utilities.NetworkHostAndPort
|
|
||||||
import net.corda.node.services.config.BFTSMaRtConfiguration
|
|
||||||
import net.corda.node.services.config.NotaryConfig
|
|
||||||
import net.corda.node.services.transactions.minCorrectReplicas
|
|
||||||
import net.corda.nodeapi.internal.DevIdentityGenerator
|
|
||||||
import net.corda.testing.node.internal.demorun.*
|
|
||||||
import net.corda.testing.core.ALICE_NAME
|
|
||||||
import net.corda.testing.core.BOB_NAME
|
|
||||||
import java.nio.file.Paths
|
|
||||||
|
|
||||||
fun main(args: Array<String>) = BFTNotaryCordform().nodeRunner().deployAndRunNodes()
|
|
||||||
|
|
||||||
private const val clusterSize = 4 // Minimum size that tolerates a faulty replica.
|
|
||||||
private val notaryNames = createNotaryNames(clusterSize)
|
|
||||||
|
|
||||||
// This is not the intended final design for how to use CordformDefinition, please treat this as experimental and DO
|
|
||||||
// NOT use this as a design to copy.
|
|
||||||
class BFTNotaryCordform : CordformDefinition() {
|
|
||||||
private val clusterName = CordaX500Name("BFT", "Zurich", "CH")
|
|
||||||
|
|
||||||
init {
|
|
||||||
nodesDirectory = Paths.get("build", "nodes", "nodesBFT")
|
|
||||||
node {
|
|
||||||
name(ALICE_NAME)
|
|
||||||
p2pPort(10002)
|
|
||||||
rpcSettings {
|
|
||||||
address("localhost:10003")
|
|
||||||
adminAddress("localhost:10103")
|
|
||||||
}
|
|
||||||
rpcUsers(notaryDemoUser)
|
|
||||||
devMode(true)
|
|
||||||
extraConfig = mapOf("h2Settings" to mapOf("address" to "localhost:0"))
|
|
||||||
}
|
|
||||||
node {
|
|
||||||
name(BOB_NAME)
|
|
||||||
p2pPort(10005)
|
|
||||||
rpcSettings {
|
|
||||||
address("localhost:10006")
|
|
||||||
adminAddress("localhost:10106")
|
|
||||||
}
|
|
||||||
devMode(true)
|
|
||||||
extraConfig = mapOf("h2Settings" to mapOf("address" to "localhost:0"))
|
|
||||||
}
|
|
||||||
val clusterAddresses = (0 until clusterSize).map { NetworkHostAndPort("localhost", 11000 + it * 10) }
|
|
||||||
fun notaryNode(replicaId: Int, configure: CordformNode.() -> Unit) = node {
|
|
||||||
name(notaryNames[replicaId])
|
|
||||||
notary(NotaryConfig(validating = false, serviceLegalName = clusterName, bftSMaRt = BFTSMaRtConfiguration(replicaId, clusterAddresses)))
|
|
||||||
extraConfig = mapOf("h2Settings" to mapOf("address" to "localhost:0"))
|
|
||||||
configure()
|
|
||||||
}
|
|
||||||
notaryNode(0) {
|
|
||||||
p2pPort(10009)
|
|
||||||
rpcSettings {
|
|
||||||
address("localhost:10010")
|
|
||||||
adminAddress("localhost:10110")
|
|
||||||
}
|
|
||||||
devMode(true)
|
|
||||||
}
|
|
||||||
notaryNode(1) {
|
|
||||||
p2pPort(10013)
|
|
||||||
rpcSettings {
|
|
||||||
address("localhost:10014")
|
|
||||||
adminAddress("localhost:10114")
|
|
||||||
}
|
|
||||||
devMode(true)
|
|
||||||
}
|
|
||||||
notaryNode(2) {
|
|
||||||
p2pPort(10017)
|
|
||||||
rpcSettings {
|
|
||||||
address("localhost:10018")
|
|
||||||
adminAddress("localhost:10118")
|
|
||||||
}
|
|
||||||
devMode(true)
|
|
||||||
}
|
|
||||||
notaryNode(3) {
|
|
||||||
p2pPort(10021)
|
|
||||||
rpcSettings {
|
|
||||||
address("localhost:10022")
|
|
||||||
adminAddress("localhost:10122")
|
|
||||||
}
|
|
||||||
devMode(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setup(context: CordformContext) {
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
package net.corda.notarydemo
|
|
||||||
|
|
||||||
import net.corda.testing.node.internal.demorun.nodeRunner
|
|
||||||
|
|
||||||
fun main(args: Array<String>) {
|
|
||||||
listOf(SingleNotaryCordform(), RaftNotaryCordform(), BFTNotaryCordform()).map { it.nodeRunner() }.forEach {
|
|
||||||
it.clean()
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,52 +0,0 @@
|
|||||||
package net.corda.notarydemo
|
|
||||||
|
|
||||||
import net.corda.cordform.CordformContext
|
|
||||||
import net.corda.cordform.CordformDefinition
|
|
||||||
import net.corda.node.services.config.NotaryConfig
|
|
||||||
import net.corda.testing.node.internal.demorun.*
|
|
||||||
import net.corda.testing.core.ALICE_NAME
|
|
||||||
import net.corda.testing.core.BOB_NAME
|
|
||||||
import net.corda.testing.core.DUMMY_NOTARY_NAME
|
|
||||||
import java.nio.file.Paths
|
|
||||||
|
|
||||||
fun main(args: Array<String>) = CustomNotaryCordform().nodeRunner().deployAndRunNodes()
|
|
||||||
|
|
||||||
class CustomNotaryCordform : CordformDefinition() {
|
|
||||||
init {
|
|
||||||
nodesDirectory = Paths.get("build", "nodes", "nodesCustom")
|
|
||||||
node {
|
|
||||||
name(ALICE_NAME)
|
|
||||||
p2pPort(10002)
|
|
||||||
rpcSettings {
|
|
||||||
address("localhost:10003")
|
|
||||||
adminAddress("localhost:10103")
|
|
||||||
}
|
|
||||||
rpcUsers(notaryDemoUser)
|
|
||||||
devMode(true)
|
|
||||||
extraConfig = mapOf("h2Settings" to mapOf("address" to "localhost:0"))
|
|
||||||
}
|
|
||||||
node {
|
|
||||||
name(BOB_NAME)
|
|
||||||
p2pPort(10005)
|
|
||||||
rpcSettings {
|
|
||||||
address("localhost:10006")
|
|
||||||
adminAddress("localhost:10106")
|
|
||||||
}
|
|
||||||
devMode(true)
|
|
||||||
extraConfig = mapOf("h2Settings" to mapOf("address" to "localhost:0"))
|
|
||||||
}
|
|
||||||
node {
|
|
||||||
name(DUMMY_NOTARY_NAME)
|
|
||||||
p2pPort(10009)
|
|
||||||
rpcSettings {
|
|
||||||
address("localhost:10010")
|
|
||||||
adminAddress("localhost:10110")
|
|
||||||
}
|
|
||||||
notary(NotaryConfig(validating = true, custom = true))
|
|
||||||
devMode(true)
|
|
||||||
extraConfig = mapOf("h2Settings" to mapOf("address" to "localhost:0"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setup(context: CordformContext) {}
|
|
||||||
}
|
|
@ -17,7 +17,7 @@ import java.util.concurrent.Future
|
|||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
val address = NetworkHostAndPort("localhost", 10003)
|
val address = NetworkHostAndPort("localhost", 10003)
|
||||||
println("Connecting to the recipient node ($address)")
|
println("Connecting to the recipient node ($address)")
|
||||||
CordaRPCClient(address).start(notaryDemoUser.username, notaryDemoUser.password).use {
|
CordaRPCClient(address).start("demou", "demop").use {
|
||||||
NotaryDemoClientApi(it.proxy).notarise(10)
|
NotaryDemoClientApi(it.proxy).notarise(10)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,86 +0,0 @@
|
|||||||
package net.corda.notarydemo
|
|
||||||
|
|
||||||
import net.corda.cordform.CordformContext
|
|
||||||
import net.corda.cordform.CordformDefinition
|
|
||||||
import net.corda.cordform.CordformNode
|
|
||||||
import net.corda.core.identity.CordaX500Name
|
|
||||||
import net.corda.core.utilities.NetworkHostAndPort
|
|
||||||
import net.corda.node.services.config.NotaryConfig
|
|
||||||
import net.corda.node.services.config.RaftConfig
|
|
||||||
import net.corda.nodeapi.internal.DevIdentityGenerator
|
|
||||||
import net.corda.testing.node.internal.demorun.*
|
|
||||||
import net.corda.testing.core.ALICE_NAME
|
|
||||||
import net.corda.testing.core.BOB_NAME
|
|
||||||
import java.nio.file.Paths
|
|
||||||
|
|
||||||
fun main(args: Array<String>) = RaftNotaryCordform().nodeRunner().deployAndRunNodes()
|
|
||||||
|
|
||||||
internal fun createNotaryNames(clusterSize: Int) = (0 until clusterSize).map { CordaX500Name("Notary Service $it", "Zurich", "CH") }
|
|
||||||
|
|
||||||
private val notaryNames = createNotaryNames(3)
|
|
||||||
|
|
||||||
// This is not the intended final design for how to use CordformDefinition, please treat this as experimental and DO
|
|
||||||
// NOT use this as a design to copy.
|
|
||||||
class RaftNotaryCordform : CordformDefinition() {
|
|
||||||
private val clusterName = CordaX500Name("Raft", "Zurich", "CH")
|
|
||||||
|
|
||||||
init {
|
|
||||||
nodesDirectory = Paths.get("build", "nodes", "nodesRaft")
|
|
||||||
node {
|
|
||||||
name(ALICE_NAME)
|
|
||||||
p2pPort(10002)
|
|
||||||
rpcSettings {
|
|
||||||
address("localhost:10003")
|
|
||||||
adminAddress("localhost:10103")
|
|
||||||
}
|
|
||||||
rpcUsers(notaryDemoUser)
|
|
||||||
devMode(true)
|
|
||||||
extraConfig = mapOf("h2Settings" to mapOf("address" to "localhost:0"))
|
|
||||||
}
|
|
||||||
node {
|
|
||||||
name(BOB_NAME)
|
|
||||||
p2pPort(10005)
|
|
||||||
rpcSettings {
|
|
||||||
address("localhost:10006")
|
|
||||||
adminAddress("localhost:10106")
|
|
||||||
}
|
|
||||||
devMode(true)
|
|
||||||
extraConfig = mapOf("h2Settings" to mapOf("address" to "localhost:0"))
|
|
||||||
}
|
|
||||||
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, serviceLegalName = clusterName, raft = RaftConfig(NetworkHostAndPort("localhost", nodePort), clusterAddresses)))
|
|
||||||
extraConfig = mapOf("h2Settings" to mapOf("address" to "localhost:0"))
|
|
||||||
configure()
|
|
||||||
devMode(true)
|
|
||||||
}
|
|
||||||
notaryNode(0, 10008) {
|
|
||||||
p2pPort(10009)
|
|
||||||
rpcSettings {
|
|
||||||
address("localhost:10010")
|
|
||||||
adminAddress("localhost:10110")
|
|
||||||
}
|
|
||||||
devMode(true)
|
|
||||||
}
|
|
||||||
notaryNode(1, 10012, 10008) {
|
|
||||||
p2pPort(10013)
|
|
||||||
rpcSettings {
|
|
||||||
address("localhost:10014")
|
|
||||||
adminAddress("localhost:10114")
|
|
||||||
}
|
|
||||||
devMode(true)
|
|
||||||
}
|
|
||||||
notaryNode(2, 10016, 10008) {
|
|
||||||
p2pPort(10017)
|
|
||||||
rpcSettings {
|
|
||||||
address("localhost:10018")
|
|
||||||
adminAddress("localhost:10118")
|
|
||||||
}
|
|
||||||
devMode(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setup(context: CordformContext) {
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
package net.corda.notarydemo
|
|
||||||
|
|
||||||
import net.corda.cordform.CordformContext
|
|
||||||
import net.corda.cordform.CordformDefinition
|
|
||||||
import net.corda.node.services.Permissions.Companion.all
|
|
||||||
import net.corda.node.services.config.NotaryConfig
|
|
||||||
import net.corda.testing.core.ALICE_NAME
|
|
||||||
import net.corda.testing.core.BOB_NAME
|
|
||||||
import net.corda.testing.core.DUMMY_NOTARY_NAME
|
|
||||||
import net.corda.testing.node.User
|
|
||||||
import net.corda.testing.node.internal.demorun.*
|
|
||||||
import java.nio.file.Paths
|
|
||||||
|
|
||||||
fun main(args: Array<String>) = SingleNotaryCordform().nodeRunner().deployAndRunNodes()
|
|
||||||
|
|
||||||
val notaryDemoUser = User("demou", "demop", setOf(all()))
|
|
||||||
|
|
||||||
// This is not the intended final design for how to use CordformDefinition, please treat this as experimental and DO
|
|
||||||
// NOT use this as a design to copy.
|
|
||||||
class SingleNotaryCordform : CordformDefinition() {
|
|
||||||
init {
|
|
||||||
nodesDirectory = Paths.get("build", "nodes", "nodesSingle")
|
|
||||||
node {
|
|
||||||
name(ALICE_NAME)
|
|
||||||
p2pPort(10002)
|
|
||||||
rpcSettings {
|
|
||||||
address("localhost:10003")
|
|
||||||
adminAddress("localhost:10103")
|
|
||||||
}
|
|
||||||
rpcUsers(notaryDemoUser)
|
|
||||||
devMode(true)
|
|
||||||
extraConfig = mapOf("h2Settings" to mapOf("address" to "localhost:0"))
|
|
||||||
}
|
|
||||||
node {
|
|
||||||
name(BOB_NAME)
|
|
||||||
p2pPort(10005)
|
|
||||||
rpcSettings {
|
|
||||||
address("localhost:10006")
|
|
||||||
adminAddress("localhost:10106")
|
|
||||||
}
|
|
||||||
devMode(true)
|
|
||||||
extraConfig = mapOf("h2Settings" to mapOf("address" to "localhost:0"))
|
|
||||||
}
|
|
||||||
node {
|
|
||||||
name(DUMMY_NOTARY_NAME)
|
|
||||||
p2pPort(10009)
|
|
||||||
rpcSettings {
|
|
||||||
address("localhost:10010")
|
|
||||||
adminAddress("localhost:10110")
|
|
||||||
}
|
|
||||||
notary(NotaryConfig(validating = true))
|
|
||||||
devMode(true)
|
|
||||||
extraConfig = mapOf("h2Settings" to mapOf("address" to "localhost:0"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setup(context: CordformContext) {}
|
|
||||||
}
|
|
@ -26,7 +26,6 @@ sourceSets {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile project(':test-utils')
|
compile project(':test-utils')
|
||||||
compile "net.corda.plugins:cordform-common:$gradle_plugins_version"
|
|
||||||
|
|
||||||
// Integration test helpers
|
// Integration test helpers
|
||||||
testCompile "org.assertj:assertj-core:$assertj_version"
|
testCompile "org.assertj:assertj-core:$assertj_version"
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
package net.corda.testing.node.internal
|
package net.corda.testing.node.internal
|
||||||
|
|
||||||
import com.google.common.collect.HashMultimap
|
|
||||||
import com.google.common.util.concurrent.ThreadFactoryBuilder
|
import com.google.common.util.concurrent.ThreadFactoryBuilder
|
||||||
import com.typesafe.config.Config
|
import com.typesafe.config.Config
|
||||||
import com.typesafe.config.ConfigFactory
|
import com.typesafe.config.ConfigFactory
|
||||||
import com.typesafe.config.ConfigRenderOptions
|
import com.typesafe.config.ConfigRenderOptions
|
||||||
import com.typesafe.config.ConfigValueFactory
|
import com.typesafe.config.ConfigValueFactory
|
||||||
import net.corda.client.rpc.internal.createCordaRPCClientWithInternalSslAndClassLoader
|
import net.corda.client.rpc.internal.createCordaRPCClientWithInternalSslAndClassLoader
|
||||||
import net.corda.cordform.CordformContext
|
|
||||||
import net.corda.cordform.CordformNode
|
|
||||||
import net.corda.core.concurrent.CordaFuture
|
import net.corda.core.concurrent.CordaFuture
|
||||||
import net.corda.core.concurrent.firstOf
|
import net.corda.core.concurrent.firstOf
|
||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
@ -33,7 +30,6 @@ import net.corda.node.utilities.registration.NodeRegistrationHelper
|
|||||||
import net.corda.nodeapi.internal.DevIdentityGenerator
|
import net.corda.nodeapi.internal.DevIdentityGenerator
|
||||||
import net.corda.nodeapi.internal.SignedNodeInfo
|
import net.corda.nodeapi.internal.SignedNodeInfo
|
||||||
import net.corda.nodeapi.internal.addShutdownHook
|
import net.corda.nodeapi.internal.addShutdownHook
|
||||||
import net.corda.nodeapi.internal.config.parseAs
|
|
||||||
import net.corda.nodeapi.internal.config.toConfig
|
import net.corda.nodeapi.internal.config.toConfig
|
||||||
import net.corda.nodeapi.internal.crypto.X509KeyStore
|
import net.corda.nodeapi.internal.crypto.X509KeyStore
|
||||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||||
@ -52,8 +48,6 @@ import net.corda.testing.internal.setGlobalSerialization
|
|||||||
import net.corda.testing.node.ClusterSpec
|
import net.corda.testing.node.ClusterSpec
|
||||||
import net.corda.testing.node.NotarySpec
|
import net.corda.testing.node.NotarySpec
|
||||||
import net.corda.testing.node.User
|
import net.corda.testing.node.User
|
||||||
import net.corda.testing.node.internal.DriverDSLImpl.ClusterType.NON_VALIDATING_RAFT
|
|
||||||
import net.corda.testing.node.internal.DriverDSLImpl.ClusterType.VALIDATING_RAFT
|
|
||||||
import net.corda.testing.node.internal.DriverDSLImpl.Companion.cordappsInCurrentAndAdditionalPackages
|
import net.corda.testing.node.internal.DriverDSLImpl.Companion.cordappsInCurrentAndAdditionalPackages
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
@ -309,97 +303,6 @@ class DriverDSLImpl(
|
|||||||
NON_VALIDATING_BFT(false, CordaX500Name("BFT", "Zurich", "CH"))
|
NON_VALIDATING_BFT(false, CordaX500Name("BFT", "Zurich", "CH"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO remove this
|
|
||||||
internal fun startCordformNodes(cordforms: List<CordformNode>): CordaFuture<*> {
|
|
||||||
check(notarySpecs.isEmpty()) { "Specify notaries in the CordformDefinition" }
|
|
||||||
check(compatibilityZone == null) { "Cordform nodes cannot be run with compatibilityZoneURL" }
|
|
||||||
|
|
||||||
val clusterNodes = HashMultimap.create<ClusterType, CordaX500Name>()
|
|
||||||
val notaryInfos = ArrayList<NotaryInfo>()
|
|
||||||
|
|
||||||
// Go though the node definitions and pick out the notaries so that we can generate their identities to be used
|
|
||||||
// in the network parameters
|
|
||||||
for (cordform in cordforms) {
|
|
||||||
if (cordform.notary == null) continue
|
|
||||||
val name = CordaX500Name.parse(cordform.name)
|
|
||||||
val notaryConfig = ConfigFactory.parseMap(cordform.notary).parseAs<NotaryConfig>()
|
|
||||||
// We need to first group the nodes that form part of a cluster. We assume for simplicity that nodes of the
|
|
||||||
// same cluster type and validating flag are part of the same cluster.
|
|
||||||
when {
|
|
||||||
notaryConfig.raft != null -> {
|
|
||||||
val key = if (notaryConfig.validating) VALIDATING_RAFT else NON_VALIDATING_RAFT
|
|
||||||
clusterNodes.put(key, name)
|
|
||||||
}
|
|
||||||
notaryConfig.bftSMaRt != null -> clusterNodes.put(ClusterType.NON_VALIDATING_BFT, name)
|
|
||||||
else -> {
|
|
||||||
// We have all we need here to generate the identity for single node notaries
|
|
||||||
val identity = DevIdentityGenerator.installKeyStoreWithNodeIdentity(baseDirectory(name), legalName = name)
|
|
||||||
notaryInfos += NotaryInfo(identity, notaryConfig.validating)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
clusterNodes.asMap().forEach { type, nodeNames ->
|
|
||||||
val identity = if (type == ClusterType.NON_VALIDATING_RAFT || type == ClusterType.VALIDATING_RAFT) {
|
|
||||||
DevIdentityGenerator.generateDistributedNotarySingularIdentity(
|
|
||||||
dirs = nodeNames.map { baseDirectory(it) },
|
|
||||||
notaryName = type.clusterName
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
DevIdentityGenerator.generateDistributedNotaryCompositeIdentity(
|
|
||||||
dirs = nodeNames.map { baseDirectory(it) },
|
|
||||||
notaryName = type.clusterName
|
|
||||||
)
|
|
||||||
}
|
|
||||||
notaryInfos += NotaryInfo(identity, type.validating)
|
|
||||||
}
|
|
||||||
|
|
||||||
val localNetworkMap = LocalNetworkMap(notaryInfos)
|
|
||||||
|
|
||||||
return cordforms.map {
|
|
||||||
val startedNode = startCordformNode(it, localNetworkMap)
|
|
||||||
if (it.webAddress != null) {
|
|
||||||
// Start a webserver if an address for it was specified
|
|
||||||
startedNode.flatMap { startWebserver(it) }
|
|
||||||
} else {
|
|
||||||
startedNode
|
|
||||||
}
|
|
||||||
}.transpose()
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO remove this
|
|
||||||
private fun startCordformNode(cordform: CordformNode, localNetworkMap: LocalNetworkMap): CordaFuture<NodeHandle> {
|
|
||||||
val name = CordaX500Name.parse(cordform.name)
|
|
||||||
// TODO We shouldn't have to allocate an RPC or web address if they're not specified. We're having to do this because of startNodeInternal
|
|
||||||
val rpcAddress = if (cordform.rpcAddress == null) {
|
|
||||||
val overrides = mutableMapOf<String, Any>("rpcSettings.address" to portAllocation.nextHostAndPort().toString())
|
|
||||||
cordform.config.apply {
|
|
||||||
overrides += "rpcSettings.adminAddress" to portAllocation.nextHostAndPort().toString()
|
|
||||||
}
|
|
||||||
overrides
|
|
||||||
} else {
|
|
||||||
val overrides = mutableMapOf<String, Any>()
|
|
||||||
cordform.config.apply {
|
|
||||||
overrides += "rpcSettings.adminAddress" to portAllocation.nextHostAndPort().toString()
|
|
||||||
}
|
|
||||||
overrides
|
|
||||||
}
|
|
||||||
val webAddress = cordform.webAddress?.let { NetworkHostAndPort.parse(it) } ?: portAllocation.nextHostAndPort()
|
|
||||||
val notary = if (cordform.notary != null) mapOf("notary" to cordform.notary) else emptyMap()
|
|
||||||
val rpcUsers = cordform.rpcUsers
|
|
||||||
|
|
||||||
val rawConfig = cordform.config + rpcAddress + notary + mapOf(
|
|
||||||
"rpcUsers" to if (rpcUsers.isEmpty()) defaultRpcUserList else rpcUsers
|
|
||||||
)
|
|
||||||
val typesafe = ConfigHelper.loadConfig(
|
|
||||||
baseDirectory = baseDirectory(name),
|
|
||||||
allowMissingConfig = true,
|
|
||||||
configOverrides = rawConfig.toNodeOnly()
|
|
||||||
)
|
|
||||||
val config = NodeConfig(typesafe).checkAndOverrideForInMemoryDB()
|
|
||||||
return startNodeInternal(config, webAddress, null, "512m", localNetworkMap, emptySet())
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
private fun queryWebserver(handle: NodeHandle, process: Process): WebserverHandle {
|
private fun queryWebserver(handle: NodeHandle, process: Process): WebserverHandle {
|
||||||
val protocol = if ((handle as NodeHandleInternal).useHTTPS) "https://" else "http://"
|
val protocol = if ((handle as NodeHandleInternal).useHTTPS) "https://" else "http://"
|
||||||
@ -993,7 +896,7 @@ private class NetworkVisibilityController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface InternalDriverDSL : DriverDSL, CordformContext {
|
interface InternalDriverDSL : DriverDSL {
|
||||||
private companion object {
|
private companion object {
|
||||||
private val DEFAULT_POLL_INTERVAL = 500.millis
|
private val DEFAULT_POLL_INTERVAL = 500.millis
|
||||||
private const val DEFAULT_WARN_COUNT = 120
|
private const val DEFAULT_WARN_COUNT = 120
|
||||||
@ -1001,7 +904,7 @@ interface InternalDriverDSL : DriverDSL, CordformContext {
|
|||||||
|
|
||||||
val shutdownManager: ShutdownManager
|
val shutdownManager: ShutdownManager
|
||||||
|
|
||||||
override fun baseDirectory(nodeName: String): Path = baseDirectory(CordaX500Name.parse(nodeName))
|
fun baseDirectory(nodeName: String): Path = baseDirectory(CordaX500Name.parse(nodeName))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Polls a function until it returns a non-null value. Note that there is no timeout on the polling.
|
* Polls a function until it returns a non-null value. Note that there is no timeout on the polling.
|
||||||
@ -1205,4 +1108,5 @@ private fun Config.toNodeOnly(): Config {
|
|||||||
return if (hasPath("webAddress")) withoutPath("webAddress").withoutPath("useHTTPS") else this
|
return if (hasPath("webAddress")) withoutPath("webAddress").withoutPath("useHTTPS") else this
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun DriverParameters.cordappsForAllNodes(): Set<TestCorDapp> = cordappsForAllNodes ?: cordappsInCurrentAndAdditionalPackages(extraCordappPackagesToScan)
|
internal fun DriverParameters.cordappsForAllNodes(): Set<TestCorDapp> = cordappsForAllNodes
|
||||||
|
?: cordappsInCurrentAndAdditionalPackages(extraCordappPackagesToScan)
|
@ -1,78 +0,0 @@
|
|||||||
package net.corda.testing.node.internal.demorun
|
|
||||||
|
|
||||||
import net.corda.cordform.CordformDefinition
|
|
||||||
import net.corda.cordform.CordformNode
|
|
||||||
import net.corda.core.internal.deleteRecursively
|
|
||||||
import net.corda.core.utilities.NetworkHostAndPort
|
|
||||||
import net.corda.core.utilities.getOrThrow
|
|
||||||
import net.corda.testing.driver.JmxPolicy
|
|
||||||
import net.corda.testing.driver.PortAllocation
|
|
||||||
import net.corda.testing.node.internal.DriverDSLImpl.Companion.cordappsInCurrentAndAdditionalPackages
|
|
||||||
import net.corda.testing.node.internal.internalDriver
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a demo runner for this cordform definition
|
|
||||||
*/
|
|
||||||
fun CordformDefinition.nodeRunner() = CordformNodeRunner(this)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A node runner creates and runs nodes for a given [[CordformDefinition]].
|
|
||||||
*/
|
|
||||||
class CordformNodeRunner(private val cordformDefinition: CordformDefinition) {
|
|
||||||
private var extraPackagesToScan = emptyList<String>()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builder method to sets the extra cordapp scan packages
|
|
||||||
*/
|
|
||||||
fun scanPackages(packages: List<String>): CordformNodeRunner {
|
|
||||||
extraPackagesToScan = packages
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
fun clean() {
|
|
||||||
System.err.println("Deleting: ${cordformDefinition.nodesDirectory}")
|
|
||||||
cordformDefinition.nodesDirectory.deleteRecursively()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deploy the nodes specified in the given [CordformDefinition]. This will block until all the nodes and webservers
|
|
||||||
* have terminated.
|
|
||||||
*/
|
|
||||||
fun deployAndRunNodes() {
|
|
||||||
runNodes(waitForAllNodesToFinish = true) { }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deploy the nodes specified in the given [CordformDefinition] and then execute the given [block] once all the nodes
|
|
||||||
* and webservers are up. After execution all these processes will be terminated.
|
|
||||||
*/
|
|
||||||
fun deployAndRunNodesAndThen(block: () -> Unit) {
|
|
||||||
runNodes(waitForAllNodesToFinish = false, block = block)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun runNodes(waitForAllNodesToFinish: Boolean, block: () -> Unit) {
|
|
||||||
clean()
|
|
||||||
val nodes = cordformDefinition.nodeConfigurers.map { configurer -> CordformNode().also { configurer.accept(it) } }
|
|
||||||
val maxPort = nodes
|
|
||||||
.flatMap { listOf(it.p2pAddress, it.rpcAddress, it.webAddress) }
|
|
||||||
.mapNotNull { address -> address?.let { NetworkHostAndPort.parse(it).port } }
|
|
||||||
.max()!!
|
|
||||||
internalDriver(
|
|
||||||
jmxPolicy = JmxPolicy(true),
|
|
||||||
driverDirectory = cordformDefinition.nodesDirectory,
|
|
||||||
// Notaries are manually specified in Cordform so we don't want the driver automatically starting any
|
|
||||||
notarySpecs = emptyList(),
|
|
||||||
// Start from after the largest port used to prevent port clash
|
|
||||||
portAllocation = PortAllocation.Incremental(maxPort + 1),
|
|
||||||
waitForAllNodesToFinish = waitForAllNodesToFinish,
|
|
||||||
cordappsForAllNodes = cordappsInCurrentAndAdditionalPackages(extraPackagesToScan)
|
|
||||||
) {
|
|
||||||
cordformDefinition.setup(this)
|
|
||||||
startCordformNodes(nodes).getOrThrow() // Only proceed once everything is up and running
|
|
||||||
println("All nodes and webservers are ready...")
|
|
||||||
block()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
|||||||
@file:JvmName("CordformUtils")
|
|
||||||
|
|
||||||
package net.corda.testing.node.internal.demorun
|
|
||||||
|
|
||||||
import net.corda.cordform.CordformDefinition
|
|
||||||
import net.corda.cordform.CordformNode
|
|
||||||
import net.corda.cordform.RpcSettings
|
|
||||||
import net.corda.cordform.SslOptions
|
|
||||||
import net.corda.core.identity.CordaX500Name
|
|
||||||
import net.corda.node.services.config.NotaryConfig
|
|
||||||
import net.corda.nodeapi.internal.config.toConfig
|
|
||||||
import net.corda.testing.node.User
|
|
||||||
|
|
||||||
fun CordformDefinition.node(configure: CordformNode.() -> Unit) {
|
|
||||||
addNode { cordformNode -> cordformNode.configure() }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun CordformNode.name(name: CordaX500Name) = name(name.toString())
|
|
||||||
|
|
||||||
fun CordformNode.rpcUsers(vararg users: User) {
|
|
||||||
rpcUsers = users.map { it.toConfig().root().unwrapped() }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun CordformNode.notary(notaryConfig: NotaryConfig) {
|
|
||||||
notary = notaryConfig.toConfig().root().unwrapped()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun CordformNode.rpcSettings(configure: RpcSettings.() -> Unit) {
|
|
||||||
RpcSettings().also(configure).also(this::rpcSettings)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun RpcSettings.ssl(configure: SslOptions.() -> Unit) {
|
|
||||||
SslOptions().also(configure).also(this::ssl)
|
|
||||||
}
|
|
@ -56,8 +56,6 @@ dependencies {
|
|||||||
// Controls FX: more java FX components http://fxexperience.com/controlsfx/
|
// Controls FX: more java FX components http://fxexperience.com/controlsfx/
|
||||||
compile "org.controlsfx:controlsfx:$controlsfx_version"
|
compile "org.controlsfx:controlsfx:$controlsfx_version"
|
||||||
|
|
||||||
compile "net.corda.plugins:cordform-common:$gradle_plugins_version"
|
|
||||||
|
|
||||||
compile project(':client:rpc')
|
compile project(':client:rpc')
|
||||||
compile project(':finance')
|
compile project(':finance')
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user