mirror of
https://github.com/corda/corda.git
synced 2024-12-18 20:47:57 +00:00
One demo definition for both IntelliJ and gradle (#697)
* Raft notary demo now defined in one place that both IntelliJ/driver and gradle/runnodes can run * New module cordform-common for code common to cordformation and corda * Add single notary demo
This commit is contained in:
parent
edf269dbe5
commit
c8d71a96f5
2
.gitignore
vendored
2
.gitignore
vendored
@ -32,6 +32,7 @@ lib/dokka.jar
|
||||
.idea/libraries
|
||||
.idea/shelf
|
||||
.idea/dataSources
|
||||
/gradle-plugins/.idea
|
||||
|
||||
# Include the -parameters compiler option by default in IntelliJ required for serialization.
|
||||
!.idea/compiler.xml
|
||||
@ -53,6 +54,7 @@ lib/dokka.jar
|
||||
# Gradle:
|
||||
# .idea/gradle.xml
|
||||
# .idea/libraries
|
||||
/gradle-plugins/gradle*
|
||||
|
||||
# Mongo Explorer plugin:
|
||||
# .idea/mongoSettings.xml
|
||||
|
2
.idea/compiler.xml
generated
2
.idea/compiler.xml
generated
@ -17,6 +17,8 @@
|
||||
<module name="corda-webserver_integrationTest" target="1.8" />
|
||||
<module name="corda-webserver_main" target="1.8" />
|
||||
<module name="corda-webserver_test" target="1.8" />
|
||||
<module name="cordform-common_main" target="1.8" />
|
||||
<module name="cordform-common_test" target="1.8" />
|
||||
<module name="core_main" target="1.8" />
|
||||
<module name="core_test" target="1.8" />
|
||||
<module name="demobench_main" target="1.8" />
|
||||
|
@ -41,6 +41,7 @@ buildscript {
|
||||
ext.rxjava_version = '1.2.4'
|
||||
ext.requery_version = '1.2.1'
|
||||
ext.dokka_version = '0.9.13'
|
||||
ext.eddsa_version = '0.2.0'
|
||||
|
||||
// Update 121 is required for ObjectInputFilter and at time of writing 131 was latest:
|
||||
ext.java8_minUpdateVersion = '131'
|
||||
@ -60,6 +61,7 @@ buildscript {
|
||||
classpath "org.jetbrains.kotlin:kotlin-noarg:$kotlin_version"
|
||||
classpath "org.jetbrains.dokka:dokka-gradle-plugin:${dokka_version}"
|
||||
classpath "org.ajoberstar:grgit:1.1.0"
|
||||
classpath "net.i2p.crypto:eddsa:$eddsa_version" // Needed for ServiceIdentityGenerator in the build environment.
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
gradlePluginsVersion=0.12.0
|
||||
gradlePluginsVersion=0.12.1
|
||||
kotlinVersion=1.1.2
|
||||
guavaVersion=21.0
|
||||
bouncycastleVersion=1.56
|
||||
|
15
cordform-common/build.gradle
Normal file
15
cordform-common/build.gradle
Normal file
@ -0,0 +1,15 @@
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'maven-publish'
|
||||
apply plugin: 'net.corda.plugins.publish-utils'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// TypeSafe Config: for simple and human friendly config files.
|
||||
compile "com.typesafe:config:$typesafe_config_version"
|
||||
|
||||
// Bouncy Castle: for X.500 distinguished name manipulation
|
||||
compile "org.bouncycastle:bcprov-jdk15on:$bouncycastle_version"
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package net.corda.cordform;
|
||||
|
||||
import org.bouncycastle.asn1.x500.X500Name;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public interface CordformContext {
|
||||
Path baseDirectory(X500Name nodeName);
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package net.corda.cordform;
|
||||
|
||||
import org.bouncycastle.asn1.x500.X500Name;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public abstract class CordformDefinition {
|
||||
public final Path driverDirectory;
|
||||
public final ArrayList<Consumer<? super CordformNode>> nodeConfigurers = new ArrayList<>();
|
||||
public final X500Name networkMapNodeName;
|
||||
|
||||
public CordformDefinition(Path driverDirectory, X500Name networkMapNodeName) {
|
||||
this.driverDirectory = driverDirectory;
|
||||
this.networkMapNodeName = networkMapNodeName;
|
||||
}
|
||||
|
||||
public void addNode(Consumer<? super CordformNode> configurer) {
|
||||
nodeConfigurers.add(configurer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make arbitrary changes to the node directories before they are started.
|
||||
* @param context Lookup of node directory by node name.
|
||||
*/
|
||||
public abstract void setup(CordformContext context);
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
package net.corda.cordform;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
import com.typesafe.config.Config;
|
||||
import com.typesafe.config.ConfigFactory;
|
||||
import com.typesafe.config.ConfigValueFactory;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class CordformNode {
|
||||
protected static final String DEFAULT_HOST = "localhost";
|
||||
|
||||
/**
|
||||
* Name of the node.
|
||||
*/
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of advertised services ID strings.
|
||||
*/
|
||||
public List<String> advertisedServices = emptyList();
|
||||
|
||||
/**
|
||||
* If running a distributed notary, a list of node addresses for joining the Raft cluster
|
||||
*/
|
||||
public List<String> notaryClusterAddresses = emptyList();
|
||||
/**
|
||||
* Set the RPC users for this node. This configuration block allows arbitrary configuration.
|
||||
* The recommended current structure is:
|
||||
* [[['username': "username_here", 'password': "password_here", 'permissions': ["permissions_here"]]]
|
||||
* The above is a list to a map of keys to values using Groovy map and list shorthands.
|
||||
*
|
||||
* Incorrect configurations will not cause a DSL error.
|
||||
*/
|
||||
public List<Map<String, Object>> rpcUsers = emptyList();
|
||||
|
||||
protected Config config = ConfigFactory.empty();
|
||||
|
||||
public Config getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the node.
|
||||
*
|
||||
* @param name The node name.
|
||||
*/
|
||||
public void name(String name) {
|
||||
this.name = name;
|
||||
config = config.withValue("myLegalName", ConfigValueFactory.fromAnyRef(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the nearest city to the node.
|
||||
*
|
||||
* @param nearestCity The name of the nearest city to the node.
|
||||
*/
|
||||
public void nearestCity(String nearestCity) {
|
||||
config = config.withValue("nearestCity", ConfigValueFactory.fromAnyRef(nearestCity));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Artemis P2P port for this node.
|
||||
*
|
||||
* @param p2pPort The Artemis messaging queue port.
|
||||
*/
|
||||
public void p2pPort(Integer p2pPort) {
|
||||
config = config.withValue("p2pAddress", ConfigValueFactory.fromAnyRef(DEFAULT_HOST + ':' + p2pPort));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Artemis RPC port for this node.
|
||||
*
|
||||
* @param rpcPort The Artemis RPC queue port.
|
||||
*/
|
||||
public void rpcPort(Integer rpcPort) {
|
||||
config = config.withValue("rpcAddress", ConfigValueFactory.fromAnyRef(DEFAULT_HOST + ':' + rpcPort));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the port which to bind the Copycat (Raft) node to
|
||||
*
|
||||
* @param notaryPort The Raft port.
|
||||
*/
|
||||
public void notaryNodePort(Integer notaryPort) {
|
||||
config = config.withValue("notaryNodeAddress", ConfigValueFactory.fromAnyRef(DEFAULT_HOST + ':' + notaryPort));
|
||||
}
|
||||
}
|
@ -63,7 +63,7 @@ dependencies {
|
||||
compile "com.fasterxml.jackson.core:jackson-databind:${jackson_version}"
|
||||
|
||||
// Java ed25519 implementation. See https://github.com/str4d/ed25519-java/
|
||||
compile 'net.i2p.crypto:eddsa:0.2.0'
|
||||
compile "net.i2p.crypto:eddsa:$eddsa_version"
|
||||
|
||||
// Bouncy castle support needed for X509 certificate manipulation
|
||||
compile "org.bouncycastle:bcprov-jdk15on:${bouncycastle_version}"
|
||||
|
@ -113,8 +113,17 @@ infix fun <T> ListenableFuture<T>.success(body: (T) -> Unit): ListenableFuture<T
|
||||
infix fun <T> ListenableFuture<T>.failure(body: (Throwable) -> Unit): ListenableFuture<T> = apply { failure(RunOnCallerThread, body) }
|
||||
@Suppress("UNCHECKED_CAST") // We need the awkward cast because otherwise F cannot be nullable, even though it's safe.
|
||||
infix fun <F, T> ListenableFuture<F>.map(mapper: (F) -> T): ListenableFuture<T> = Futures.transform(this, { (mapper as (F?) -> T)(it) })
|
||||
|
||||
infix fun <F, T> ListenableFuture<F>.flatMap(mapper: (F) -> ListenableFuture<T>): ListenableFuture<T> = Futures.transformAsync(this) { mapper(it!!) }
|
||||
|
||||
inline fun <T, reified R> Collection<T>.mapToArray(transform: (T) -> R) = run {
|
||||
val iterator = iterator()
|
||||
var expected = 0
|
||||
Array(size) {
|
||||
expected++ == it || throw UnsupportedOperationException("Array constructor is non-sequential!")
|
||||
transform(iterator.next())
|
||||
}
|
||||
}
|
||||
|
||||
/** Executes the given block and sets the future to either the result, or any exception that was thrown. */
|
||||
inline fun <T> SettableFuture<T>.catch(block: () -> T) {
|
||||
try {
|
||||
|
@ -8,6 +8,8 @@ buildscript {
|
||||
|
||||
// If you bump this version you must re-bootstrap the codebase. See the README for more information.
|
||||
ext.gradle_plugins_version = constants.getProperty("gradlePluginsVersion")
|
||||
ext.bouncycastle_version = constants.getProperty("bouncycastleVersion")
|
||||
ext.typesafe_config_version = constants.getProperty("typesafeConfigVersion")
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
@ -37,7 +39,7 @@ bintrayConfig {
|
||||
projectUrl = 'https://github.com/corda/corda'
|
||||
gpgSign = true
|
||||
gpgPassphrase = System.getenv('CORDA_BINTRAY_GPG_PASSPHRASE')
|
||||
publications = ['cordformation', 'quasar-utils']
|
||||
publications = ['cordformation', 'quasar-utils', 'cordform-common']
|
||||
license {
|
||||
name = 'Apache-2.0'
|
||||
url = 'https://www.apache.org/licenses/LICENSE-2.0'
|
||||
|
@ -4,8 +4,6 @@ buildscript {
|
||||
file("$projectDir/../../constants.properties").withInputStream { constants.load(it) }
|
||||
|
||||
ext.kotlin_version = constants.getProperty("kotlinVersion")
|
||||
ext.bouncycastle_version = constants.getProperty("bouncycastleVersion")
|
||||
ext.typesafe_config_version = constants.getProperty("typesafeConfigVersion")
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
@ -46,11 +44,7 @@ dependencies {
|
||||
|
||||
noderunner "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version"
|
||||
|
||||
// TypeSafe Config: for simple and human friendly config files.
|
||||
compile "com.typesafe:config:$typesafe_config_version"
|
||||
|
||||
// Bouncy Castle: for X.500 distinguished name manipulation
|
||||
compile "org.bouncycastle:bcprov-jdk15on:${bouncycastle_version}"
|
||||
compile project(':cordform-common')
|
||||
}
|
||||
|
||||
task createNodeRunner(type: Jar, dependsOn: [classes]) {
|
||||
|
@ -1,19 +1,28 @@
|
||||
package net.corda.plugins
|
||||
|
||||
import static org.gradle.api.tasks.SourceSet.MAIN_SOURCE_SET_NAME
|
||||
import net.corda.cordform.CordformContext
|
||||
import net.corda.cordform.CordformDefinition
|
||||
import org.apache.tools.ant.filters.FixCrLfFilter
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.plugins.JavaPluginConvention
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
|
||||
/**
|
||||
* Creates nodes based on the configuration of this task in the gradle configuration DSL.
|
||||
*
|
||||
* See documentation for examples.
|
||||
*/
|
||||
class Cordform extends DefaultTask {
|
||||
protected Path directory = Paths.get("./build/nodes")
|
||||
protected List<Node> nodes = new ArrayList<Node>()
|
||||
/**
|
||||
* Optionally the name of a CordformDefinition subclass to which all configuration will be delegated.
|
||||
*/
|
||||
String definitionClass
|
||||
protected def directory = Paths.get("build", "nodes")
|
||||
private def nodes = new ArrayList<Node>()
|
||||
protected String networkMapNodeName
|
||||
|
||||
/**
|
||||
@ -42,7 +51,7 @@ class Cordform extends DefaultTask {
|
||||
* @param configureClosure A node configuration that will be deployed.
|
||||
*/
|
||||
void node(Closure configureClosure) {
|
||||
nodes << project.configure(new Node(project), configureClosure)
|
||||
nodes << (Node) project.configure(new Node(project), configureClosure)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -51,7 +60,7 @@ class Cordform extends DefaultTask {
|
||||
* @param name The name of the node as specified in the node configuration DSL.
|
||||
* @return A node instance.
|
||||
*/
|
||||
protected Node getNodeByName(String name) {
|
||||
private Node getNodeByName(String name) {
|
||||
for(Node node : nodes) {
|
||||
if(node.name == name) {
|
||||
return node
|
||||
@ -64,7 +73,7 @@ class Cordform extends DefaultTask {
|
||||
/**
|
||||
* Installs the run script into the nodes directory.
|
||||
*/
|
||||
protected void installRunScript() {
|
||||
private void installRunScript() {
|
||||
project.copy {
|
||||
from Cordformation.getPluginFile(project, "net/corda/plugins/runnodes.jar")
|
||||
fileMode 0755
|
||||
@ -85,19 +94,49 @@ class Cordform extends DefaultTask {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The definitionClass needn't be compiled until just before our build method, so we load it manually via sourceSets.main.runtimeClasspath.
|
||||
*/
|
||||
private CordformDefinition loadCordformDefinition() {
|
||||
def plugin = project.convention.getPlugin(JavaPluginConvention.class)
|
||||
def classpath = plugin.sourceSets.getByName(MAIN_SOURCE_SET_NAME).runtimeClasspath
|
||||
URL[] urls = classpath.files.collect { it.toURI().toURL() }
|
||||
(CordformDefinition) new URLClassLoader(urls, CordformDefinition.classLoader).loadClass(definitionClass).newInstance()
|
||||
}
|
||||
|
||||
/**
|
||||
* This task action will create and install the nodes based on the node configurations added.
|
||||
*/
|
||||
@TaskAction
|
||||
void build() {
|
||||
String networkMapNodeName
|
||||
if (null != definitionClass) {
|
||||
def cd = loadCordformDefinition()
|
||||
networkMapNodeName = cd.networkMapNodeName.toString()
|
||||
cd.nodeConfigurers.each { nc ->
|
||||
node { Node it ->
|
||||
nc.accept it
|
||||
it.rootDir directory
|
||||
}
|
||||
}
|
||||
cd.setup new CordformContext() {
|
||||
Path baseDirectory(X500Name nodeName) {
|
||||
project.projectDir.toPath().resolve(getNodeByName(nodeName.toString()).nodeDir.toPath())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
networkMapNodeName = this.networkMapNodeName
|
||||
nodes.each {
|
||||
it.rootDir directory
|
||||
}
|
||||
}
|
||||
installRunScript()
|
||||
Node networkMapNode = getNodeByName(networkMapNodeName)
|
||||
def networkMapNode = getNodeByName(networkMapNodeName)
|
||||
nodes.each {
|
||||
if(it != networkMapNode) {
|
||||
it.networkMapAddress(networkMapNode.getP2PAddress(), networkMapNodeName)
|
||||
}
|
||||
it.build(directory.toFile())
|
||||
it.build()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,7 @@ class Cordformation implements Plugin<Project> {
|
||||
* @param filePathInJar The file in the JAR, relative to root, you wish to access.
|
||||
* @return A file handle to the file in the JAR.
|
||||
*/
|
||||
static File getPluginFile(Project project, String filePathInJar) {
|
||||
protected static File getPluginFile(Project project, String filePathInJar) {
|
||||
return project.rootProject.resources.text.fromArchiveEntry(project.rootProject.buildscript.configurations.classpath.find {
|
||||
it.name.contains('cordformation')
|
||||
}, filePathInJar).asFile()
|
||||
|
@ -1,33 +1,21 @@
|
||||
package net.corda.plugins
|
||||
|
||||
import com.typesafe.config.*
|
||||
import net.corda.cordform.CordformNode
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import org.bouncycastle.asn1.x500.style.BCStyle
|
||||
import org.gradle.api.Project
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
|
||||
/**
|
||||
* Represents a node that will be installed.
|
||||
*/
|
||||
class Node {
|
||||
class Node extends CordformNode {
|
||||
static final String NODEJAR_NAME = 'corda.jar'
|
||||
static final String WEBJAR_NAME = 'corda-webserver.jar'
|
||||
static final String DEFAULT_HOST = 'localhost'
|
||||
|
||||
/**
|
||||
* Name of the node.
|
||||
*/
|
||||
public String name
|
||||
/**
|
||||
* A list of advertised services ID strings.
|
||||
*/
|
||||
protected List<String> advertisedServices = []
|
||||
|
||||
/**
|
||||
* If running a distributed notary, a list of node addresses for joining the Raft cluster
|
||||
*/
|
||||
protected List<String> notaryClusterAddresses = []
|
||||
/**
|
||||
* Set the list of CorDapps to install to the plugins directory. Each cordapp is a fully qualified Maven
|
||||
* dependency name, eg: com.example:product-name:0.1
|
||||
@ -35,39 +23,10 @@ class Node {
|
||||
* @note Your app will be installed by default and does not need to be included here.
|
||||
*/
|
||||
protected List<String> cordapps = []
|
||||
/**
|
||||
* Set the RPC users for this node. This configuration block allows arbitrary configuration.
|
||||
* The recommended current structure is:
|
||||
* [[['username': "username_here", 'password': "password_here", 'permissions': ["permissions_here"]]]
|
||||
* The above is a list to a map of keys to values using Groovy map and list shorthands.
|
||||
*
|
||||
* @note Incorrect configurations will not cause a DSL error.
|
||||
*/
|
||||
protected List<Map<String, Object>> rpcUsers = []
|
||||
|
||||
private Config config = ConfigFactory.empty()
|
||||
private File nodeDir
|
||||
protected File nodeDir
|
||||
private Project project
|
||||
|
||||
/**
|
||||
* Set the name of the node.
|
||||
*
|
||||
* @param name The node name.
|
||||
*/
|
||||
void name(String name) {
|
||||
this.name = name
|
||||
config = config.withValue("myLegalName", ConfigValueFactory.fromAnyRef(name))
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the nearest city to the node.
|
||||
*
|
||||
* @param nearestCity The name of the nearest city to the node.
|
||||
*/
|
||||
void nearestCity(String nearestCity) {
|
||||
config = config.withValue("nearestCity", ConfigValueFactory.fromAnyRef(nearestCity))
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this node will use HTTPS communication.
|
||||
*
|
||||
@ -88,26 +47,6 @@ class Node {
|
||||
config = config.withValue("useTestClock", ConfigValueFactory.fromAnyRef(useTestClock))
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Artemis P2P port for this node.
|
||||
*
|
||||
* @param p2pPort The Artemis messaging queue port.
|
||||
*/
|
||||
void p2pPort(Integer p2pPort) {
|
||||
config = config.withValue("p2pAddress",
|
||||
ConfigValueFactory.fromAnyRef("$DEFAULT_HOST:$p2pPort".toString()))
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Artemis RPC port for this node.
|
||||
*
|
||||
* @param rpcPort The Artemis RPC queue port.
|
||||
*/
|
||||
void rpcPort(Integer rpcPort) {
|
||||
config = config.withValue("rpcAddress",
|
||||
ConfigValueFactory.fromAnyRef("$DEFAULT_HOST:$rpcPort".toString()))
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the HTTP web server port for this node.
|
||||
*
|
||||
@ -118,14 +57,6 @@ class Node {
|
||||
ConfigValueFactory.fromAnyRef("$DEFAULT_HOST:$webPort".toString()))
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the port which to bind the Copycat (Raft) node to
|
||||
*/
|
||||
void notaryNodePort(Integer notaryPort) {
|
||||
config = config.withValue("notaryNodeAddress",
|
||||
ConfigValueFactory.fromAnyRef("$DEFAULT_HOST:$notaryPort".toString()))
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the network map address for this node.
|
||||
*
|
||||
@ -155,16 +86,19 @@ class Node {
|
||||
this.project = project
|
||||
}
|
||||
|
||||
void build(File rootDir) {
|
||||
protected void rootDir(Path rootDir) {
|
||||
def dirName
|
||||
try {
|
||||
X500Name x500Name = new X500Name(name)
|
||||
dirName = x500Name.getRDNs(BCStyle.CN).getAt(0).getFirst().getValue().toString()
|
||||
} catch(IllegalArgumentException ex) {
|
||||
} catch(IllegalArgumentException ignore) {
|
||||
// Can't parse as an X500 name, use the full string
|
||||
dirName = name
|
||||
}
|
||||
nodeDir = new File(rootDir, dirName.replaceAll("\\s",""))
|
||||
nodeDir = new File(rootDir.toFile(), dirName.replaceAll("\\s",""))
|
||||
}
|
||||
|
||||
protected void build() {
|
||||
configureRpcUsers()
|
||||
installCordaJar()
|
||||
installWebserverJar()
|
||||
|
@ -1,4 +1,6 @@
|
||||
rootProject.name = 'corda-gradle-plugins'
|
||||
include 'publish-utils'
|
||||
include 'quasar-utils'
|
||||
include 'cordformation'
|
||||
include 'cordformation'
|
||||
include 'cordform-common'
|
||||
project(':cordform-common').projectDir = new File("$settingsDir/../cordform-common")
|
||||
|
@ -54,6 +54,7 @@ dependencies {
|
||||
compile project(':node-schemas')
|
||||
compile project(':node-api')
|
||||
compile project(':client:rpc')
|
||||
compile project(':cordform-common')
|
||||
|
||||
compile "com.google.code.findbugs:jsr305:3.0.1"
|
||||
|
||||
|
@ -19,6 +19,10 @@ import net.corda.core.node.services.ServiceType
|
||||
import net.corda.core.utilities.*
|
||||
import net.corda.node.LOGS_DIRECTORY_NAME
|
||||
import net.corda.node.services.config.*
|
||||
import net.corda.node.services.config.ConfigHelper
|
||||
import net.corda.node.services.config.FullNodeConfiguration
|
||||
import net.corda.node.services.config.VerifierType
|
||||
import net.corda.node.services.config.configOf
|
||||
import net.corda.node.services.network.NetworkMapService
|
||||
import net.corda.node.services.transactions.RaftValidatingNotaryService
|
||||
import net.corda.node.utilities.ServiceIdentityGenerator
|
||||
@ -26,6 +30,8 @@ import net.corda.nodeapi.ArtemisMessagingComponent
|
||||
import net.corda.nodeapi.User
|
||||
import net.corda.nodeapi.config.SSLConfiguration
|
||||
import net.corda.nodeapi.config.parseAs
|
||||
import net.corda.cordform.CordformNode
|
||||
import net.corda.cordform.CordformContext
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
@ -57,7 +63,7 @@ private val log: Logger = loggerFor<DriverDSL>()
|
||||
/**
|
||||
* This is the interface that's exposed to DSL users.
|
||||
*/
|
||||
interface DriverDSLExposedInterface {
|
||||
interface DriverDSLExposedInterface : CordformContext {
|
||||
/**
|
||||
* Starts a [net.corda.node.internal.Node] in a separate process.
|
||||
*
|
||||
@ -74,6 +80,8 @@ interface DriverDSLExposedInterface {
|
||||
verifierType: VerifierType = VerifierType.InMemory,
|
||||
customOverrides: Map<String, Any?> = emptyMap()): ListenableFuture<NodeHandle>
|
||||
|
||||
fun startNodes(nodes: List<CordformNode>): List<ListenableFuture<NodeHandle>>
|
||||
|
||||
/**
|
||||
* Starts a distributed notary cluster.
|
||||
*
|
||||
@ -100,7 +108,7 @@ interface DriverDSLExposedInterface {
|
||||
|
||||
/**
|
||||
* Starts a network map service node. Note that only a single one should ever be running, so you will probably want
|
||||
* to set networkMapStrategy to FalseNetworkMap in your [driver] call.
|
||||
* to set networkMapStartStrategy to Dedicated(false) in your [driver] call.
|
||||
*/
|
||||
fun startDedicatedNetworkMapService(): ListenableFuture<Unit>
|
||||
|
||||
@ -166,11 +174,6 @@ sealed class PortAllocation {
|
||||
}
|
||||
}
|
||||
|
||||
sealed class NetworkMapStartStrategy {
|
||||
data class Dedicated(val startAutomatically: Boolean) : NetworkMapStartStrategy()
|
||||
data class Nominated(val legalName: X500Name, val address: HostAndPort) : NetworkMapStartStrategy()
|
||||
}
|
||||
|
||||
/**
|
||||
* [driver] allows one to start up nodes like this:
|
||||
* driver {
|
||||
@ -418,7 +421,6 @@ class DriverDSL(
|
||||
val networkMapStartStrategy: NetworkMapStartStrategy
|
||||
) : DriverDSLInternalInterface {
|
||||
private val dedicatedNetworkMapAddress = portAllocation.nextHostAndPort()
|
||||
private val dedicatedNetworkMapLegalName = DUMMY_MAP.name
|
||||
var _executorService: ListeningScheduledExecutorService? = null
|
||||
val executorService get() = _executorService!!
|
||||
var _shutdownManager: ShutdownManager? = null
|
||||
@ -471,57 +473,59 @@ class DriverDSL(
|
||||
}
|
||||
}
|
||||
|
||||
// TODO move to cmopanion
|
||||
private fun toServiceConfig(address: HostAndPort, legalName: X500Name) = mapOf(
|
||||
"address" to address.toString(),
|
||||
"legalName" to legalName.toString()
|
||||
)
|
||||
private fun networkMapServiceConfigLookup(networkMapCandidates: List<CordformNode>): (X500Name) -> Map<String, String>? {
|
||||
return networkMapStartStrategy.run {
|
||||
when (this) {
|
||||
is NetworkMapStartStrategy.Dedicated -> {
|
||||
serviceConfig(dedicatedNetworkMapAddress).let {
|
||||
{ _: X500Name -> it }
|
||||
}
|
||||
}
|
||||
is NetworkMapStartStrategy.Nominated -> {
|
||||
serviceConfig(HostAndPort.fromString(networkMapCandidates.filter {
|
||||
it.name == legalName.toString()
|
||||
}.single().config.getString("p2pAddress"))).let {
|
||||
{ nodeName: X500Name -> if (nodeName == legalName) null else it }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun startNode(
|
||||
providedName: X500Name?,
|
||||
advertisedServices: Set<ServiceInfo>,
|
||||
rpcUsers: List<User>,
|
||||
verifierType: VerifierType,
|
||||
customOverrides: Map<String, Any?>
|
||||
): ListenableFuture<NodeHandle> {
|
||||
customOverrides: Map<String, Any?>): ListenableFuture<NodeHandle> {
|
||||
val p2pAddress = portAllocation.nextHostAndPort()
|
||||
val rpcAddress = portAllocation.nextHostAndPort()
|
||||
val webAddress = portAllocation.nextHostAndPort()
|
||||
val debugPort = if (isDebug) debugPortAllocation.nextPort() else null
|
||||
// TODO: Derive name from the full picked name, don't just wrap the common name
|
||||
val name = providedName ?: X509Utilities.getDevX509Name("${oneOf(names).commonName}-${p2pAddress.port}")
|
||||
val baseDirectory = driverDirectory / name.commonName
|
||||
val configOverrides = configOf(
|
||||
return startNode(p2pAddress, webAddress, name, configOf(
|
||||
"myLegalName" to name.toString(),
|
||||
"p2pAddress" to p2pAddress.toString(),
|
||||
"rpcAddress" to rpcAddress.toString(),
|
||||
"webAddress" to webAddress.toString(),
|
||||
"extraAdvertisedServiceIds" to advertisedServices.map { it.toString() },
|
||||
"networkMapService" to when (networkMapStartStrategy) {
|
||||
is NetworkMapStartStrategy.Dedicated -> toServiceConfig(dedicatedNetworkMapAddress, dedicatedNetworkMapLegalName)
|
||||
is NetworkMapStartStrategy.Nominated -> networkMapStartStrategy.run {
|
||||
if (name != legalName) {
|
||||
toServiceConfig(address, legalName)
|
||||
} else {
|
||||
p2pAddress == address || throw IllegalArgumentException("Passed-in address $address of nominated network map $legalName is wrong, it should be: $p2pAddress")
|
||||
null
|
||||
}
|
||||
}
|
||||
},
|
||||
"networkMapService" to networkMapServiceConfigLookup(emptyList())(name),
|
||||
"useTestClock" to useTestClock,
|
||||
"rpcUsers" to rpcUsers.map { it.toMap() },
|
||||
"verifierType" to verifierType.name
|
||||
) + customOverrides
|
||||
) + customOverrides)
|
||||
}
|
||||
|
||||
private fun startNode(p2pAddress: HostAndPort, webAddress: HostAndPort, nodeName: X500Name, configOverrides: Config) = run {
|
||||
val debugPort = if (isDebug) debugPortAllocation.nextPort() else null
|
||||
val config = ConfigHelper.loadConfig(
|
||||
baseDirectory = baseDirectory,
|
||||
baseDirectory = baseDirectory(nodeName),
|
||||
allowMissingConfig = true,
|
||||
configOverrides = configOverrides)
|
||||
val configuration = config.parseAs<FullNodeConfiguration>()
|
||||
|
||||
val processFuture = startNode(executorService, configuration, config, quasarJarPath, debugPort, systemProperties)
|
||||
registerProcess(processFuture)
|
||||
return processFuture.flatMap { process ->
|
||||
processFuture.flatMap { process ->
|
||||
// We continue to use SSL enabled port for RPC when its for node user.
|
||||
establishRpc(p2pAddress, configuration).flatMap { rpc ->
|
||||
rpc.waitUntilRegisteredWithNetworkMap().map {
|
||||
@ -531,6 +535,22 @@ class DriverDSL(
|
||||
}
|
||||
}
|
||||
|
||||
override fun startNodes(nodes: List<CordformNode>): List<ListenableFuture<NodeHandle>> {
|
||||
val networkMapServiceConfigLookup = networkMapServiceConfigLookup(nodes)
|
||||
return nodes.map {
|
||||
val p2pAddress = HostAndPort.fromString(it.config.getString("p2pAddress")); portAllocation.nextHostAndPort()
|
||||
portAllocation.nextHostAndPort() // rpcAddress
|
||||
val webAddress = portAllocation.nextHostAndPort()
|
||||
val name = X500Name(it.name)
|
||||
startNode(p2pAddress, webAddress, name, it.config + mapOf(
|
||||
"extraAdvertisedServiceIds" to it.advertisedServices,
|
||||
"networkMapService" to networkMapServiceConfigLookup(name),
|
||||
"rpcUsers" to it.rpcUsers,
|
||||
"notaryClusterAddresses" to it.notaryClusterAddresses
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
override fun startNotaryCluster(
|
||||
notaryName: X500Name,
|
||||
clusterSize: Int,
|
||||
@ -539,7 +559,7 @@ class DriverDSL(
|
||||
rpcUsers: List<User>
|
||||
): ListenableFuture<Pair<Party, List<NodeHandle>>> {
|
||||
val nodeNames = (1..clusterSize).map { DUMMY_NOTARY.name.appendToCommonName(it.toString()) }
|
||||
val paths = nodeNames.map { driverDirectory / it.commonName }
|
||||
val paths = nodeNames.map { baseDirectory(it) }
|
||||
ServiceIdentityGenerator.generateToDisk(paths, type.id, notaryName)
|
||||
|
||||
val serviceInfo = ServiceInfo(type, notaryName)
|
||||
@ -592,20 +612,22 @@ class DriverDSL(
|
||||
Executors.newScheduledThreadPool(2, ThreadFactoryBuilder().setNameFormat("driver-pool-thread-%d").build())
|
||||
)
|
||||
_shutdownManager = ShutdownManager(executorService)
|
||||
if (networkMapStartStrategy is NetworkMapStartStrategy.Dedicated && networkMapStartStrategy.startAutomatically) {
|
||||
if (networkMapStartStrategy.startDedicated) {
|
||||
startDedicatedNetworkMapService()
|
||||
}
|
||||
}
|
||||
|
||||
override fun baseDirectory(nodeName: X500Name) = driverDirectory / nodeName.commonName.replace(WHITESPACE, "")
|
||||
|
||||
override fun startDedicatedNetworkMapService(): ListenableFuture<Unit> {
|
||||
val debugPort = if (isDebug) debugPortAllocation.nextPort() else null
|
||||
val apiAddress = portAllocation.nextHostAndPort().toString()
|
||||
val baseDirectory = driverDirectory / dedicatedNetworkMapLegalName.commonName
|
||||
val networkMapLegalName = networkMapStartStrategy.legalName
|
||||
val config = ConfigHelper.loadConfig(
|
||||
baseDirectory = baseDirectory,
|
||||
baseDirectory = baseDirectory(networkMapLegalName),
|
||||
allowMissingConfig = true,
|
||||
configOverrides = configOf(
|
||||
"myLegalName" to dedicatedNetworkMapLegalName.toString(),
|
||||
"myLegalName" to networkMapLegalName.toString(),
|
||||
// TODO: remove the webAddress as NMS doesn't need to run a web server. This will cause all
|
||||
// node port numbers to be shifted, so all demos and docs need to be updated accordingly.
|
||||
"webAddress" to apiAddress,
|
||||
|
@ -0,0 +1,23 @@
|
||||
package net.corda.node.driver
|
||||
|
||||
import com.google.common.net.HostAndPort
|
||||
import net.corda.core.utilities.DUMMY_MAP
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
|
||||
sealed class NetworkMapStartStrategy {
|
||||
internal abstract val startDedicated: Boolean
|
||||
internal abstract val legalName: X500Name
|
||||
internal fun serviceConfig(address: HostAndPort) = mapOf(
|
||||
"address" to address.toString(),
|
||||
"legalName" to legalName.toString()
|
||||
)
|
||||
|
||||
class Dedicated(startAutomatically: Boolean) : NetworkMapStartStrategy() {
|
||||
override val startDedicated = startAutomatically
|
||||
override val legalName = DUMMY_MAP.name
|
||||
}
|
||||
|
||||
class Nominated(override val legalName: X500Name) : NetworkMapStartStrategy() {
|
||||
override val startDedicated = false
|
||||
}
|
||||
}
|
@ -4,12 +4,12 @@ import net.corda.core.crypto.CompositeKey
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.crypto.generateKeyPair
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.core.serialization.storageKryo
|
||||
import net.corda.core.utilities.loggerFor
|
||||
import net.corda.core.utilities.trace
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
|
||||
object ServiceIdentityGenerator {
|
||||
private val log = loggerFor<ServiceIdentityGenerator>()
|
||||
@ -36,17 +36,8 @@ object ServiceIdentityGenerator {
|
||||
val privateKeyFile = "$serviceId-private-key"
|
||||
val publicKeyFile = "$serviceId-public"
|
||||
notaryParty.writeToFile(dir.resolve(publicKeyFile))
|
||||
keyPair.serialize().writeToFile(dir.resolve(privateKeyFile))
|
||||
// Use storageKryo as our whitelist is not available in the gradle build environment:
|
||||
keyPair.serialize(storageKryo()).writeToFile(dir.resolve(privateKeyFile))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val dirs = args[0].split("|").map { Paths.get(it) }
|
||||
val serviceId = args[1]
|
||||
val serviceName = X500Name(args[2])
|
||||
val quorumSize = args.getOrNull(3)?.toInt() ?: 1
|
||||
|
||||
println("Generating service identity for \"$serviceName\"")
|
||||
ServiceIdentityGenerator.generateToDisk(dirs, serviceId, serviceName, quorumSize)
|
||||
}
|
@ -8,13 +8,6 @@ apply plugin: 'net.corda.plugins.publish-utils'
|
||||
apply plugin: 'net.corda.plugins.cordformation'
|
||||
apply plugin: 'maven-publish'
|
||||
|
||||
ext {
|
||||
deployTo = "build/nodes"
|
||||
notaryType = "corda.notary.validating.raft"
|
||||
notaryName = "CN=Raft,O=R3,OU=corda,L=Zurich,C=CH"
|
||||
advertisedNotary = "$notaryType|$notaryName"
|
||||
}
|
||||
|
||||
configurations {
|
||||
integrationTestCompile.extendsFrom testCompile
|
||||
integrationTestRuntime.extendsFrom testRuntime
|
||||
@ -31,6 +24,7 @@ dependencies {
|
||||
compile project(':client:jfx')
|
||||
compile project(':client:rpc')
|
||||
compile project(':test-utils')
|
||||
compile project(':cordform-common')
|
||||
|
||||
// Javax is required for webapis
|
||||
compile "org.glassfish.jersey.core:jersey-server:${jersey_version}"
|
||||
@ -55,76 +49,15 @@ publishing {
|
||||
}
|
||||
}
|
||||
|
||||
task cleanNodes {
|
||||
doLast {
|
||||
delete deployTo
|
||||
}
|
||||
task deployNodesSingle(type: Cordform, dependsOn: 'jar') {
|
||||
definitionClass = 'net.corda.notarydemo.SingleNotaryCordform'
|
||||
}
|
||||
|
||||
task generateNotaryIdentity(type: JavaExec, dependsOn: 'cleanNodes') {
|
||||
classpath = sourceSets.main.runtimeClasspath
|
||||
main = "net.corda.node.utilities.ServiceIdentityGeneratorKt"
|
||||
def nodeDirs = ["$deployTo/Notary1",
|
||||
"$deployTo/Notary2",
|
||||
"$deployTo/Notary3"].join("|")
|
||||
args = [nodeDirs, notaryType, notaryName]
|
||||
}
|
||||
|
||||
task deployNodes(type: Cordform, dependsOn: ['jar', generateNotaryIdentity]) {
|
||||
directory deployTo
|
||||
networkMap "CN=Notary 1,O=R3,OU=corda,L=London,C=UK"
|
||||
node {
|
||||
name "CN=Alice Corp,O=Alice Corp,L=London,C=UK"
|
||||
nearestCity "London"
|
||||
advertisedServices = []
|
||||
p2pPort 10002
|
||||
rpcPort 10003
|
||||
cordapps = []
|
||||
rpcUsers = [['username': "demo", 'password': "demo", 'permissions': [
|
||||
'StartFlow.net.corda.notarydemo.flows.DummyIssueAndMove',
|
||||
'StartFlow.net.corda.notarydemo.flows.RPCStartableNotaryFlowClient'
|
||||
]]]
|
||||
}
|
||||
node {
|
||||
name "CN=Bob Plc,O=Bob Plc,L=London,C=UK"
|
||||
nearestCity "New York"
|
||||
advertisedServices = []
|
||||
p2pPort 10005
|
||||
rpcPort 10006
|
||||
cordapps = []
|
||||
}
|
||||
node {
|
||||
name "CN=Notary 1,O=R3,OU=corda,L=London,C=UK"
|
||||
nearestCity "London"
|
||||
advertisedServices = [advertisedNotary]
|
||||
p2pPort 10009
|
||||
rpcPort 10010
|
||||
cordapps = []
|
||||
notaryNodePort 10008
|
||||
}
|
||||
node {
|
||||
name "CN=Notary 2,O=R3,OU=corda,L=London,C=UK"
|
||||
nearestCity "London"
|
||||
advertisedServices = [advertisedNotary]
|
||||
p2pPort 10013
|
||||
rpcPort 10014
|
||||
cordapps = []
|
||||
notaryNodePort 10012
|
||||
notaryClusterAddresses = ["localhost:10008"]
|
||||
}
|
||||
node {
|
||||
name "CN=Notary 3,O=R3,OU=corda,L=London,C=UK"
|
||||
nearestCity "London"
|
||||
advertisedServices = [advertisedNotary]
|
||||
p2pPort 10017
|
||||
rpcPort 10018
|
||||
cordapps = []
|
||||
notaryNodePort 10016
|
||||
notaryClusterAddresses = ["localhost:10008"]
|
||||
}
|
||||
task deployNodesRaft(type: Cordform, dependsOn: 'jar') {
|
||||
definitionClass = 'net.corda.notarydemo.RaftNotaryCordform'
|
||||
}
|
||||
|
||||
task notarise(type: JavaExec) {
|
||||
classpath = sourceSets.main.runtimeClasspath
|
||||
main = 'net.corda.notarydemo.NotaryDemoKt'
|
||||
main = 'net.corda.notarydemo.NotariseKt'
|
||||
}
|
||||
|
@ -0,0 +1,28 @@
|
||||
package net.corda.demorun
|
||||
|
||||
import net.corda.node.driver.NetworkMapStartStrategy
|
||||
import net.corda.node.driver.PortAllocation
|
||||
import net.corda.node.driver.driver
|
||||
import net.corda.cordform.CordformDefinition
|
||||
import net.corda.cordform.CordformNode
|
||||
|
||||
fun CordformDefinition.node(configure: CordformNode.() -> Unit) = addNode { cordformNode -> cordformNode.configure() }
|
||||
|
||||
fun CordformDefinition.clean() {
|
||||
System.err.println("Deleting: $driverDirectory")
|
||||
driverDirectory.toFile().deleteRecursively()
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and starts all nodes required for the demo.
|
||||
*/
|
||||
fun CordformDefinition.runNodes() = driver(
|
||||
isDebug = true,
|
||||
driverDirectory = driverDirectory,
|
||||
networkMapStartStrategy = NetworkMapStartStrategy.Nominated(networkMapNodeName),
|
||||
portAllocation = PortAllocation.Incremental(10001)
|
||||
) {
|
||||
setup(this)
|
||||
startNodes(nodeConfigurers.map { configurer -> CordformNode().also { configurer.accept(it) } })
|
||||
waitForAllNodesToFinish()
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package net.corda.notarydemo
|
||||
|
||||
import net.corda.demorun.clean
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
listOf(SingleNotaryCordform, RaftNotaryCordform).forEach {
|
||||
it.clean()
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
package net.corda.notarydemo
|
||||
|
||||
import com.google.common.net.HostAndPort
|
||||
import net.corda.core.crypto.appendToCommonName
|
||||
import net.corda.core.div
|
||||
import net.corda.core.utilities.ALICE
|
||||
import net.corda.core.utilities.BOB
|
||||
import net.corda.core.utilities.DUMMY_NOTARY
|
||||
import net.corda.node.driver.NetworkMapStartStrategy
|
||||
import net.corda.node.driver.PortAllocation
|
||||
import net.corda.node.driver.driver
|
||||
import net.corda.node.services.startFlowPermission
|
||||
import net.corda.node.services.transactions.RaftValidatingNotaryService
|
||||
import net.corda.nodeapi.User
|
||||
import net.corda.notarydemo.flows.DummyIssueAndMove
|
||||
import net.corda.notarydemo.flows.RPCStartableNotaryFlowClient
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
|
||||
/** Creates and starts all nodes required for the demo. */
|
||||
fun main(args: Array<String>) {
|
||||
val demoUser = listOf(User("demo", "demo", setOf(startFlowPermission<DummyIssueAndMove>(), startFlowPermission<RPCStartableNotaryFlowClient>())))
|
||||
val networkMap = NetworkMapStartStrategy.Nominated(DUMMY_NOTARY.name.appendToCommonName("1"), HostAndPort.fromParts("localhost", 10009))
|
||||
driver(isDebug = true, driverDirectory = "build" / "notary-demo-nodes", networkMapStartStrategy = networkMap, portAllocation = PortAllocation.Incremental(10001)) {
|
||||
startNode(ALICE.name, rpcUsers = demoUser)
|
||||
startNode(BOB.name)
|
||||
startNotaryCluster(X500Name("CN=Raft,O=R3,OU=corda,L=Zurich,C=CH"), clusterSize = 3, type = RaftValidatingNotaryService.type)
|
||||
waitForAllNodesToFinish()
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
package net.corda.notarydemo
|
||||
|
||||
import net.corda.core.crypto.appendToCommonName
|
||||
import net.corda.core.div
|
||||
import net.corda.core.node.services.ServiceInfo
|
||||
import net.corda.core.utilities.ALICE
|
||||
import net.corda.core.utilities.BOB
|
||||
import net.corda.core.utilities.DUMMY_NOTARY
|
||||
import net.corda.demorun.node
|
||||
import net.corda.demorun.runNodes
|
||||
import net.corda.node.services.startFlowPermission
|
||||
import net.corda.node.services.transactions.RaftValidatingNotaryService
|
||||
import net.corda.node.utilities.ServiceIdentityGenerator
|
||||
import net.corda.nodeapi.User
|
||||
import net.corda.notarydemo.flows.DummyIssueAndMove
|
||||
import net.corda.notarydemo.flows.RPCStartableNotaryFlowClient
|
||||
import net.corda.cordform.CordformDefinition
|
||||
import net.corda.cordform.CordformContext
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
|
||||
fun main(args: Array<String>) = RaftNotaryCordform.runNodes()
|
||||
|
||||
private val notaryNames = (1..3).map { DUMMY_NOTARY.name.appendToCommonName(" $it") }
|
||||
|
||||
object RaftNotaryCordform : CordformDefinition("build" / "notary-demo-nodes", notaryNames[0]) {
|
||||
private val advertisedNotary = ServiceInfo(RaftValidatingNotaryService.type, X500Name("CN=Raft,O=R3,OU=corda,L=Zurich,C=CH"))
|
||||
|
||||
init {
|
||||
node {
|
||||
name(ALICE.name.toString())
|
||||
nearestCity("London")
|
||||
p2pPort(10002)
|
||||
rpcPort(10003)
|
||||
rpcUsers = listOf(User("demo", "demo", setOf(startFlowPermission<DummyIssueAndMove>(), startFlowPermission<RPCStartableNotaryFlowClient>())).toMap())
|
||||
}
|
||||
node {
|
||||
name(BOB.name.toString())
|
||||
nearestCity("New York")
|
||||
p2pPort(10005)
|
||||
rpcPort(10006)
|
||||
}
|
||||
node {
|
||||
name(notaryNames[0].toString())
|
||||
nearestCity("London")
|
||||
advertisedServices = listOf(advertisedNotary.toString())
|
||||
p2pPort(10009)
|
||||
rpcPort(10010)
|
||||
notaryNodePort(10008)
|
||||
}
|
||||
node {
|
||||
name(notaryNames[1].toString())
|
||||
nearestCity("London")
|
||||
advertisedServices = listOf(advertisedNotary.toString())
|
||||
p2pPort(10013)
|
||||
rpcPort(10014)
|
||||
notaryNodePort(10012)
|
||||
notaryClusterAddresses = listOf("localhost:10008")
|
||||
}
|
||||
node {
|
||||
name(notaryNames[2].toString())
|
||||
nearestCity("London")
|
||||
advertisedServices = listOf(advertisedNotary.toString())
|
||||
p2pPort(10017)
|
||||
rpcPort(10018)
|
||||
notaryNodePort(10016)
|
||||
notaryClusterAddresses = listOf("localhost:10008")
|
||||
}
|
||||
}
|
||||
|
||||
override fun setup(context: CordformContext) {
|
||||
ServiceIdentityGenerator.generateToDisk(notaryNames.map { context.baseDirectory(it) }, advertisedNotary.type.id, advertisedNotary.name!!)
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package net.corda.notarydemo
|
||||
|
||||
import net.corda.core.div
|
||||
import net.corda.core.node.services.ServiceInfo
|
||||
import net.corda.core.utilities.ALICE
|
||||
import net.corda.core.utilities.BOB
|
||||
import net.corda.core.utilities.DUMMY_NOTARY
|
||||
import net.corda.demorun.node
|
||||
import net.corda.demorun.runNodes
|
||||
import net.corda.node.services.startFlowPermission
|
||||
import net.corda.node.services.transactions.ValidatingNotaryService
|
||||
import net.corda.nodeapi.User
|
||||
import net.corda.notarydemo.flows.DummyIssueAndMove
|
||||
import net.corda.notarydemo.flows.RPCStartableNotaryFlowClient
|
||||
import net.corda.cordform.CordformDefinition
|
||||
import net.corda.cordform.CordformContext
|
||||
|
||||
fun main(args: Array<String>) = SingleNotaryCordform.runNodes()
|
||||
|
||||
object SingleNotaryCordform : CordformDefinition("build" / "notary-demo-nodes", DUMMY_NOTARY.name) {
|
||||
init {
|
||||
node {
|
||||
name(ALICE.name.toString())
|
||||
nearestCity("London")
|
||||
p2pPort(10002)
|
||||
rpcPort(10003)
|
||||
rpcUsers = listOf(User("demo", "demo", setOf(startFlowPermission<DummyIssueAndMove>(), startFlowPermission<RPCStartableNotaryFlowClient>())).toMap())
|
||||
}
|
||||
node {
|
||||
name(BOB.name.toString())
|
||||
nearestCity("New York")
|
||||
p2pPort(10005)
|
||||
rpcPort(10006)
|
||||
}
|
||||
node {
|
||||
name(DUMMY_NOTARY.name.toString())
|
||||
nearestCity("London")
|
||||
advertisedServices = listOf(ServiceInfo(ValidatingNotaryService.type).toString())
|
||||
p2pPort(10009)
|
||||
rpcPort(10010)
|
||||
notaryNodePort(10008)
|
||||
}
|
||||
}
|
||||
|
||||
override fun setup(context: CordformContext) {}
|
||||
}
|
@ -31,4 +31,5 @@ include 'samples:irs-demo'
|
||||
include 'samples:network-visualiser'
|
||||
include 'samples:simm-valuation-demo'
|
||||
include 'samples:raft-notary-demo'
|
||||
include 'samples:bank-of-corda-demo'
|
||||
include 'samples:bank-of-corda-demo'
|
||||
include 'cordform-common'
|
||||
|
Loading…
Reference in New Issue
Block a user