Merge pull request #1395 from corda/chrisr3-os-merge

Merge from Open Source up to df4699c6
This commit is contained in:
Chris Rankin 2018-09-17 15:54:33 +01:00 committed by GitHub
commit 1bae06cbf3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 106 additions and 90 deletions

View File

@ -64,6 +64,10 @@ jar {
baseName 'corda-firewall'
}
capsule {
version capsule_version
}
task buildFirewallJar(type: FatCapsule, dependsOn: project(':bridge').jar) {
applicationClass 'net.corda.bridge.Firewall'
archiveName "corda-firewall-${corda_release_version}.jar"

View File

@ -19,9 +19,9 @@ buildscript {
ext.quasar_group = 'co.paralleluniverse'
ext.quasar_version = '0.7.10'
// gradle-capsule-plugin:1.0.2 contains capsule:1.0.1
// TODO: Upgrade gradle-capsule-plugin to a version with capsule:1.0.3
ext.capsule_version = '1.0.1'
// gradle-capsule-plugin:1.0.2 contains capsule:1.0.1 by default.
// We must configure it manually to use the latest capsule version.
ext.capsule_version = '1.0.3'
ext.asm_version = '5.0.4'
ext.artemis_version = '2.6.2'
@ -119,8 +119,8 @@ buildscript {
plugins {
// TODO The capsule plugin requires the newer DSL plugin block.It would be nice if we could unify all the plugins into one style,
// but the DSL has some restrictions e.g can't be used on the allprojects section. So we should revisit this if there are improvements in Gradle.
// Version 1.0.2 of this plugin uses capsule:1.0.1
id "us.kirchmeier.capsule" version "1.0.2"
// Version 1.0.2 of this plugin uses capsule:1.0.1 by default.
id 'us.kirchmeier.capsule' version '1.0.2' apply false
// Add the shadow plugin to the plugins classpath for the entire project.
id 'com.github.johnrengelman.shadow' version '2.0.4' apply false
@ -482,6 +482,6 @@ if (file('corda-docs-only-build').exists() || (System.getenv('CORDA_DOCS_ONLY_BU
}
wrapper {
gradleVersion = "4.10"
gradleVersion = "4.10.1"
distributionType = Wrapper.DistributionType.ALL
}

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@ -41,15 +41,21 @@ object X509Utilities {
val DEFAULT_IDENTITY_SIGNATURE_SCHEME = Crypto.EDDSA_ED25519_SHA512
val DEFAULT_TLS_SIGNATURE_SCHEME = Crypto.ECDSA_SECP256R1_SHA256
// TODO This class is more of a general purpose utility class and as such these constants belong elsewhere
// TODO This class is more of a general purpose utility class and as such these constants belong elsewhere.
// Aliases for private keys and certificates.
const val CORDA_ROOT_CA = "cordarootca"
const val CORDA_INTERMEDIATE_CA = "cordaintermediateca"
const val CORDA_CLIENT_TLS = "cordaclienttls"
const val CORDA_CLIENT_CA = "cordaclientca"
// TODO These don't need to be prefixes, but can be the full aliases.
// TODO These don't need to be prefixes, but can be the full aliases. However, because they are used as key aliases
// we should ensure that:
// a) they always contain valid characters, preferably [A-Za-z0-9] in order to be supported by the majority of
// crypto service implementations (i.e., HSMs).
// b) they are at most 127 chars in length (i.e., as of 2018, Azure Key Vault does not support bigger aliases).
const val NODE_IDENTITY_ALIAS_PREFIX = "identity"
// TODO Hyphen (-) seems to be supported by the major HSM vendors, but we should consider remove it in the
// future and stick to [A-Za-z0-9].
const val DISTRIBUTED_NOTARY_ALIAS_PREFIX = "distributed-notary"
val DEFAULT_VALIDITY_WINDOW = Pair(0.millis, 3650.days)

View File

@ -33,6 +33,10 @@ targetCompatibility = 1.6
jar.enabled = false
capsule {
version capsule_version
}
task buildCordaJAR(type: FatCapsule, dependsOn: project(':node').tasks.jar) {
applicationClass 'net.corda.node.Corda'
archiveName "corda-enterprise-${corda_release_version}.jar"

View File

@ -891,11 +891,11 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
val privateKeyAlias = "$id-private-key"
if (privateKeyAlias !in keyStore) {
singleName ?: throw IllegalArgumentException(
"Unable to find in the key store the identity of the distributed notary the node is part of")
// We shouldn't have a distributed notary at this stage, so singleName should NOT be null.
requireNotNull(singleName) {
"Unable to find in the key store the identity of the distributed notary the node is part of"
}
log.info("$privateKeyAlias not found in key store, generating fresh key!")
// TODO This check shouldn't be needed
check(singleName == configuration.myLegalName)
keyStore.storeLegalIdentity(privateKeyAlias, generateKeyPair())
}
@ -904,7 +904,7 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
// TODO: Use configuration to indicate composite key should be used instead of public key for the identity.
val compositeKeyAlias = "$id-composite-key"
val certificates = if (compositeKeyAlias in keyStore) {
// Use composite key instead if it exists
// Use composite key instead if it exists.
val certificate = keyStore[compositeKeyAlias]
// We have to create the certificate chain for the composite key manually, this is because we don't have a keystore
// provider that understand compositeKey-privateKey combo. The cert chain is created using the composite key certificate +

View File

@ -70,64 +70,87 @@ open class NodeStartup: CordaCliWrapper("corda", "Runs a Corda Node") {
*/
override fun runProgram(): Int {
val startTime = System.currentTimeMillis()
if (!canNormalizeEmptyPath()) {
println("You are using a version of Java that is not supported (${System.getProperty("java.version")}). Please upgrade to the latest supported version.")
println("Corda will now exit...")
return ExitCodes.FAILURE
}
// Step 1. Check for supported Java version.
if (!isValidJavaVersion()) return ExitCodes.FAILURE
val registrationMode = checkRegistrationMode()
// TODO: Reconsider if automatic re-registration should be applied when something failed during initial registration.
// There might be cases where the node user should investigate what went wrong before registering again.
if (registrationMode && !cmdLineOptions.isRegistration) {
println("Node was started before with `--initial-registration`, but the registration was not completed.\nResuming registration.")
// Pretend that the node was started with `--initial-registration` to help prevent user error.
cmdLineOptions.isRegistration = true
}
// We do the single node check before we initialise logging so that in case of a double-node start it
// Step 2. We do the single node check before we initialise logging so that in case of a double-node start it
// doesn't mess with the running node's logs.
enforceSingleNodeIsRunning(cmdLineOptions.baseDirectory)
// Step 3. Initialise logging.
initLogging()
// Register all cryptography [Provider]s.
// Step 4. Register all cryptography [Provider]s.
// Required to install our [SecureRandom] before e.g., UUID asks for one.
// This needs to go after initLogging(netty clashes with our logging).
Crypto.registerProviders()
// Step 5. Print banner and basic node info.
val versionInfo = getVersionInfo()
drawBanner(versionInfo)
Node.printBasicNodeInfo(LOGS_CAN_BE_FOUND_IN_STRING, System.getProperty("log-path"))
// Step 6. Load and validate node configuration.
val configuration = (attempt { loadConfiguration() }.doOnException(handleConfigurationLoadingError(cmdLineOptions.configFile)) as? Try.Success)?.let(Try.Success<NodeConfiguration>::value) ?: return ExitCodes.FAILURE
val errors = configuration.validate()
if (errors.isNotEmpty()) {
logger.error("Invalid node configuration. Errors were:${System.lineSeparator()}${errors.joinToString(System.lineSeparator())}")
return ExitCodes.FAILURE
}
// Step 7. Configuring special serialisation requirements, i.e., bft-smart relies on Java serialization.
attempt { banJavaSerialisation(configuration) }.doOnException { error -> error.logAsUnexpected("Exception while configuring serialisation") } as? Try.Success ?: return ExitCodes.FAILURE
// Step 8. Any actions required before starting up the Corda network layer.
attempt { preNetworkRegistration(configuration) }.doOnException(handleRegistrationError) as? Try.Success ?: return ExitCodes.FAILURE
cmdLineOptions.nodeRegistrationOption?.let {
// Null checks for [compatibilityZoneURL], [rootTruststorePath] and [rootTruststorePassword] has been done in [CmdLineOptions.loadConfig]
attempt { registerWithNetwork(configuration, versionInfo, it) }.doOnException(handleRegistrationError) as? Try.Success ?: return ExitCodes.FAILURE
// At this point the node registration was successful. We can delete the marker file.
deleteNodeRegistrationMarker(cmdLineOptions.baseDirectory)
return ExitCodes.SUCCESS
// Step 9. Check if in registration mode.
checkAndRunRegistrationMode(configuration, versionInfo)?.let {
return if (it) ExitCodes.SUCCESS
else ExitCodes.FAILURE
}
// Step 10. Log startup info.
logStartupInfo(versionInfo, configuration)
// Step 11. Start node: create the node, check for other command-line options, add extra logging etc.
attempt { startNode(configuration, versionInfo, startTime) }.doOnSuccess { logger.info("Node exiting successfully") }.doOnException(handleStartError) as? Try.Success ?: return ExitCodes.FAILURE
return ExitCodes.SUCCESS
}
private fun checkAndRunRegistrationMode(configuration: NodeConfiguration, versionInfo: VersionInfo): Boolean? {
checkUnfinishedRegistration()
cmdLineOptions.nodeRegistrationOption?.let {
// Null checks for [compatibilityZoneURL], [rootTruststorePath] and [rootTruststorePassword] has been done in [CmdLineOptions.loadConfig]
attempt { registerWithNetwork(configuration, versionInfo, it) }.doOnException(handleRegistrationError) as? Try.Success
?: return false
// At this point the node registration was successful. We can delete the marker file.
deleteNodeRegistrationMarker(cmdLineOptions.baseDirectory)
return true
}
return null
}
private fun isValidJavaVersion(): Boolean {
if (!canNormalizeEmptyPath()) {
println("You are using a version of Java that is not supported (${System.getProperty("java.version")}). Please upgrade to the latest supported version.")
println("Corda will now exit...")
return false
}
return true
}
// TODO: Reconsider if automatic re-registration should be applied when something failed during initial registration.
// There might be cases where the node user should investigate what went wrong before registering again.
private fun checkUnfinishedRegistration() {
if (checkRegistrationMode() && !cmdLineOptions.isRegistration) {
println("Node was started before with `--initial-registration`, but the registration was not completed.\nResuming registration.")
// Pretend that the node was started with `--initial-registration` to help prevent user error.
cmdLineOptions.isRegistration = true
}
}
private fun <RESULT> attempt(action: () -> RESULT): Try<RESULT> = Try.on(action)
private fun Exception.isExpectedWhenStartingNode() = startNodeExpectedErrors.any { error -> error.isInstance(this) }
@ -275,6 +298,7 @@ open class NodeStartup: CordaCliWrapper("corda", "Runs a Corda Node") {
logLoadedCorDapps(node.services.cordappProvider.cordapps)
node.nodeReadyFuture.thenMatch({
// Elapsed time in seconds. We used 10 / 100.0 and not directly / 1000.0 to only keep two decimal digits.
val elapsed = (System.currentTimeMillis() - startTime) / 10 / 100.0
val name = nodeInfo.legalIdentitiesAndCerts.first().name.organisation
Node.printBasicNodeInfo("Node for \"$name\" started up and registered in $elapsed sec")

View File

@ -46,7 +46,7 @@ open class NetworkRegistrationHelper(private val certificatesDirectory: Path,
private val nextIdleDuration: (Duration?) -> Duration? = FixedPeriodLimitedRetrialStrategy(10, Duration.ofMinutes(1))) {
companion object {
const val SELF_SIGNED_PRIVATE_KEY = "Self Signed Private Key"
const val SELF_SIGNED_PRIVATE_KEY = "SelfSignedPrivateKey"
val logger = contextLogger()
}
@ -154,6 +154,8 @@ open class NetworkRegistrationHelper(private val certificatesDirectory: Path,
// Save private key and certificate chain to the key store.
with(nodeKeystore.value) {
setPrivateKey(keyAlias, keyPair.private, certificates, keyPassword = keyPassword)
// The key was temporarily stored as SELF_SIGNED_PRIVATE_KEY, but now that it's signed by the Doorman we
// can delete this old record.
internal.deleteEntry(SELF_SIGNED_PRIVATE_KEY)
save()
}
@ -164,6 +166,7 @@ open class NetworkRegistrationHelper(private val certificatesDirectory: Path,
// Create or load self signed keypair from the key store.
// We use the self sign certificate to store the key temporarily in the keystore while waiting for the request approval.
if (alias !in this) {
// NODE_CA should be TLS compatible due to the cert hierarchy structure.
val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
val selfSignCert = X509Utilities.createSelfSignedCACertificate(myLegalName.x500Principal, keyPair)
// Save to the key store.

View File

@ -2,17 +2,13 @@ Notary demo
-----------
This demo shows a party getting transactions notarised by either a single-node or a distributed notary service.
All versions of the demo start two counterparty nodes.
One of the counterparties will generate transactions that transfer a self-issued asset to the other party and submit
them for notarisation.
The Raft (https://raft.github.io/) version of the demo will start three distributed notary nodes.
The BFT SMaRt (https://bft-smart.github.io/library/) version of the demo will start four distributed notary nodes.
The output will display a list of notarised transaction IDs and corresponding signer public keys. In the Raft distributed notary,
every node in the cluster can service client requests, and one signature is sufficient to satisfy the notary composite key requirement.
In the BFT SMaRt distributed notary, three signatures are required.
In the BFT-SMaRt distributed notary, three signatures are required.
You will notice that successive transactions get signed by different members of the cluster (usually allocated in a random order).
To run the Raft version of the demo from the command line in Unix:
@ -22,7 +18,7 @@ To run the Raft version of the demo from the command line in Unix:
Single notaries).
2. Run ``./samples/notary-demo/build/nodes/nodesRaft/runnodes``, which will start the nodes in separate terminal windows/tabs.
Wait until a "Node started up and registered in ..." message appears on each of the terminals
3. Run ``./gradlew samples:notary-demo:notarise`` to make a call to the "Party" node to initiate notarisation requests
3. Run ``./gradlew samples:notary-demo:notarise`` to make a call to the "Alice Corp" node to initiate notarisation requests
In a few seconds you will see a message "Notarised 10 transactions" with a list of transaction ids and the signer public keys
To run from the command line in Windows:
@ -32,7 +28,7 @@ To run from the command line in Windows:
Single notaries).
2. Run ``samples\notary-demo\build\nodes\nodesRaft\runnodes``, which will start the nodes in separate terminal windows/tabs.
Wait until a "Node started up and registered in ..." message appears on each of the terminals
3. Run ``gradlew samples:notary-demo:notarise`` to make a call to the "Party" node to initiate notarisation requests
3. Run ``gradlew samples:notary-demo:notarise`` to make a call to the "Alice Corp" node to initiate notarisation requests
In a few seconds you will see a message "Notarised 10 transactions" with a list of transaction ids and the signer public keys
To run the BFT SMaRt notary demo, use ``nodesBFT`` instead of ``nodesRaft`` in the path (you will see messages from notary nodes

View File

@ -62,14 +62,6 @@ task deployNodesSingle(type: Cordform, dependsOn: 'jar') {
}
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
@ -95,14 +87,6 @@ task deployNodesCustom(type: Cordform, dependsOn: 'jar') {
}
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
@ -128,14 +112,6 @@ task deployNodesRaft(type: Cordform, dependsOn: 'jar') {
}
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
@ -200,14 +176,6 @@ task deployNodesBFT(type: Cordform, dependsOn: 'jar') {
}
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

View File

@ -3,7 +3,6 @@ package net.corda.notarydemo
import net.corda.client.rpc.CordaRPCClient
import net.corda.core.crypto.CompositeKey
import net.corda.core.crypto.toStringShort
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.messaging.CordaRPCOps
import net.corda.core.messaging.startFlow
import net.corda.core.transactions.SignedTransaction
@ -12,6 +11,7 @@ import net.corda.core.utilities.getOrThrow
import net.corda.notarydemo.flows.DummyIssueAndMove
import net.corda.notarydemo.flows.RPCStartableNotaryFlowClient
import net.corda.testing.core.BOB_NAME
import net.corda.testing.core.TestIdentity
import java.util.concurrent.Future
fun main(args: Array<String>) {
@ -29,13 +29,8 @@ private class NotaryDemoClientApi(val rpc: CordaRPCOps) {
checkNotNull(id) { "No unique notary identity, try cleaning the node directories." }
}
private val counterparty by lazy {
val parties = rpc.networkMapSnapshot()
parties.fold(ArrayList<PartyAndCertificate>()) { acc, elem ->
acc.addAll(elem.legalIdentitiesAndCerts.filter { it.name == BOB_NAME })
acc
}.single().party
}
/** A dummy identity. */
private val counterparty = TestIdentity(BOB_NAME).party
/** Makes calls to the node rpc to start transaction notarisation. */
fun notarise(count: Int) {

View File

@ -39,6 +39,6 @@ jar {
}
publish {
name 'tools-database-manager'
disableDefaultJar = true
}
name 'tools-database-manager'
}

View File

@ -19,6 +19,10 @@ configurations {
sourceCompatibility = 1.6
targetCompatibility = 1.6
capsule {
version capsule_version
}
task buildExplorerJAR(type: FatCapsule, dependsOn: project(':tools:explorer').tasks.jar) {
applicationClass 'net.corda.explorer.Main'
archiveName "node-explorer-${corda_release_version}.jar"

View File

@ -134,6 +134,10 @@ jar {
zip64 = true
}
capsule {
version capsule_version
}
// For building a runnable jar with no other dependencies for remote JMeter slave server, that has Corda code on classpath.
// Run with: java -jar jmeter-corda-<version>.jar
// No additional args required but will be passed if specified.

View File

@ -29,6 +29,10 @@ jar {
}
}
capsule {
version capsule_version
}
task buildClientJar(type: FatCapsule) {
applicationClass mainClassName
baseName "notaryhealthcheck-client"
@ -47,4 +51,4 @@ publish {
name "corda-notary-healthcheck-client"
}
assemble.dependsOn buildClientJar
assemble.dependsOn buildClientJar

View File

@ -28,6 +28,10 @@ targetCompatibility = 1.6
jar.enabled = false
capsule {
version capsule_version
}
task buildWebserverJar(type: FatCapsule, dependsOn: project(':node').tasks.jar) {
applicationClass 'net.corda.webserver.WebServer'
archiveName "corda-webserver-${corda_release_version}.jar"