mirror of
https://github.com/corda/corda.git
synced 2025-04-07 11:27:01 +00:00
CORDA-1924: Remove references to Cordform definition and cordform-common (#3842)
This commit is contained in:
parent
329c9da0a9
commit
3594ccd89b
@ -210,7 +210,6 @@ allprojects {
|
||||
mavenCentral()
|
||||
jcenter()
|
||||
maven { url 'https://jitpack.io' }
|
||||
maven { url "$artifactory_contextUrl/corda-releases" } // cordform-common
|
||||
}
|
||||
|
||||
configurations {
|
||||
|
@ -6,6 +6,8 @@ release, see :doc:`upgrade-notes`.
|
||||
|
||||
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)
|
||||
|
||||
* 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
|
||||
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.
|
||||
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.ConfigFactory
|
||||
import net.corda.cordform.CordformNode
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.internal.*
|
||||
@ -46,11 +45,11 @@ import kotlin.streams.toList
|
||||
*/
|
||||
// TODO Move this to tools:bootstrapper
|
||||
class NetworkBootstrapper
|
||||
@VisibleForTesting
|
||||
internal constructor(private val initSerEnv: Boolean,
|
||||
private val embeddedCordaJar: () -> InputStream,
|
||||
private val nodeInfosGenerator: (List<Path>) -> List<Path>,
|
||||
private val contractsJarConverter: (Path) -> ContractsJar) {
|
||||
@VisibleForTesting
|
||||
internal constructor(private val initSerEnv: Boolean,
|
||||
private val embeddedCordaJar: () -> InputStream,
|
||||
private val nodeInfosGenerator: (List<Path>) -> List<Path>,
|
||||
private val contractsJarConverter: (Path) -> ContractsJar) {
|
||||
|
||||
constructor() : this(
|
||||
initSerEnv = true,
|
||||
@ -102,7 +101,7 @@ class NetworkBootstrapper
|
||||
process.destroyForcibly()
|
||||
throw IllegalStateException("Error while generating node info file. Please check the logs in $logsDir.")
|
||||
}
|
||||
check(process.exitValue() == 0) { "Error while generating node info file. Please check the logs in $logsDir." }
|
||||
check(process.exitValue() == 0) { "Error while generating node info file. Please check the logs in $logsDir." }
|
||||
return nodeDir.list { paths ->
|
||||
paths.filter { it.fileName.toString().startsWith(NODE_INFO_FILE_NAME_PREFIX) }.findFirst().get()
|
||||
}
|
||||
@ -269,7 +268,7 @@ class NetworkBootstrapper
|
||||
|
||||
private fun distributeNodeInfos(nodeDirs: List<Path>, nodeInfoFiles: List<Path>) {
|
||||
for (nodeDir in nodeDirs) {
|
||||
val additionalNodeInfosDir = (nodeDir / CordformNode.NODE_INFO_DIRECTORY).createDirectories()
|
||||
val additionalNodeInfosDir = (nodeDir / NODE_INFO_DIRECTORY).createDirectories()
|
||||
for (nodeInfoFile in nodeInfoFiles) {
|
||||
nodeInfoFile.copyToDirectory(additionalNodeInfosDir, REPLACE_EXISTING)
|
||||
}
|
||||
@ -364,10 +363,10 @@ class NetworkBootstrapper
|
||||
|
||||
private fun NodeInfo.notaryIdentity(): Party {
|
||||
return when (legalIdentities.size) {
|
||||
// Single node notaries have just one identity like all other nodes. This identity is the notary identity
|
||||
// Single node notaries have just one identity like all other nodes. This identity is the notary identity
|
||||
1 -> legalIdentities[0]
|
||||
// Nodes which are part of a distributed notary have a second identity which is the composite identity of the
|
||||
// cluster and is shared by all the other members. This is the notary identity.
|
||||
// Nodes which are part of a distributed notary have a second identity which is the composite identity of the
|
||||
// cluster and is shared by all the other members. This is the notary identity.
|
||||
2 -> legalIdentities[1]
|
||||
else -> throw IllegalArgumentException("Not sure how to get the notary identity in this scenerio: $this")
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
package net.corda.nodeapi.internal.network
|
||||
|
||||
import net.corda.cordform.CordformNode
|
||||
import net.corda.core.internal.*
|
||||
import net.corda.core.utilities.contextLogger
|
||||
import net.corda.nodeapi.internal.NODE_INFO_DIRECTORY
|
||||
import rx.Observable
|
||||
import rx.Scheduler
|
||||
import rx.Subscription
|
||||
@ -96,10 +96,11 @@ class NodeInfoFilesCopier(scheduler: Scheduler = Schedulers.io()) : AutoCloseabl
|
||||
private fun poll() {
|
||||
nodeDataMapBox.locked {
|
||||
for (nodeData in values) {
|
||||
nodeData.nodeDir.list { paths -> paths
|
||||
.filter { it.isRegularFile() }
|
||||
.filter { it.fileName.toString().startsWith(NODE_INFO_FILE_NAME_PREFIX) }
|
||||
.forEach { processPath(nodeData, it) }
|
||||
nodeData.nodeDir.list { paths ->
|
||||
paths
|
||||
.filter { it.isRegularFile() }
|
||||
.filter { it.fileName.toString().startsWith(NODE_INFO_FILE_NAME_PREFIX) }
|
||||
.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.
|
||||
*/
|
||||
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.
|
||||
val previouslySeenFiles = mutableMapOf<Path, FileTime>()
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
package net.corda.nodeapi.internal.network
|
||||
|
||||
import com.typesafe.config.ConfigFactory
|
||||
import net.corda.cordform.CordformNode.NODE_INFO_DIRECTORY
|
||||
import net.corda.core.crypto.secureRandomBytes
|
||||
import net.corda.core.crypto.sha256
|
||||
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.node.services.config.NotaryConfig
|
||||
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.config.parseAs
|
||||
import net.corda.nodeapi.internal.config.toConfig
|
||||
|
@ -1,10 +1,10 @@
|
||||
package net.corda.nodeapi.internal.network
|
||||
|
||||
import net.corda.cordform.CordformNode
|
||||
import net.corda.core.internal.div
|
||||
import net.corda.core.internal.list
|
||||
import net.corda.core.internal.write
|
||||
import net.corda.nodeapi.eventually
|
||||
import net.corda.nodeapi.internal.NODE_INFO_DIRECTORY
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
@ -34,12 +34,12 @@ class NodeInfoFilesCopierTest {
|
||||
private val rootPath get() = folder.root.toPath()
|
||||
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 node2RootPath by lazy { nodeDir(NODE_2_PATH) }
|
||||
private val node1AdditionalNodeInfoPath by lazy { node1RootPath.resolve(CordformNode.NODE_INFO_DIRECTORY) }
|
||||
private val node2AdditionalNodeInfoPath by lazy { node2RootPath.resolve(CordformNode.NODE_INFO_DIRECTORY) }
|
||||
private val node1AdditionalNodeInfoPath by lazy { node1RootPath.resolve(NODE_INFO_DIRECTORY) }
|
||||
private val node2AdditionalNodeInfoPath by lazy { node2RootPath.resolve(NODE_INFO_DIRECTORY) }
|
||||
|
||||
private lateinit var nodeInfoFilesCopier: NodeInfoFilesCopier
|
||||
|
||||
|
@ -71,7 +71,6 @@ dependencies {
|
||||
compile project(":confidential-identities")
|
||||
compile project(':client:rpc')
|
||||
compile project(':tools:shell')
|
||||
compile "net.corda.plugins:cordform-common:$gradle_plugins_version"
|
||||
|
||||
// Log4J: logging framework (with SLF4J bindings)
|
||||
compile "org.apache.logging.log4j:log4j-slf4j-impl:${log4j_version}"
|
||||
|
@ -1,6 +1,5 @@
|
||||
package net.corda.node.services.network
|
||||
|
||||
import net.corda.cordform.CordformNode
|
||||
import net.corda.core.concurrent.CordaFuture
|
||||
import net.corda.core.crypto.random63BitValue
|
||||
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.seconds
|
||||
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.network.NETWORK_PARAMS_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) {
|
||||
// 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()) {
|
||||
assertThat(nodeInfosDir.list()).isEmpty()
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
package net.corda.node.services.network
|
||||
|
||||
import net.corda.cordform.CordformNode
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.internal.*
|
||||
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.seconds
|
||||
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.SignedNodeInfo
|
||||
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)
|
||||
private val nodeInfosDir = nodePath / CordformNode.NODE_INFO_DIRECTORY
|
||||
|
||||
private val nodeInfosDir = nodePath / NODE_INFO_DIRECTORY
|
||||
private val nodeInfoFilesMap = HashMap<Path, NodeInfoFromFile>()
|
||||
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.
|
||||
*
|
||||
* 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.Jimfs
|
||||
import com.nhaarman.mockito_kotlin.*
|
||||
import net.corda.cordform.CordformNode.NODE_INFO_DIRECTORY
|
||||
import net.corda.core.crypto.Crypto
|
||||
import net.corda.core.crypto.SecureHash
|
||||
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.utilities.millis
|
||||
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.network.NETWORK_PARAMS_UPDATE_FILE_NAME
|
||||
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.Jimfs
|
||||
import net.corda.cordform.CordformNode
|
||||
import net.corda.core.internal.createDirectories
|
||||
import net.corda.core.internal.div
|
||||
import net.corda.core.internal.size
|
||||
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.network.NodeInfoFilesCopier
|
||||
import net.corda.testing.core.ALICE_NAME
|
||||
@ -51,7 +51,7 @@ class NodeInfoWatcherTest {
|
||||
val identityService = makeTestIdentityService()
|
||||
keyManagementService = MockKeyManagementService(identityService)
|
||||
nodeInfoWatcher = NodeInfoWatcher(tempFolder.root.toPath(), scheduler)
|
||||
nodeInfoPath = tempFolder.root.toPath() / CordformNode.NODE_INFO_DIRECTORY
|
||||
nodeInfoPath = tempFolder.root.toPath() / NODE_INFO_DIRECTORY
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -7,21 +7,6 @@ apply plugin: 'net.corda.plugins.cordapp'
|
||||
apply plugin: 'net.corda.plugins.cordformation'
|
||||
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 {
|
||||
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
|
||||
@ -48,13 +33,46 @@ dependencies {
|
||||
}
|
||||
|
||||
task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
||||
// CordformationDefinition is an experimental feature
|
||||
definitionClass = 'net.corda.bank.BankOfCordaCordform'
|
||||
}
|
||||
|
||||
task integrationTest(type: Test, dependsOn: []) {
|
||||
testClassesDirs = sourceSets.integrationTest.output.classesDirs
|
||||
classpath = sourceSets.integrationTest.runtimeClasspath
|
||||
nodeDefaults {
|
||||
cordapp project(':finance')
|
||||
}
|
||||
node {
|
||||
name "O=Notary Service,L=Zurich,C=CH"
|
||||
notary = [validating: true]
|
||||
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 {
|
||||
|
@ -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
|
||||
|
||||
import net.corda.bank.BOC_RPC_PWD
|
||||
import net.corda.bank.BOC_RPC_USER
|
||||
import net.corda.bank.api.BankOfCordaWebApi.IssueRequestParams
|
||||
import net.corda.client.rpc.CordaRPCClient
|
||||
import net.corda.core.messaging.startFlow
|
||||
@ -16,6 +14,9 @@ import net.corda.testing.http.HttpApi
|
||||
* Interface for communicating with Bank of Corda node
|
||||
*/
|
||||
object BankOfCordaClientApi {
|
||||
const val BOC_RPC_USER = "bankUser"
|
||||
const val BOC_RPC_PWD = "test"
|
||||
|
||||
/**
|
||||
* HTTP API
|
||||
*/
|
||||
@ -40,7 +41,8 @@ object BankOfCordaClientApi {
|
||||
// Resolve parties via RPC
|
||||
val issueToParty = rpc.wellKnownPartyFromX500Name(params.issueToPartyName)
|
||||
?: 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 issuerBankPartyRef = OpaqueBytes.of(params.issuerBankPartyRef.toByte())
|
||||
|
@ -49,19 +49,229 @@ publishing {
|
||||
task deployNodes(dependsOn: ['deployNodesSingle', 'deployNodesRaft', 'deployNodesBFT', 'deployNodesCustom'])
|
||||
|
||||
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') {
|
||||
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') {
|
||||
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') {
|
||||
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) {
|
||||
|
@ -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>) {
|
||||
val address = NetworkHostAndPort("localhost", 10003)
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
compile project(':test-utils')
|
||||
compile "net.corda.plugins:cordform-common:$gradle_plugins_version"
|
||||
|
||||
// Integration test helpers
|
||||
testCompile "org.assertj:assertj-core:$assertj_version"
|
||||
|
@ -1,14 +1,11 @@
|
||||
package net.corda.testing.node.internal
|
||||
|
||||
import com.google.common.collect.HashMultimap
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder
|
||||
import com.typesafe.config.Config
|
||||
import com.typesafe.config.ConfigFactory
|
||||
import com.typesafe.config.ConfigRenderOptions
|
||||
import com.typesafe.config.ConfigValueFactory
|
||||
import 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.firstOf
|
||||
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.SignedNodeInfo
|
||||
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.crypto.X509KeyStore
|
||||
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.NotarySpec
|
||||
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 okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
@ -309,97 +303,6 @@ class DriverDSLImpl(
|
||||
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")
|
||||
private fun queryWebserver(handle: NodeHandle, process: Process): WebserverHandle {
|
||||
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 val DEFAULT_POLL_INTERVAL = 500.millis
|
||||
private const val DEFAULT_WARN_COUNT = 120
|
||||
@ -1001,7 +904,7 @@ interface InternalDriverDSL : DriverDSL, CordformContext {
|
||||
|
||||
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.
|
||||
@ -1205,4 +1108,5 @@ private fun Config.toNodeOnly(): Config {
|
||||
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/
|
||||
compile "org.controlsfx:controlsfx:$controlsfx_version"
|
||||
|
||||
compile "net.corda.plugins:cordform-common:$gradle_plugins_version"
|
||||
|
||||
compile project(':client:rpc')
|
||||
compile project(':finance')
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user