From ca36b4676d4f8c5a73c560a159d7be451af52f8c Mon Sep 17 00:00:00 2001 From: Andrzej Cichocki Date: Thu, 25 May 2017 10:30:28 +0100 Subject: [PATCH 001/126] Unduplicate certificatesDirectory (#740) --- .../kotlin/net/corda/nodeapi/config/SSLConfiguration.kt | 7 ++++++- .../net/corda/node/services/config/NodeConfiguration.kt | 7 ++----- .../kotlin/net/corda/verifier/VerifierDriver.kt | 5 +++-- verifier/src/main/kotlin/net/corda/verifier/Verifier.kt | 7 +++---- .../main/kotlin/net/corda/webserver/WebServerConfig.kt | 8 +++----- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/config/SSLConfiguration.kt b/node-api/src/main/kotlin/net/corda/nodeapi/config/SSLConfiguration.kt index 8bc6644dcf..13a70eb517 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/config/SSLConfiguration.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/config/SSLConfiguration.kt @@ -10,4 +10,9 @@ interface SSLConfiguration { val sslKeystore: Path get() = certificatesDirectory / "sslkeystore.jks" val nodeKeystore: Path get() = certificatesDirectory / "nodekeystore.jks" val trustStoreFile: Path get() = certificatesDirectory / "truststore.jks" -} \ No newline at end of file +} + +interface NodeSSLConfiguration : SSLConfiguration { + val baseDirectory: Path + override val certificatesDirectory: Path get() = baseDirectory / "certificates" +} diff --git a/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt b/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt index 1ee3b213b0..9d7f078516 100644 --- a/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt +++ b/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt @@ -1,7 +1,6 @@ package net.corda.node.services.config import com.google.common.net.HostAndPort -import net.corda.core.div import net.corda.core.node.VersionInfo import net.corda.core.node.services.ServiceInfo import net.corda.node.internal.NetworkMapInfo @@ -11,16 +10,14 @@ import net.corda.node.services.messaging.CertificateChainCheckPolicy import net.corda.node.services.network.NetworkMapService import net.corda.node.utilities.TestClock import net.corda.nodeapi.User +import net.corda.nodeapi.config.NodeSSLConfiguration import net.corda.nodeapi.config.OldConfig -import net.corda.nodeapi.config.SSLConfiguration import org.bouncycastle.asn1.x500.X500Name import java.net.URL import java.nio.file.Path import java.util.* -interface NodeConfiguration : SSLConfiguration { - val baseDirectory: Path - override val certificatesDirectory: Path get() = baseDirectory / "certificates" +interface NodeConfiguration : NodeSSLConfiguration { val myLegalName: X500Name val networkMapService: NetworkMapInfo? val minimumPlatformVersion: Int diff --git a/verifier/src/integration-test/kotlin/net/corda/verifier/VerifierDriver.kt b/verifier/src/integration-test/kotlin/net/corda/verifier/VerifierDriver.kt index 96032a9df5..5c255c0cfe 100644 --- a/verifier/src/integration-test/kotlin/net/corda/verifier/VerifierDriver.kt +++ b/verifier/src/integration-test/kotlin/net/corda/verifier/VerifierDriver.kt @@ -21,6 +21,7 @@ import net.corda.nodeapi.ArtemisMessagingComponent.Companion.NODE_USER import net.corda.nodeapi.ArtemisTcpTransport import net.corda.nodeapi.ConnectionDirection import net.corda.nodeapi.VerifierApi +import net.corda.nodeapi.config.NodeSSLConfiguration import net.corda.nodeapi.config.SSLConfiguration import org.apache.activemq.artemis.api.core.SimpleString import org.apache.activemq.artemis.api.core.client.ActiveMQClient @@ -182,8 +183,8 @@ data class VerifierDriverDSL( private fun startVerificationRequestorInternal(name: X500Name, hostAndPort: HostAndPort): VerificationRequestorHandle { val baseDir = driverDSL.driverDirectory / name.commonName - val sslConfig = object : SSLConfiguration { - override val certificatesDirectory = baseDir / "certificates" + val sslConfig = object : NodeSSLConfiguration { + override val baseDirectory = baseDir override val keyStorePassword: String get() = "cordacadevpass" override val trustStorePassword: String get() = "trustpass" } diff --git a/verifier/src/main/kotlin/net/corda/verifier/Verifier.kt b/verifier/src/main/kotlin/net/corda/verifier/Verifier.kt index 333dc8a878..aeed27e3ca 100644 --- a/verifier/src/main/kotlin/net/corda/verifier/Verifier.kt +++ b/verifier/src/main/kotlin/net/corda/verifier/Verifier.kt @@ -13,20 +13,19 @@ import net.corda.nodeapi.ArtemisTcpTransport.Companion.tcpTransport import net.corda.nodeapi.ConnectionDirection import net.corda.nodeapi.VerifierApi import net.corda.nodeapi.VerifierApi.VERIFICATION_REQUESTS_QUEUE_NAME -import net.corda.nodeapi.config.SSLConfiguration +import net.corda.nodeapi.config.NodeSSLConfiguration import net.corda.nodeapi.config.getValue import org.apache.activemq.artemis.api.core.client.ActiveMQClient import java.nio.file.Path import java.nio.file.Paths data class VerifierConfiguration( - val baseDirectory: Path, + override val baseDirectory: Path, val config: Config -) : SSLConfiguration { +) : NodeSSLConfiguration { val nodeHostAndPort: HostAndPort by config override val keyStorePassword: String by config override val trustStorePassword: String by config - override val certificatesDirectory = baseDirectory / "certificates" } class Verifier { diff --git a/webserver/src/main/kotlin/net/corda/webserver/WebServerConfig.kt b/webserver/src/main/kotlin/net/corda/webserver/WebServerConfig.kt index ad17a38ed1..194536869e 100644 --- a/webserver/src/main/kotlin/net/corda/webserver/WebServerConfig.kt +++ b/webserver/src/main/kotlin/net/corda/webserver/WebServerConfig.kt @@ -2,16 +2,14 @@ package net.corda.webserver import com.google.common.net.HostAndPort import com.typesafe.config.Config -import net.corda.core.div -import net.corda.nodeapi.config.SSLConfiguration +import net.corda.nodeapi.config.NodeSSLConfiguration import net.corda.nodeapi.config.getValue import java.nio.file.Path /** * [baseDirectory] is not retrieved from the config file but rather from a command line argument. */ -class WebServerConfig(val baseDirectory: Path, val config: Config) : SSLConfiguration { - override val certificatesDirectory: Path get() = baseDirectory / "certificates" +class WebServerConfig(override val baseDirectory: Path, val config: Config) : NodeSSLConfiguration { override val keyStorePassword: String by config override val trustStorePassword: String by config val exportJMXto: String get() = "http" @@ -19,4 +17,4 @@ class WebServerConfig(val baseDirectory: Path, val config: Config) : SSLConfigur val myLegalName: String by config val p2pAddress: HostAndPort by config // TODO: Use RPC port instead of P2P port (RPC requires authentication, P2P does not) val webAddress: HostAndPort by config -} \ No newline at end of file +} From 1aae41214ffdbe1d62ffb0458f2af36d094886db Mon Sep 17 00:00:00 2001 From: Chris Rankin Date: Thu, 25 May 2017 11:49:21 +0100 Subject: [PATCH 002/126] Unpack DemoBench's capsules within $HOME/demobench directory. (#738) * Unpack the capsules into a subdirectory of $HOME/demobench. * Minor tidy up. * Add a new suggested bank. --- .../kotlin/net/corda/demobench/model/JVMConfig.kt | 8 ++++++-- .../kotlin/net/corda/demobench/model/NodeConfig.kt | 5 ++--- .../net/corda/demobench/model/NodeController.kt | 5 ++++- .../kotlin/net/corda/demobench/model/NodeData.kt | 3 ++- .../net/corda/demobench/model/ServiceController.kt | 12 +++++------- .../src/main/kotlin/net/corda/demobench/pty/R3Pty.kt | 5 ++--- 6 files changed, 21 insertions(+), 17 deletions(-) diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/model/JVMConfig.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/model/JVMConfig.kt index 3e4c3d1652..148cc9025b 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/model/JVMConfig.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/model/JVMConfig.kt @@ -3,14 +3,15 @@ package net.corda.demobench.model import javafx.scene.control.Alert import javafx.scene.control.Alert.AlertType.ERROR import javafx.stage.Stage -import tornadofx.* import java.nio.file.Path import java.nio.file.Paths +import tornadofx.* class JVMConfig : Controller() { val userHome: Path = Paths.get(System.getProperty("user.home")).toAbsolutePath() val dataHome: Path = userHome.resolve("demobench") + val capsuleHome: Path = dataHome.resolve(".capsule") val javaPath: Path = Paths.get(System.getProperty("java.home"), "bin", "java") val applicationDir: Path = Paths.get(System.getProperty("user.dir")).toAbsolutePath() @@ -23,9 +24,12 @@ class JVMConfig : Controller() { } fun processFor(jarPath: Path, vararg args: String): ProcessBuilder { - return ProcessBuilder(commandFor(jarPath, *args)) + return ProcessBuilder(commandFor(jarPath, *args)).apply { setCapsuleCacheDir(environment()) } } + fun setCapsuleCacheDir(env: MutableMap): MutableMap = env.apply { + put("CAPSULE_CACHE_DIR", capsuleHome.toString()) + } } typealias atRuntime = (Path, String) -> Unit diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeConfig.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeConfig.kt index 7a73d40e28..baf94692f5 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeConfig.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeConfig.kt @@ -47,10 +47,9 @@ class NodeConfig( .withValue("myLegalName", valueFor(legalName.toString())) .withValue("p2pAddress", addressValueFor(p2pPort)) .withValue("extraAdvertisedServiceIds", valueFor(extraServices)) - .withFallback(optional("networkMapService", networkMap, { - c, n -> + .withFallback(optional("networkMapService", networkMap, { c, n -> c.withValue("address", addressValueFor(n.p2pPort)) - .withValue("legalName", valueFor(n.legalName.toString())) + .withValue("legalName", valueFor(n.legalName.toString())) })) .withValue("webAddress", addressValueFor(webPort)) .withValue("rpcAddress", addressValueFor(rpcPort)) diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeController.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeController.kt index 31460611d9..b593bc32ce 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeController.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeController.kt @@ -116,7 +116,10 @@ class NodeController(check: atRuntime = ::checkExists) : Controller() { confFile.writeText(config.toText()) // Execute the Corda node - pty.run(command, System.getenv(), nodeDir.toString()) + val cordaEnv = System.getenv().toMutableMap().apply { + jvm.setCapsuleCacheDir(this) + } + pty.run(command, cordaEnv, nodeDir.toString()) log.info("Launched node: ${config.legalName}") return true } catch (e: Exception) { diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeData.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeData.kt index 0138ae92d2..e4f234fa10 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeData.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeData.kt @@ -19,7 +19,8 @@ object SuggestedDetails { "Bank of Big Apples" to "New York", "Bank of Baguettes" to "Paris", "Bank of Fondue" to "Geneve", - "Bank of Maple Syrup" to "Toronto" + "Bank of Maple Syrup" to "Toronto", + "Bank of Golden Gates" to "San Francisco" ) private var cursor = 0 diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/model/ServiceController.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/model/ServiceController.kt index 0974a4f6df..cfd1c23038 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/model/ServiceController.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/model/ServiceController.kt @@ -4,7 +4,6 @@ import tornadofx.* import java.io.IOException import java.io.InputStreamReader import java.net.URL -import java.util.* import java.util.logging.Level class ServiceController(resourceName: String = "/services.conf") : Controller() { @@ -17,11 +16,11 @@ class ServiceController(resourceName: String = "/services.conf") : Controller() * Load our list of known extra Corda services. */ private fun loadConf(url: URL?): List { - if (url == null) { - return emptyList() + return if (url == null) { + emptyList() } else { try { - val set = TreeSet() + val set = sortedSetOf() InputStreamReader(url.openStream()).useLines { sq -> sq.forEach { line -> val service = line.trim() @@ -30,12 +29,11 @@ class ServiceController(resourceName: String = "/services.conf") : Controller() log.info("Supports: $service") } } - return set.toList() + set.toList() } catch (e: IOException) { log.log(Level.SEVERE, "Failed to load $url: ${e.message}", e) - return emptyList() + emptyList() } } } - } diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/pty/R3Pty.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/pty/R3Pty.kt index 68152fbfc1..1269062d64 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/pty/R3Pty.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/pty/R3Pty.kt @@ -44,7 +44,7 @@ class R3Pty(val name: X500Name, settings: SettingsProvider, dimension: Dimension @Throws(IOException::class) fun run(args: Array, envs: Map, workingDir: String?) { - check(!terminal.isSessionRunning, { "${terminal.sessionName} is already running" }) + check(!terminal.isSessionRunning) { "${terminal.sessionName} is already running" } val environment = envs.toMutableMap() if (!UIUtil.isWindows) { @@ -64,8 +64,7 @@ class R3Pty(val name: X500Name, settings: SettingsProvider, dimension: Dimension onExit(exitValue) } - val session = terminal.createTerminalSession(connector) - session.start() + terminal.createTerminalSession(connector).apply { start() } } @Suppress("unused") From 9f2b44f8f7577449037e0ea18c719118c46e1c23 Mon Sep 17 00:00:00 2001 From: Konstantinos Chalkias Date: Thu, 25 May 2017 13:18:49 +0100 Subject: [PATCH 003/126] Rename Timestamp to TimeWindow (#706) Rename Timestamp to TimeWindow + refactoring --- .../net/corda/core/contracts/Structures.kt | 59 ++++++++++++++----- .../corda/core/contracts/TransactionTypes.kt | 2 +- .../core/contracts/TransactionVerification.kt | 4 +- .../net/corda/core/crypto/CryptoUtils.kt | 1 - .../net/corda/core/crypto/MerkleTree.kt | 2 +- .../core/node/services/TimeWindowChecker.kt | 26 ++++++++ .../core/node/services/TimestampChecker.kt | 26 -------- .../net/corda/core/serialization/Kryo.kt | 6 +- .../core/transactions/BaseTransaction.kt | 10 ++-- .../core/transactions/LedgerTransaction.kt | 6 +- .../core/transactions/MerkleTransaction.kt | 8 +-- .../core/transactions/TransactionBuilder.kt | 22 +++---- .../core/transactions/WireTransaction.kt | 8 +-- .../kotlin/net/corda/flows/FinalityFlow.kt | 2 +- .../main/kotlin/net/corda/flows/NotaryFlow.kt | 30 +++++----- .../net/corda/flows/TwoPartyDealFlow.kt | 7 +-- .../contracts/TransactionEncumbranceTests.kt | 10 ++-- .../corda/core/contracts/TransactionTests.kt | 16 ++--- .../core/crypto/PartialMerkleTreeTest.kt | 12 ++-- .../node/services/TimeWindowCheckerTests.kt | 33 +++++++++++ .../node/services/TimestampCheckerTests.kt | 33 ----------- .../TransactionSerializationTests.kt | 6 +- .../net/corda/core/testing/Generators.kt | 9 +-- docs/source/changelog.rst | 7 +++ .../docs/WorkflowTransactionBuildTutorial.kt | 6 +- .../contracts/universal/UniversalContract.kt | 6 +- .../net/corda/contracts/universal/Cap.kt | 10 ++-- .../net/corda/contracts/universal/Caplet.kt | 6 +- .../contracts/universal/FXFwdTimeOption.kt | 6 +- .../net/corda/contracts/universal/FXSwap.kt | 18 +++--- .../net/corda/contracts/universal/IRS.kt | 6 +- .../corda/contracts/universal/RollOutTests.kt | 4 +- .../net/corda/contracts/universal/Swaption.kt | 2 +- .../contracts/universal/ZeroCouponBond.kt | 6 +- .../corda/contracts/JavaCommercialPaper.java | 18 +++--- .../net/corda/contracts/CommercialPaper.kt | 8 +-- .../corda/contracts/CommercialPaperLegacy.kt | 6 +- .../net/corda/contracts/asset/Obligation.kt | 35 ++--------- .../net/corda/flows/TwoPartyTradeFlow.kt | 6 +- .../corda/contracts/CommercialPaperTests.kt | 20 +++---- .../corda/contracts/asset/ObligationTests.kt | 24 ++++---- .../net/corda/contracts/testing/Generators.kt | 2 +- .../services/vault/schemas/VaultSchemaTest.kt | 8 +-- .../net/corda/node/internal/AbstractNode.kt | 12 ++-- .../BFTNonValidatingNotaryService.kt | 14 ++--- .../node/services/transactions/BFTSMaRt.kt | 14 ++--- .../transactions/NonValidatingNotaryFlow.kt | 8 +-- .../RaftNonValidatingNotaryService.kt | 6 +- .../RaftValidatingNotaryService.kt | 6 +- .../transactions/SimpleNotaryService.kt | 6 +- .../transactions/ValidatingNotaryFlow.kt | 8 +-- .../transactions/ValidatingNotaryService.kt | 6 +- .../node/messaging/TwoPartyTradeFlowTests.kt | 6 +- .../corda/node/services/NotaryChangeTests.kt | 2 +- .../database/RequeryConfigurationTest.kt | 2 +- .../persistence/DBTransactionStorageTests.kt | 2 +- .../transactions/NotaryServiceTests.kt | 12 ++-- .../node/services/vault/VaultQueryTests.kt | 2 +- .../corda/attachmentdemo/AttachmentDemo.kt | 1 - .../net/corda/bank/BankOfCordaHttpAPITest.kt | 2 - .../net/corda/irs/api/InterestRateSwapAPI.kt | 1 - .../main/kotlin/net/corda/irs/contract/IRS.kt | 7 +-- .../kotlin/net/corda/irs/flows/FixingFlow.kt | 6 +- .../corda/irs/flows/UpdateBusinessDayFlow.kt | 4 +- .../kotlin/net/corda/irs/plugin/IRSPlugin.kt | 1 - .../net/corda/simulation/TradeSimulation.kt | 0 .../kotlin/net/corda/irs/testing/IRSTests.kt | 49 ++++++++------- .../net/corda/vega/contracts/OGTrade.kt | 6 +- .../net/corda/vega/contracts/PortfolioSwap.kt | 6 +- .../kotlin/net/corda/vega/flows/SimmFlow.kt | 1 - .../net/corda/vega/flows/StateRevisionFlow.kt | 3 +- .../net/corda/vega/services/SimmService.kt | 1 - .../test/kotlin/net/corda/vega/SwapExample.kt | 2 +- .../net/corda/traderdemo/flow/SellerFlow.kt | 9 ++- .../main/kotlin/net/corda/testing/TestDSL.kt | 4 +- .../testing/TransactionDSLInterpreter.kt | 18 +++--- 76 files changed, 382 insertions(+), 387 deletions(-) create mode 100644 core/src/main/kotlin/net/corda/core/node/services/TimeWindowChecker.kt delete mode 100644 core/src/main/kotlin/net/corda/core/node/services/TimestampChecker.kt create mode 100644 core/src/test/kotlin/net/corda/core/node/services/TimeWindowCheckerTests.kt delete mode 100644 core/src/test/kotlin/net/corda/core/node/services/TimestampCheckerTests.kt delete mode 100644 samples/irs-demo/src/main/kotlin/net/corda/simulation/TradeSimulation.kt diff --git a/core/src/main/kotlin/net/corda/core/contracts/Structures.kt b/core/src/main/kotlin/net/corda/core/contracts/Structures.kt index 5f687b2fb4..e56a42f409 100644 --- a/core/src/main/kotlin/net/corda/core/contracts/Structures.kt +++ b/core/src/main/kotlin/net/corda/core/contracts/Structures.kt @@ -5,7 +5,6 @@ import net.corda.core.crypto.SecureHash import net.corda.core.flows.FlowLogicRef import net.corda.core.flows.FlowLogicRefFactory import net.corda.core.identity.AbstractParty -import net.corda.core.identity.AnonymousParty import net.corda.core.identity.Party import net.corda.core.node.services.ServiceType import net.corda.core.serialization.* @@ -406,33 +405,63 @@ data class AuthenticatedObject( ) /** + * A time-window is required for validation/notarization purposes. * If present in a transaction, contains a time that was verified by the uniqueness service. The true time must be - * between (after, before). + * between (fromTime, untilTime). + * Usually, a time-window is required to have both sides set (fromTime, untilTime). + * However, some apps may require that a time-window has a start [Instant] (fromTime), but no end [Instant] (untilTime) and vice versa. + * TODO: Consider refactoring using TimeWindow abstraction like TimeWindow.From, TimeWindow.Until, TimeWindow.Between. */ @CordaSerializable -data class Timestamp( - /** The time at which this transaction is said to have occurred is after this moment */ - val after: Instant?, - /** The time at which this transaction is said to have occurred is before this moment */ - val before: Instant? +class TimeWindow private constructor( + /** The time at which this transaction is said to have occurred is after this moment. */ + val fromTime: Instant?, + /** The time at which this transaction is said to have occurred is before this moment. */ + val untilTime: Instant? ) { - init { - if (after == null && before == null) - throw IllegalArgumentException("At least one of before/after must be specified") - if (after != null && before != null) - check(after <= before) + companion object { + /** Use when the left-side [fromTime] of a [TimeWindow] is only required and we don't need an end instant (untilTime). */ + @JvmStatic + fun fromOnly(fromTime: Instant) = TimeWindow(fromTime, null) + + /** Use when the right-side [untilTime] of a [TimeWindow] is only required and we don't need a start instant (fromTime). */ + @JvmStatic + fun untilOnly(untilTime: Instant) = TimeWindow(null, untilTime) + + /** Use when both sides of a [TimeWindow] must be set ([fromTime], [untilTime]). */ + @JvmStatic + fun between(fromTime: Instant, untilTime: Instant): TimeWindow { + require(fromTime < untilTime) { "fromTime should be earlier than untilTime" } + return TimeWindow(fromTime, untilTime) + } + + /** + * When we need to create a [TimeWindow] based on a specific time [Instant] and some tolerance in both sides of this instant. + * The result will be the following time-window: ([time] - [tolerance], [time] + [tolerance]). + */ + @JvmStatic + fun withTolerance(time: Instant, tolerance: Duration) = TimeWindow(time - tolerance, time + tolerance) } - constructor(time: Instant, tolerance: Duration) : this(time - tolerance, time + tolerance) + /** The midpoint is calculated as fromTime + (untilTime - fromTime)/2. Note that it can only be computed if both sides are set. */ + val midpoint: Instant get() = fromTime!! + Duration.between(fromTime, untilTime!!).dividedBy(2) - val midpoint: Instant get() = after!! + Duration.between(after, before!!).dividedBy(2) + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is TimeWindow) return false + return (fromTime == other.fromTime && untilTime == other.untilTime) + } + + override fun hashCode() = 31 * (fromTime?.hashCode() ?: 0) + (untilTime?.hashCode() ?: 0) + + override fun toString() = "TimeWindow(fromTime=$fromTime, untilTime=$untilTime)" } /** * Implemented by a program that implements business logic on the shared ledger. All participants run this code for * every [LedgerTransaction] they see on the network, for every input and output state. All contracts must accept the * transaction for it to be accepted: failure of any aborts the entire thing. The time is taken from a trusted - * timestamp attached to the transaction itself i.e. it is NOT necessarily the current time. + * time-window attached to the transaction itself i.e. it is NOT necessarily the current time. * * TODO: Contract serialization is likely to change, so the annotation is likely temporary. */ diff --git a/core/src/main/kotlin/net/corda/core/contracts/TransactionTypes.kt b/core/src/main/kotlin/net/corda/core/contracts/TransactionTypes.kt index e4d343a3c6..b1e98a49e9 100644 --- a/core/src/main/kotlin/net/corda/core/contracts/TransactionTypes.kt +++ b/core/src/main/kotlin/net/corda/core/contracts/TransactionTypes.kt @@ -19,7 +19,7 @@ sealed class TransactionType { */ @Throws(TransactionVerificationException::class) fun verify(tx: LedgerTransaction) { - require(tx.notary != null || tx.timestamp == null) { "Transactions with timestamps must be notarised." } + require(tx.notary != null || tx.timeWindow == null) { "Transactions with time-windows must be notarised" } val duplicates = detectDuplicateInputs(tx) if (duplicates.isNotEmpty()) throw TransactionVerificationException.DuplicateInputStates(tx.id, duplicates) val missing = verifySigners(tx) diff --git a/core/src/main/kotlin/net/corda/core/contracts/TransactionVerification.kt b/core/src/main/kotlin/net/corda/core/contracts/TransactionVerification.kt index 8ad833d7af..47ee213c09 100644 --- a/core/src/main/kotlin/net/corda/core/contracts/TransactionVerification.kt +++ b/core/src/main/kotlin/net/corda/core/contracts/TransactionVerification.kt @@ -1,8 +1,8 @@ package net.corda.core.contracts -import net.corda.core.identity.Party import net.corda.core.crypto.SecureHash import net.corda.core.flows.FlowException +import net.corda.core.identity.Party import net.corda.core.serialization.CordaSerializable import java.security.PublicKey import java.util.* @@ -19,7 +19,7 @@ data class TransactionForContract(val inputs: List, val commands: List>, val origHash: SecureHash, val inputNotary: Party? = null, - val timestamp: Timestamp? = null) { + val timeWindow: TimeWindow? = null) { override fun hashCode() = origHash.hashCode() override fun equals(other: Any?) = other is TransactionForContract && other.origHash == origHash diff --git a/core/src/main/kotlin/net/corda/core/crypto/CryptoUtils.kt b/core/src/main/kotlin/net/corda/core/crypto/CryptoUtils.kt index 276a48f824..c55d515d74 100644 --- a/core/src/main/kotlin/net/corda/core/crypto/CryptoUtils.kt +++ b/core/src/main/kotlin/net/corda/core/crypto/CryptoUtils.kt @@ -2,7 +2,6 @@ package net.corda.core.crypto -import net.corda.core.identity.AbstractParty import net.corda.core.identity.AnonymousParty import net.corda.core.identity.Party import net.corda.core.serialization.CordaSerializable diff --git a/core/src/main/kotlin/net/corda/core/crypto/MerkleTree.kt b/core/src/main/kotlin/net/corda/core/crypto/MerkleTree.kt index 8491208e60..babf164bc6 100644 --- a/core/src/main/kotlin/net/corda/core/crypto/MerkleTree.kt +++ b/core/src/main/kotlin/net/corda/core/crypto/MerkleTree.kt @@ -8,7 +8,7 @@ import java.util.* * See: https://en.wikipedia.org/wiki/Merkle_tree * * Transaction is split into following blocks: inputs, attachments' refs, outputs, commands, notary, - * signers, tx type, timestamp. Merkle Tree is kept in a recursive data structure. Building is done bottom up, + * signers, tx type, time-window. Merkle Tree is kept in a recursive data structure. Building is done bottom up, * from all leaves' hashes. If number of leaves is not a power of two, the tree is padded with zero hashes. */ sealed class MerkleTree { diff --git a/core/src/main/kotlin/net/corda/core/node/services/TimeWindowChecker.kt b/core/src/main/kotlin/net/corda/core/node/services/TimeWindowChecker.kt new file mode 100644 index 0000000000..b06ee522af --- /dev/null +++ b/core/src/main/kotlin/net/corda/core/node/services/TimeWindowChecker.kt @@ -0,0 +1,26 @@ +package net.corda.core.node.services + +import net.corda.core.contracts.TimeWindow +import net.corda.core.seconds +import net.corda.core.until +import java.time.Clock +import java.time.Duration + +/** + * Checks if the given time-window falls within the allowed tolerance interval. + */ +class TimeWindowChecker(val clock: Clock = Clock.systemUTC(), + val tolerance: Duration = 30.seconds) { + fun isValid(timeWindow: TimeWindow): Boolean { + val untilTime = timeWindow.untilTime + val fromTime = timeWindow.fromTime + + val now = clock.instant() + + // We don't need to test for (fromTime == null && untilTime == null) or backwards bounds because the TimeWindow + // constructor already checks that. + if (untilTime != null && untilTime until now > tolerance) return false + if (fromTime != null && now until fromTime > tolerance) return false + return true + } +} diff --git a/core/src/main/kotlin/net/corda/core/node/services/TimestampChecker.kt b/core/src/main/kotlin/net/corda/core/node/services/TimestampChecker.kt deleted file mode 100644 index 2948aa92ef..0000000000 --- a/core/src/main/kotlin/net/corda/core/node/services/TimestampChecker.kt +++ /dev/null @@ -1,26 +0,0 @@ -package net.corda.core.node.services - -import net.corda.core.contracts.Timestamp -import net.corda.core.seconds -import net.corda.core.until -import java.time.Clock -import java.time.Duration - -/** - * Checks if the given timestamp falls within the allowed tolerance interval. - */ -class TimestampChecker(val clock: Clock = Clock.systemUTC(), - val tolerance: Duration = 30.seconds) { - fun isValid(timestampCommand: Timestamp): Boolean { - val before = timestampCommand.before - val after = timestampCommand.after - - val now = clock.instant() - - // We don't need to test for (before == null && after == null) or backwards bounds because the TimestampCommand - // constructor already checks that. - if (before != null && before until now > tolerance) return false - if (after != null && now until after > tolerance) return false - return true - } -} diff --git a/core/src/main/kotlin/net/corda/core/serialization/Kryo.kt b/core/src/main/kotlin/net/corda/core/serialization/Kryo.kt index 788bc93ad8..a4315ee500 100644 --- a/core/src/main/kotlin/net/corda/core/serialization/Kryo.kt +++ b/core/src/main/kotlin/net/corda/core/serialization/Kryo.kt @@ -325,7 +325,7 @@ object WireTransactionSerializer : Serializer() { kryo.writeClassAndObject(output, obj.notary) kryo.writeClassAndObject(output, obj.mustSign) kryo.writeClassAndObject(output, obj.type) - kryo.writeClassAndObject(output, obj.timestamp) + kryo.writeClassAndObject(output, obj.timeWindow) } private fun attachmentsClassLoader(kryo: Kryo, attachmentHashes: List): ClassLoader? { @@ -353,8 +353,8 @@ object WireTransactionSerializer : Serializer() { val notary = kryo.readClassAndObject(input) as Party? val signers = kryo.readClassAndObject(input) as List val transactionType = kryo.readClassAndObject(input) as TransactionType - val timestamp = kryo.readClassAndObject(input) as Timestamp? - return WireTransaction(inputs, attachmentHashes, outputs, commands, notary, signers, transactionType, timestamp) + val timeWindow = kryo.readClassAndObject(input) as TimeWindow? + return WireTransaction(inputs, attachmentHashes, outputs, commands, notary, signers, transactionType, timeWindow) } } } diff --git a/core/src/main/kotlin/net/corda/core/transactions/BaseTransaction.kt b/core/src/main/kotlin/net/corda/core/transactions/BaseTransaction.kt index 61010282e8..876efdda82 100644 --- a/core/src/main/kotlin/net/corda/core/transactions/BaseTransaction.kt +++ b/core/src/main/kotlin/net/corda/core/transactions/BaseTransaction.kt @@ -36,12 +36,12 @@ abstract class BaseTransaction( * If specified, a time window in which this transaction may have been notarised. Contracts can check this * time window to find out when a transaction is deemed to have occurred, from the ledger's perspective. */ - val timestamp: Timestamp? + val timeWindow: TimeWindow? ) : NamedByHash { protected fun checkInvariants() { - if (notary == null) check(inputs.isEmpty()) { "The notary must be specified explicitly for any transaction that has inputs." } - if (timestamp != null) check(notary != null) { "If a timestamp is provided, there must be a notary." } + if (notary == null) check(inputs.isEmpty()) { "The notary must be specified explicitly for any transaction that has inputs" } + if (timeWindow != null) check(notary != null) { "If a time-window is provided, there must be a notary" } } override fun equals(other: Any?): Boolean { @@ -50,10 +50,10 @@ abstract class BaseTransaction( notary == other.notary && mustSign == other.mustSign && type == other.type && - timestamp == other.timestamp + timeWindow == other.timeWindow } - override fun hashCode() = Objects.hash(notary, mustSign, type, timestamp) + override fun hashCode() = Objects.hash(notary, mustSign, type, timeWindow) override fun toString(): String = "${javaClass.simpleName}(id=$id)" } diff --git a/core/src/main/kotlin/net/corda/core/transactions/LedgerTransaction.kt b/core/src/main/kotlin/net/corda/core/transactions/LedgerTransaction.kt index 4665387c7d..3fd91f1f0e 100644 --- a/core/src/main/kotlin/net/corda/core/transactions/LedgerTransaction.kt +++ b/core/src/main/kotlin/net/corda/core/transactions/LedgerTransaction.kt @@ -32,9 +32,9 @@ class LedgerTransaction( override val id: SecureHash, notary: Party?, signers: List, - timestamp: Timestamp?, + timeWindow: TimeWindow?, type: TransactionType -) : BaseTransaction(inputs, outputs, notary, signers, type, timestamp) { +) : BaseTransaction(inputs, outputs, notary, signers, type, timeWindow) { init { checkInvariants() } @@ -47,7 +47,7 @@ class LedgerTransaction( /** Strips the transaction down to a form that is usable by the contract verify functions */ fun toTransactionForContract(): TransactionForContract { return TransactionForContract(inputs.map { it.state.data }, outputs.map { it.data }, attachments, commands, id, - inputs.map { it.state.notary }.singleOrNull(), timestamp) + inputs.map { it.state.notary }.singleOrNull(), timeWindow) } /** diff --git a/core/src/main/kotlin/net/corda/core/transactions/MerkleTransaction.kt b/core/src/main/kotlin/net/corda/core/transactions/MerkleTransaction.kt index 78c25f7154..8ef6fba2e9 100644 --- a/core/src/main/kotlin/net/corda/core/transactions/MerkleTransaction.kt +++ b/core/src/main/kotlin/net/corda/core/transactions/MerkleTransaction.kt @@ -33,7 +33,7 @@ interface TraversableTransaction { val notary: Party? val mustSign: List val type: TransactionType? - val timestamp: Timestamp? + val timeWindow: TimeWindow? /** * Returns a flattened list of all the components that are present in the transaction, in the following order: @@ -45,7 +45,7 @@ interface TraversableTransaction { * - The notary [Party], if present * - Each required signer ([mustSign]) that is present * - The type of the transaction, if present - * - The timestamp of the transaction, if present + * - The time-window of the transaction, if present */ val availableComponents: List get() { @@ -56,7 +56,7 @@ interface TraversableTransaction { notary?.let { result += it } result.addAll(mustSign) type?.let { result += it } - timestamp?.let { result += it } + timeWindow?.let { result += it } return result } @@ -81,7 +81,7 @@ class FilteredLeaves( override val notary: Party?, override val mustSign: List, override val type: TransactionType?, - override val timestamp: Timestamp? + override val timeWindow: TimeWindow? ) : TraversableTransaction { /** * Function that checks the whole filtered structure. diff --git a/core/src/main/kotlin/net/corda/core/transactions/TransactionBuilder.kt b/core/src/main/kotlin/net/corda/core/transactions/TransactionBuilder.kt index 19396b1e01..ce8646d825 100644 --- a/core/src/main/kotlin/net/corda/core/transactions/TransactionBuilder.kt +++ b/core/src/main/kotlin/net/corda/core/transactions/TransactionBuilder.kt @@ -37,9 +37,9 @@ open class TransactionBuilder( protected val outputs: MutableList> = arrayListOf(), protected val commands: MutableList = arrayListOf(), protected val signers: MutableSet = mutableSetOf(), - protected var timestamp: Timestamp? = null) { + protected var timeWindow: TimeWindow? = null) { - val time: Timestamp? get() = timestamp + val time: TimeWindow? get() = timeWindow // TODO: rename using a more descriptive name (i.e. timeWindowGetter) or remove if unused. /** * Creates a copy of the builder. @@ -53,28 +53,28 @@ open class TransactionBuilder( outputs = ArrayList(outputs), commands = ArrayList(commands), signers = LinkedHashSet(signers), - timestamp = timestamp + timeWindow = timeWindow ) /** - * Places a [TimestampCommand] in this transaction, removing any existing command if there is one. + * Places a [TimeWindow] in this transaction, removing any existing command if there is one. * The command requires a signature from the Notary service, which acts as a Timestamp Authority. * The signature can be obtained using [NotaryFlow]. * - * The window of time in which the final timestamp may lie is defined as [time] +/- [timeTolerance]. + * The window of time in which the final time-window may lie is defined as [time] +/- [timeTolerance]. * If you want a non-symmetrical time window you must add the command via [addCommand] yourself. The tolerance * should be chosen such that your code can finish building the transaction and sending it to the TSA within that * window of time, taking into account factors such as network latency. Transactions being built by a group of * collaborating parties may therefore require a higher time tolerance than a transaction being built by a single * node. */ - fun setTime(time: Instant, timeTolerance: Duration) = setTime(Timestamp(time, timeTolerance)) + fun addTimeWindow(time: Instant, timeTolerance: Duration) = addTimeWindow(TimeWindow.withTolerance(time, timeTolerance)) - fun setTime(newTimestamp: Timestamp) { - check(notary != null) { "Only notarised transactions can have a timestamp" } + fun addTimeWindow(timeWindow: TimeWindow) { + check(notary != null) { "Only notarised transactions can have a time-window" } signers.add(notary!!.owningKey) - check(currentSigs.isEmpty()) { "Cannot change timestamp after signing" } - this.timestamp = newTimestamp + check(currentSigs.isEmpty()) { "Cannot change time-window after signing" } + this.timeWindow = timeWindow } /** A more convenient way to add items to this transaction that calls the add* methods for you based on type */ @@ -132,7 +132,7 @@ open class TransactionBuilder( } fun toWireTransaction() = WireTransaction(ArrayList(inputs), ArrayList(attachments), - ArrayList(outputs), ArrayList(commands), notary, signers.toList(), type, timestamp) + ArrayList(outputs), ArrayList(commands), notary, signers.toList(), type, timeWindow) fun toSignedTransaction(checkSufficientSignatures: Boolean = true): SignedTransaction { if (checkSufficientSignatures) { diff --git a/core/src/main/kotlin/net/corda/core/transactions/WireTransaction.kt b/core/src/main/kotlin/net/corda/core/transactions/WireTransaction.kt index 09e2b9218b..a02ac8d1d9 100644 --- a/core/src/main/kotlin/net/corda/core/transactions/WireTransaction.kt +++ b/core/src/main/kotlin/net/corda/core/transactions/WireTransaction.kt @@ -31,8 +31,8 @@ class WireTransaction( notary: Party?, signers: List, type: TransactionType, - timestamp: Timestamp? -) : BaseTransaction(inputs, outputs, notary, signers, type, timestamp), TraversableTransaction { + timeWindow: TimeWindow? +) : BaseTransaction(inputs, outputs, notary, signers, type, timeWindow), TraversableTransaction { init { checkInvariants() } @@ -100,7 +100,7 @@ class WireTransaction( val resolvedInputs = inputs.map { ref -> resolveStateRef(ref)?.let { StateAndRef(it, ref) } ?: throw TransactionResolutionException(ref.txhash) } - return LedgerTransaction(resolvedInputs, outputs, authenticatedArgs, attachments, id, notary, mustSign, timestamp, type) + return LedgerTransaction(resolvedInputs, outputs, authenticatedArgs, attachments, id, notary, mustSign, timeWindow, type) } /** @@ -130,7 +130,7 @@ class WireTransaction( notNullFalse(notary) as Party?, mustSign.filter { filtering(it) }, notNullFalse(type) as TransactionType?, - notNullFalse(timestamp) as Timestamp? + notNullFalse(timeWindow) as TimeWindow? ) } diff --git a/core/src/main/kotlin/net/corda/flows/FinalityFlow.kt b/core/src/main/kotlin/net/corda/flows/FinalityFlow.kt index ff62d89deb..e609c4f5ca 100644 --- a/core/src/main/kotlin/net/corda/flows/FinalityFlow.kt +++ b/core/src/main/kotlin/net/corda/flows/FinalityFlow.kt @@ -89,7 +89,7 @@ class FinalityFlow(val transactions: Iterable, private fun needsNotarySignature(stx: SignedTransaction): Boolean { val wtx = stx.tx - val needsNotarisation = wtx.inputs.isNotEmpty() || wtx.timestamp != null + val needsNotarisation = wtx.inputs.isNotEmpty() || wtx.timeWindow != null return needsNotarisation && hasNoNotarySignature(stx) } diff --git a/core/src/main/kotlin/net/corda/flows/NotaryFlow.kt b/core/src/main/kotlin/net/corda/flows/NotaryFlow.kt index 32ff54484b..3c67bb35e3 100644 --- a/core/src/main/kotlin/net/corda/flows/NotaryFlow.kt +++ b/core/src/main/kotlin/net/corda/flows/NotaryFlow.kt @@ -2,7 +2,7 @@ package net.corda.flows import co.paralleluniverse.fibers.Suspendable import net.corda.core.contracts.StateRef -import net.corda.core.contracts.Timestamp +import net.corda.core.contracts.TimeWindow import net.corda.core.crypto.DigitalSignature import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SignedData @@ -11,7 +11,7 @@ import net.corda.core.flows.FlowException import net.corda.core.flows.FlowLogic import net.corda.core.flows.InitiatingFlow import net.corda.core.identity.Party -import net.corda.core.node.services.TimestampChecker +import net.corda.core.node.services.TimeWindowChecker import net.corda.core.node.services.UniquenessException import net.corda.core.node.services.UniquenessProvider import net.corda.core.serialization.CordaSerializable @@ -23,13 +23,13 @@ import net.corda.core.utilities.unwrap object NotaryFlow { /** * A flow to be used by a party for obtaining signature(s) from a [NotaryService] ascertaining the transaction - * timestamp is correct and none of its inputs have been used in another completed transaction. + * time-window is correct and none of its inputs have been used in another completed transaction. * * In case of a single-node or Raft notary, the flow will return a single signature. For the BFT notary multiple * signatures will be returned – one from each replica that accepted the input state commit. * * @throws NotaryException in case the any of the inputs to the transaction have been consumed - * by another transaction or the timestamp is invalid. + * by another transaction or the time-window is invalid. */ @InitiatingFlow open class Client(private val stx: SignedTransaction, @@ -63,7 +63,7 @@ object NotaryFlow { val payload: Any = if (serviceHub.networkMapCache.isValidatingNotary(notaryParty)) { stx } else { - wtx.buildFilteredTransaction { it is StateRef || it is Timestamp } + wtx.buildFilteredTransaction { it is StateRef || it is TimeWindow } } val response = try { @@ -90,19 +90,19 @@ object NotaryFlow { /** * A flow run by a notary service that handles notarisation requests. * - * It checks that the timestamp command is valid (if present) and commits the input state, or returns a conflict + * It checks that the time-window command is valid (if present) and commits the input state, or returns a conflict * if any of the input states have been previously committed. * * Additional transaction validation logic can be added when implementing [receiveAndVerifyTx]. */ // See AbstractStateReplacementFlow.Acceptor for why it's Void? abstract class Service(val otherSide: Party, - val timestampChecker: TimestampChecker, + val timeWindowChecker: TimeWindowChecker, val uniquenessProvider: UniquenessProvider) : FlowLogic() { @Suspendable override fun call(): Void? { - val (id, inputs, timestamp) = receiveAndVerifyTx() - validateTimestamp(timestamp) + val (id, inputs, timeWindow) = receiveAndVerifyTx() + validateTimeWindow(timeWindow) commitInputStates(inputs, id) signAndSendResponse(id) return null @@ -121,9 +121,9 @@ object NotaryFlow { send(otherSide, listOf(signature)) } - private fun validateTimestamp(t: Timestamp?) { - if (t != null && !timestampChecker.isValid(t)) - throw NotaryException(NotaryError.TimestampInvalid) + private fun validateTimeWindow(t: TimeWindow?) { + if (t != null && !timeWindowChecker.isValid(t)) + throw NotaryException(NotaryError.TimeWindowInvalid) } /** @@ -162,7 +162,7 @@ object NotaryFlow { * The minimum amount of information needed to notarise a transaction. Note that this does not include * any sensitive transaction details. */ -data class TransactionParts(val id: SecureHash, val inputs: List, val timestamp: Timestamp?) +data class TransactionParts(val id: SecureHash, val inputs: List, val timestamp: TimeWindow?) class NotaryException(val error: NotaryError) : FlowException("Error response from Notary - $error") @@ -172,8 +172,8 @@ sealed class NotaryError { override fun toString() = "One or more input states for transaction $txId have been used in another transaction" } - /** Thrown if the time specified in the timestamp command is outside the allowed tolerance */ - object TimestampInvalid : NotaryError() + /** Thrown if the time specified in the [TimeWindow] command is outside the allowed tolerance. */ + object TimeWindowInvalid : NotaryError() data class TransactionInvalid(val msg: String) : NotaryError() data class SignaturesInvalid(val msg: String) : NotaryError() diff --git a/core/src/main/kotlin/net/corda/flows/TwoPartyDealFlow.kt b/core/src/main/kotlin/net/corda/flows/TwoPartyDealFlow.kt index c776be45e8..45b8694c80 100644 --- a/core/src/main/kotlin/net/corda/flows/TwoPartyDealFlow.kt +++ b/core/src/main/kotlin/net/corda/flows/TwoPartyDealFlow.kt @@ -4,7 +4,6 @@ import co.paralleluniverse.fibers.Suspendable import net.corda.core.contracts.DealState import net.corda.core.contracts.requireThat import net.corda.core.crypto.SecureHash -import net.corda.core.crypto.expandedCompositeKeys import net.corda.core.flows.FlowLogic import net.corda.core.identity.AbstractParty import net.corda.core.identity.Party @@ -181,9 +180,9 @@ object TwoPartyDealFlow { val deal = handshake.payload.dealBeingOffered val ptx = deal.generateAgreement(handshake.payload.notary) - // And add a request for timestamping: it may be that none of the contracts need this! But it can't hurt - // to have one. - ptx.setTime(serviceHub.clock.instant(), 30.seconds) + // And add a request for a time-window: it may be that none of the contracts need this! + // But it can't hurt to have one. + ptx.addTimeWindow(serviceHub.clock.instant(), 30.seconds) return Pair(ptx, arrayListOf(deal.parties.single { it == serviceHub.myInfo.legalIdentity as AbstractParty }.owningKey)) } } diff --git a/core/src/test/kotlin/net/corda/core/contracts/TransactionEncumbranceTests.kt b/core/src/test/kotlin/net/corda/core/contracts/TransactionEncumbranceTests.kt index 8fd3bad22a..c13ebbae09 100644 --- a/core/src/test/kotlin/net/corda/core/contracts/TransactionEncumbranceTests.kt +++ b/core/src/test/kotlin/net/corda/core/contracts/TransactionEncumbranceTests.kt @@ -30,7 +30,7 @@ class TransactionEncumbranceTests { override val legalContractReference = SecureHash.sha256("DummyTimeLock") override fun verify(tx: TransactionForContract) { val timeLockInput = tx.inputs.filterIsInstance().singleOrNull() ?: return - val time = tx.timestamp?.before ?: throw IllegalArgumentException("Transactions containing time-locks must be timestamped") + val time = tx.timeWindow?.untilTime ?: throw IllegalArgumentException("Transactions containing time-locks must have a time-window") requireThat { "the time specified in the time-lock has passed" using (time >= timeLockInput.validFrom) } @@ -70,7 +70,7 @@ class TransactionEncumbranceTests { input("5pm time-lock") output { stateWithNewOwner } command(MEGA_CORP.owningKey) { Cash.Commands.Move() } - timestamp(FIVE_PM) + timeWindow(FIVE_PM) verifies() } } @@ -89,7 +89,7 @@ class TransactionEncumbranceTests { input("5pm time-lock") output { state } command(MEGA_CORP.owningKey) { Cash.Commands.Move() } - timestamp(FOUR_PM) + timeWindow(FOUR_PM) this `fails with` "the time specified in the time-lock has passed" } } @@ -106,7 +106,7 @@ class TransactionEncumbranceTests { input("state encumbered by 5pm time-lock") output { stateWithNewOwner } command(MEGA_CORP.owningKey) { Cash.Commands.Move() } - timestamp(FIVE_PM) + timeWindow(FIVE_PM) this `fails with` "Missing required encumbrance 1 in INPUT" } } @@ -146,7 +146,7 @@ class TransactionEncumbranceTests { input("5pm time-lock") output { stateWithNewOwner } command(MEGA_CORP.owningKey) { Cash.Commands.Move() } - timestamp(FIVE_PM) + timeWindow(FIVE_PM) this `fails with` "Missing required encumbrance 1 in INPUT" } } diff --git a/core/src/test/kotlin/net/corda/core/contracts/TransactionTests.kt b/core/src/test/kotlin/net/corda/core/contracts/TransactionTests.kt index 05b2e39479..61750d7619 100644 --- a/core/src/test/kotlin/net/corda/core/contracts/TransactionTests.kt +++ b/core/src/test/kotlin/net/corda/core/contracts/TransactionTests.kt @@ -41,7 +41,7 @@ class TransactionTests { notary = DUMMY_NOTARY, signers = listOf(compKey, DUMMY_KEY_1.public, DUMMY_KEY_2.public), type = TransactionType.General, - timestamp = null + timeWindow = null ) assertEquals( setOf(compKey, DUMMY_KEY_2.public), @@ -69,7 +69,7 @@ class TransactionTests { notary = DUMMY_NOTARY, signers = listOf(DUMMY_KEY_1.public, DUMMY_KEY_2.public), type = TransactionType.General, - timestamp = null + timeWindow = null ) assertFailsWith { makeSigned(wtx).verifySignatures() } @@ -101,7 +101,7 @@ class TransactionTests { val attachments = emptyList() val id = SecureHash.randomSHA256() val signers = listOf(DUMMY_NOTARY_KEY.public) - val timestamp: Timestamp? = null + val timeWindow: TimeWindow? = null val transaction: LedgerTransaction = LedgerTransaction( inputs, outputs, @@ -110,7 +110,7 @@ class TransactionTests { id, null, signers, - timestamp, + timeWindow, TransactionType.General ) @@ -128,7 +128,7 @@ class TransactionTests { val attachments = emptyList() val id = SecureHash.randomSHA256() val signers = listOf(DUMMY_NOTARY_KEY.public) - val timestamp: Timestamp? = null + val timeWindow: TimeWindow? = null val transaction: LedgerTransaction = LedgerTransaction( inputs, outputs, @@ -137,7 +137,7 @@ class TransactionTests { id, DUMMY_NOTARY, signers, - timestamp, + timeWindow, TransactionType.General ) @@ -155,7 +155,7 @@ class TransactionTests { val attachments = emptyList() val id = SecureHash.randomSHA256() val signers = listOf(DUMMY_NOTARY_KEY.public) - val timestamp: Timestamp? = null + val timeWindow: TimeWindow? = null val transaction: LedgerTransaction = LedgerTransaction( inputs, outputs, @@ -164,7 +164,7 @@ class TransactionTests { id, notary, signers, - timestamp, + timeWindow, TransactionType.General ) diff --git a/core/src/test/kotlin/net/corda/core/crypto/PartialMerkleTreeTest.kt b/core/src/test/kotlin/net/corda/core/crypto/PartialMerkleTreeTest.kt index dbbc52c5e0..93baa88cec 100644 --- a/core/src/test/kotlin/net/corda/core/crypto/PartialMerkleTreeTest.kt +++ b/core/src/test/kotlin/net/corda/core/crypto/PartialMerkleTreeTest.kt @@ -43,7 +43,7 @@ class PartialMerkleTreeTest { input("MEGA_CORP cash") output("MEGA_CORP cash".output().copy(owner = MINI_CORP)) command(MEGA_CORP_PUBKEY) { Cash.Commands.Move() } - timestamp(TEST_TX_TIME) + timeWindow(TEST_TX_TIME) this.verifies() } } @@ -98,7 +98,7 @@ class PartialMerkleTreeTest { is StateRef -> true is TransactionState<*> -> elem.data.participants[0].owningKey.keys == MINI_CORP_PUBKEY.keys is Command -> MEGA_CORP_PUBKEY in elem.signers - is Timestamp -> true + is TimeWindow -> true is PublicKey -> elem == MEGA_CORP_PUBKEY else -> false } @@ -113,7 +113,7 @@ class PartialMerkleTreeTest { assertEquals(1, leaves.inputs.size) assertEquals(1, leaves.mustSign.size) assertEquals(0, leaves.attachments.size) - assertTrue(mt.filteredLeaves.timestamp != null) + assertTrue(mt.filteredLeaves.timeWindow != null) assertEquals(null, mt.filteredLeaves.type) assertEquals(null, mt.filteredLeaves.notary) assertTrue(mt.verify()) @@ -133,7 +133,7 @@ class PartialMerkleTreeTest { assertTrue(mt.filteredLeaves.commands.isEmpty()) assertTrue(mt.filteredLeaves.inputs.isEmpty()) assertTrue(mt.filteredLeaves.outputs.isEmpty()) - assertTrue(mt.filteredLeaves.timestamp == null) + assertTrue(mt.filteredLeaves.timeWindow == null) assertFailsWith { mt.verify() } } @@ -219,7 +219,7 @@ class PartialMerkleTreeTest { } } - private fun makeSimpleCashWtx(notary: Party, timestamp: Timestamp? = null, attachments: List = emptyList()): WireTransaction { + private fun makeSimpleCashWtx(notary: Party, timeWindow: TimeWindow? = null, attachments: List = emptyList()): WireTransaction { return WireTransaction( inputs = testTx.inputs, attachments = attachments, @@ -228,7 +228,7 @@ class PartialMerkleTreeTest { notary = notary, signers = listOf(MEGA_CORP_PUBKEY, DUMMY_PUBKEY_1), type = TransactionType.General, - timestamp = timestamp + timeWindow = timeWindow ) } } diff --git a/core/src/test/kotlin/net/corda/core/node/services/TimeWindowCheckerTests.kt b/core/src/test/kotlin/net/corda/core/node/services/TimeWindowCheckerTests.kt new file mode 100644 index 0000000000..9b174d6b41 --- /dev/null +++ b/core/src/test/kotlin/net/corda/core/node/services/TimeWindowCheckerTests.kt @@ -0,0 +1,33 @@ +package net.corda.core.node.services + +import net.corda.core.contracts.TimeWindow +import net.corda.core.seconds +import org.junit.Test +import java.time.Clock +import java.time.Instant +import java.time.ZoneId +import kotlin.test.assertFalse +import kotlin.test.assertTrue + +class TimeWindowCheckerTests { + val clock = Clock.fixed(Instant.now(), ZoneId.systemDefault()) + val timeWindowChecker = TimeWindowChecker(clock, tolerance = 30.seconds) + + @Test + fun `should return true for valid time-window`() { + val now = clock.instant() + val timeWindowPast = TimeWindow.between(now - 60.seconds, now - 29.seconds) + val timeWindowFuture = TimeWindow.between(now + 29.seconds, now + 60.seconds) + assertTrue { timeWindowChecker.isValid(timeWindowPast) } + assertTrue { timeWindowChecker.isValid(timeWindowFuture) } + } + + @Test + fun `should return false for invalid time-window`() { + val now = clock.instant() + val timeWindowPast = TimeWindow.between(now - 60.seconds, now - 31.seconds) + val timeWindowFuture = TimeWindow.between(now + 31.seconds, now + 60.seconds) + assertFalse { timeWindowChecker.isValid(timeWindowPast) } + assertFalse { timeWindowChecker.isValid(timeWindowFuture) } + } +} diff --git a/core/src/test/kotlin/net/corda/core/node/services/TimestampCheckerTests.kt b/core/src/test/kotlin/net/corda/core/node/services/TimestampCheckerTests.kt deleted file mode 100644 index 98462ae3d1..0000000000 --- a/core/src/test/kotlin/net/corda/core/node/services/TimestampCheckerTests.kt +++ /dev/null @@ -1,33 +0,0 @@ -package net.corda.core.node.services - -import net.corda.core.contracts.Timestamp -import net.corda.core.seconds -import org.junit.Test -import java.time.Clock -import java.time.Instant -import java.time.ZoneId -import kotlin.test.assertFalse -import kotlin.test.assertTrue - -class TimestampCheckerTests { - val clock = Clock.fixed(Instant.now(), ZoneId.systemDefault()) - val timestampChecker = TimestampChecker(clock, tolerance = 30.seconds) - - @Test - fun `should return true for valid timestamp`() { - val now = clock.instant() - val timestampPast = Timestamp(now - 60.seconds, now - 29.seconds) - val timestampFuture = Timestamp(now + 29.seconds, now + 60.seconds) - assertTrue { timestampChecker.isValid(timestampPast) } - assertTrue { timestampChecker.isValid(timestampFuture) } - } - - @Test - fun `should return false for invalid timestamp`() { - val now = clock.instant() - val timestampPast = Timestamp(now - 60.seconds, now - 31.seconds) - val timestampFuture = Timestamp(now + 31.seconds, now + 60.seconds) - assertFalse { timestampChecker.isValid(timestampPast) } - assertFalse { timestampChecker.isValid(timestampFuture) } - } -} diff --git a/core/src/test/kotlin/net/corda/core/serialization/TransactionSerializationTests.kt b/core/src/test/kotlin/net/corda/core/serialization/TransactionSerializationTests.kt index e0e1cd17df..eed2941019 100644 --- a/core/src/test/kotlin/net/corda/core/serialization/TransactionSerializationTests.kt +++ b/core/src/test/kotlin/net/corda/core/serialization/TransactionSerializationTests.kt @@ -107,11 +107,11 @@ class TransactionSerializationTests { } @Test - fun timestamp() { - tx.setTime(TEST_TX_TIME, 30.seconds) + fun timeWindow() { + tx.addTimeWindow(TEST_TX_TIME, 30.seconds) tx.signWith(MEGA_CORP_KEY) tx.signWith(DUMMY_NOTARY_KEY) val stx = tx.toSignedTransaction() - assertEquals(TEST_TX_TIME, stx.tx.timestamp?.midpoint) + assertEquals(TEST_TX_TIME, stx.tx.timeWindow?.midpoint) } } diff --git a/core/src/test/kotlin/net/corda/core/testing/Generators.kt b/core/src/test/kotlin/net/corda/core/testing/Generators.kt index 436ef4125e..910bac6edd 100644 --- a/core/src/test/kotlin/net/corda/core/testing/Generators.kt +++ b/core/src/test/kotlin/net/corda/core/testing/Generators.kt @@ -5,7 +5,8 @@ import com.pholser.junit.quickcheck.generator.Generator import com.pholser.junit.quickcheck.generator.java.util.ArrayListGenerator import com.pholser.junit.quickcheck.random.SourceOfRandomness import net.corda.core.contracts.* -import net.corda.core.crypto.* +import net.corda.core.crypto.SecureHash +import net.corda.core.crypto.entropyToKeyPair import net.corda.core.identity.AnonymousParty import net.corda.core.identity.Party import net.corda.core.serialization.OpaqueBytes @@ -118,9 +119,9 @@ class DurationGenerator : Generator(Duration::class.java) { } } -class TimestampGenerator : Generator(Timestamp::class.java) { - override fun generate(random: SourceOfRandomness, status: GenerationStatus): Timestamp { - return Timestamp(InstantGenerator().generate(random, status), DurationGenerator().generate(random, status)) +class TimeWindowGenerator : Generator(TimeWindow::class.java) { + override fun generate(random: SourceOfRandomness, status: GenerationStatus): TimeWindow { + return TimeWindow.withTolerance(InstantGenerator().generate(random, status), DurationGenerator().generate(random, status)) } } diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index 446dc4a903..7d7783ebc0 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -8,6 +8,13 @@ UNRELEASED ---------- * API changes: + * ``Timestamp`` used for validation/notarization time-range has been renamed to ``TimeWindow``. + There are now 4 factory methods ``TimeWindow.fromOnly(fromTime: Instant)``, + ``TimeWindow.untilOnly(untilTime: Instant)``, ``TimeWindow.between(fromTime: Instant, untilTime: Instant)`` and + ``TimeWindow.withTolerance(time: Instant, tolerance: Duration)``. + Previous constructors ``TimeWindow(fromTime: Instant, untilTime: Instant)`` and + ``TimeWindow(time: Instant, tolerance: Duration)`` have been removed. + * ``CordaPluginRegistry.requiredFlows`` is no longer needed. Instead annotate any flows you wish to start via RPC with ``@StartableByRPC`` and any scheduled flows with ``@SchedulableFlow``. diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/WorkflowTransactionBuildTutorial.kt b/docs/source/example-code/src/main/kotlin/net/corda/docs/WorkflowTransactionBuildTutorial.kt index 6c25dea3b7..aaba15267e 100644 --- a/docs/source/example-code/src/main/kotlin/net/corda/docs/WorkflowTransactionBuildTutorial.kt +++ b/docs/source/example-code/src/main/kotlin/net/corda/docs/WorkflowTransactionBuildTutorial.kt @@ -80,7 +80,7 @@ data class TradeApprovalContract(override val legalContractReference: SecureHash */ override fun verify(tx: TransactionForContract) { val command = tx.commands.requireSingleCommand() - require(tx.timestamp?.midpoint != null) { "must be timestamped" } + require(tx.timeWindow?.midpoint != null) { "must have a time-window" } when (command.value) { is Commands.Issue -> { requireThat { @@ -132,7 +132,7 @@ class SubmitTradeApprovalFlow(val tradeId: String, // Create the TransactionBuilder and populate with the new state. val tx = TransactionType.General.Builder(notary) .withItems(tradeProposal, Command(TradeApprovalContract.Commands.Issue(), listOf(tradeProposal.source.owningKey))) - tx.setTime(serviceHub.clock.instant(), Duration.ofSeconds(60)) + tx.addTimeWindow(serviceHub.clock.instant(), Duration.ofSeconds(60)) // We can automatically sign as there is no untrusted data. val signedTx = serviceHub.signInitialTransaction(tx) // Notarise and distribute. @@ -193,7 +193,7 @@ class SubmitCompletionFlow(val ref: StateRef, val verdict: WorkflowState) : Flow newState, Command(TradeApprovalContract.Commands.Completed(), listOf(serviceHub.myInfo.legalIdentity.owningKey, latestRecord.state.data.source.owningKey))) - tx.setTime(serviceHub.clock.instant(), Duration.ofSeconds(60)) + tx.addTimeWindow(serviceHub.clock.instant(), Duration.ofSeconds(60)) // We can sign this transaction immediately as we have already checked all the fields and the decision // is ultimately a manual one from the caller. // As a SignedTransaction we can pass the data around certain that it cannot be modified, diff --git a/experimental/src/main/kotlin/net/corda/contracts/universal/UniversalContract.kt b/experimental/src/main/kotlin/net/corda/contracts/universal/UniversalContract.kt index f86753bfba..7a83a6cd93 100644 --- a/experimental/src/main/kotlin/net/corda/contracts/universal/UniversalContract.kt +++ b/experimental/src/main/kotlin/net/corda/contracts/universal/UniversalContract.kt @@ -47,8 +47,8 @@ class UniversalContract : Contract { is PerceivableOr -> eval(tx, expr.left) || eval(tx, expr.right) is Const -> expr.value is TimePerceivable -> when (expr.cmp) { - Comparison.LTE -> tx.timestamp!!.after!! <= eval(tx, expr.instant) - Comparison.GTE -> tx.timestamp!!.before!! >= eval(tx, expr.instant) + Comparison.LTE -> tx.timeWindow!!.fromTime!! <= eval(tx, expr.instant) + Comparison.GTE -> tx.timeWindow!!.untilTime!! >= eval(tx, expr.instant) else -> throw NotImplementedError("eval special") } is ActorPerceivable -> tx.commands.single().signers.contains(expr.actor.owningKey) @@ -207,7 +207,7 @@ class UniversalContract : Contract { assert(rest is Zero) requireThat { - "action must be timestamped" using (tx.timestamp != null) + "action must have a time-window" using (tx.timeWindow != null) // "action must be authorized" by (cmd.signers.any { action.actors.any { party -> party.owningKey == it } }) // todo perhaps merge these two requirements? "condition must be met" using (eval(tx, action.condition)) diff --git a/experimental/src/test/kotlin/net/corda/contracts/universal/Cap.kt b/experimental/src/test/kotlin/net/corda/contracts/universal/Cap.kt index 5d275c2876..b7674f43f0 100644 --- a/experimental/src/test/kotlin/net/corda/contracts/universal/Cap.kt +++ b/experimental/src/test/kotlin/net/corda/contracts/universal/Cap.kt @@ -167,7 +167,7 @@ class Cap { fun issue() { transaction { output { stateInitial } - timestamp(TEST_TX_TIME_1) + timeWindow(TEST_TX_TIME_1) this `fails with` "transaction has a single command" @@ -187,7 +187,7 @@ class Cap { transaction { input { stateInitial } output { stateAfterFixingFirst } - timestamp(TEST_TX_TIME_1) + timeWindow(TEST_TX_TIME_1) tweak { command(highStreetBank.owningKey) { UniversalContract.Commands.Action("some undefined name") } @@ -234,7 +234,7 @@ class Cap { output { stateAfterExecutionFirst } output { statePaymentFirst } - timestamp(TEST_TX_TIME_1) + timeWindow(TEST_TX_TIME_1) tweak { command(highStreetBank.owningKey) { UniversalContract.Commands.Action("some undefined name") } @@ -253,7 +253,7 @@ class Cap { input { stateAfterFixingFinal } output { statePaymentFinal } - timestamp(TEST_TX_TIME_1) + timeWindow(TEST_TX_TIME_1) tweak { command(highStreetBank.owningKey) { UniversalContract.Commands.Action("some undefined name") } @@ -271,7 +271,7 @@ class Cap { transaction { input { stateAfterExecutionFirst } output { stateAfterFixingFinal } - timestamp(TEST_TX_TIME_1) + timeWindow(TEST_TX_TIME_1) tweak { command(highStreetBank.owningKey) { UniversalContract.Commands.Action("some undefined name") } diff --git a/experimental/src/test/kotlin/net/corda/contracts/universal/Caplet.kt b/experimental/src/test/kotlin/net/corda/contracts/universal/Caplet.kt index 0c69005b22..ada8347cf3 100644 --- a/experimental/src/test/kotlin/net/corda/contracts/universal/Caplet.kt +++ b/experimental/src/test/kotlin/net/corda/contracts/universal/Caplet.kt @@ -54,7 +54,7 @@ class Caplet { fun issue() { transaction { output { stateStart } - timestamp(TEST_TX_TIME_1) + timeWindow(TEST_TX_TIME_1) this `fails with` "transaction has a single command" @@ -74,7 +74,7 @@ class Caplet { transaction { input { stateFixed } output { stateFinal } - timestamp(TEST_TX_TIME_1) + timeWindow(TEST_TX_TIME_1) tweak { command(highStreetBank.owningKey) { UniversalContract.Commands.Action("some undefined name") } @@ -92,7 +92,7 @@ class Caplet { transaction { input { stateStart } output { stateFixed } - timestamp(TEST_TX_TIME_1) + timeWindow(TEST_TX_TIME_1) tweak { command(highStreetBank.owningKey) { UniversalContract.Commands.Action("some undefined name") } diff --git a/experimental/src/test/kotlin/net/corda/contracts/universal/FXFwdTimeOption.kt b/experimental/src/test/kotlin/net/corda/contracts/universal/FXFwdTimeOption.kt index 9bea6c3c37..73abc393cb 100644 --- a/experimental/src/test/kotlin/net/corda/contracts/universal/FXFwdTimeOption.kt +++ b/experimental/src/test/kotlin/net/corda/contracts/universal/FXFwdTimeOption.kt @@ -51,7 +51,7 @@ class FXFwdTimeOption fun `issue - signature`() { transaction { output { inState } - timestamp(TEST_TX_TIME_1) + timeWindow(TEST_TX_TIME_1) this `fails with` "transaction has a single command" @@ -77,7 +77,7 @@ class FXFwdTimeOption output { outState1 } output { outState2 } - timestamp(TEST_TX_TIME_AFTER_MATURITY) + timeWindow(TEST_TX_TIME_AFTER_MATURITY) tweak { command(highStreetBank.owningKey) { UniversalContract.Commands.Action("some undefined name") } @@ -109,7 +109,7 @@ class FXFwdTimeOption output { outState1 } output { outState2 } - timestamp(TEST_TX_TIME_BEFORE_MATURITY) + timeWindow(TEST_TX_TIME_BEFORE_MATURITY) tweak { command(acmeCorp.owningKey) { UniversalContract.Commands.Action("some undefined name") } diff --git a/experimental/src/test/kotlin/net/corda/contracts/universal/FXSwap.kt b/experimental/src/test/kotlin/net/corda/contracts/universal/FXSwap.kt index 272ae30171..755c9c2b98 100644 --- a/experimental/src/test/kotlin/net/corda/contracts/universal/FXSwap.kt +++ b/experimental/src/test/kotlin/net/corda/contracts/universal/FXSwap.kt @@ -43,7 +43,7 @@ class FXSwap { transaction { output { inState } - timestamp(TEST_TX_TIME_1) + timeWindow(TEST_TX_TIME_1) this `fails with` "transaction has a single command" @@ -68,7 +68,7 @@ class FXSwap { input { inState } output { outState1 } output { outState2 } - timestamp(TEST_TX_TIME_1) + timeWindow(TEST_TX_TIME_1) tweak { command(highStreetBank.owningKey) { UniversalContract.Commands.Action("some undefined name") } @@ -87,7 +87,7 @@ class FXSwap { input { inState } output { outState2 } output { outState1 } - timestamp(TEST_TX_TIME_1) + timeWindow(TEST_TX_TIME_1) tweak { command(highStreetBank.owningKey) { UniversalContract.Commands.Action("some undefined name") } @@ -106,7 +106,7 @@ class FXSwap { input { inState } output { outState1 } output { outState2 } - timestamp(TEST_TX_TIME_1) + timeWindow(TEST_TX_TIME_1) command(momAndPop.owningKey) { UniversalContract.Commands.Action("execute") } this `fails with` "condition must be met" @@ -119,7 +119,7 @@ class FXSwap { input { inState } output { outState1 } output { outState2 } - timestamp(TEST_TX_TIME_TOO_EARLY) + timeWindow(TEST_TX_TIME_TOO_EARLY) command(acmeCorp.owningKey) { UniversalContract.Commands.Action("execute") } this `fails with` "condition must be met" @@ -131,7 +131,7 @@ class FXSwap { transaction { input { inState } output { outState1 } - timestamp(TEST_TX_TIME_1) + timeWindow(TEST_TX_TIME_1) command(acmeCorp.owningKey) { UniversalContract.Commands.Action("execute") } this `fails with` "output state must match action result state" @@ -144,7 +144,7 @@ class FXSwap { input { inState } output { outState1 } output { outStateBad2 } - timestamp(TEST_TX_TIME_1) + timeWindow(TEST_TX_TIME_1) command(acmeCorp.owningKey) { UniversalContract.Commands.Action("execute") } this `fails with` "output states must match action result state" @@ -157,7 +157,7 @@ class FXSwap { input { inState } output { outStateBad1 } output { outState2 } - timestamp(TEST_TX_TIME_1) + timeWindow(TEST_TX_TIME_1) command(acmeCorp.owningKey) { UniversalContract.Commands.Action("execute") } this `fails with` "output states must match action result state" @@ -170,7 +170,7 @@ class FXSwap { input { inState } output { outState1 } output { outStateBad3 } - timestamp(TEST_TX_TIME_1) + timeWindow(TEST_TX_TIME_1) command(acmeCorp.owningKey) { UniversalContract.Commands.Action("execute") } this `fails with` "output states must match action result state" diff --git a/experimental/src/test/kotlin/net/corda/contracts/universal/IRS.kt b/experimental/src/test/kotlin/net/corda/contracts/universal/IRS.kt index e80cffc391..a2d1250b63 100644 --- a/experimental/src/test/kotlin/net/corda/contracts/universal/IRS.kt +++ b/experimental/src/test/kotlin/net/corda/contracts/universal/IRS.kt @@ -134,7 +134,7 @@ class IRS { fun issue() { transaction { output { stateInitial } - timestamp(TEST_TX_TIME_1) + timeWindow(TEST_TX_TIME_1) this `fails with` "transaction has a single command" @@ -154,7 +154,7 @@ class IRS { transaction { input { stateInitial } output { stateAfterFixingFirst } - timestamp(TEST_TX_TIME_1) + timeWindow(TEST_TX_TIME_1) tweak { command(highStreetBank.owningKey) { UniversalContract.Commands.Action("some undefined name") } @@ -201,7 +201,7 @@ class IRS { output { stateAfterExecutionFirst } output { statePaymentFirst } - timestamp(TEST_TX_TIME_1) + timeWindow(TEST_TX_TIME_1) tweak { command(highStreetBank.owningKey) { UniversalContract.Commands.Action("some undefined name") } diff --git a/experimental/src/test/kotlin/net/corda/contracts/universal/RollOutTests.kt b/experimental/src/test/kotlin/net/corda/contracts/universal/RollOutTests.kt index c91a78be11..4f75b87c2a 100644 --- a/experimental/src/test/kotlin/net/corda/contracts/universal/RollOutTests.kt +++ b/experimental/src/test/kotlin/net/corda/contracts/universal/RollOutTests.kt @@ -143,7 +143,7 @@ class RollOutTests { fun issue() { transaction { output { stateStart } - timestamp(TEST_TX_TIME_1) + timeWindow(TEST_TX_TIME_1) this `fails with` "transaction has a single command" @@ -164,7 +164,7 @@ class RollOutTests { input { stateStart } output { stateStep1a } output { stateStep1b } - timestamp(TEST_TX_TIME_1) + timeWindow(TEST_TX_TIME_1) /* tweak { command(highStreetBank.owningKey) { UniversalContract.Commands.Action("some undefined name") } diff --git a/experimental/src/test/kotlin/net/corda/contracts/universal/Swaption.kt b/experimental/src/test/kotlin/net/corda/contracts/universal/Swaption.kt index 7dea92bc4f..904954e1aa 100644 --- a/experimental/src/test/kotlin/net/corda/contracts/universal/Swaption.kt +++ b/experimental/src/test/kotlin/net/corda/contracts/universal/Swaption.kt @@ -60,7 +60,7 @@ class Swaption { fun issue() { transaction { output { stateInitial } - timestamp(TEST_TX_TIME_1) + timeWindow(TEST_TX_TIME_1) this `fails with` "transaction has a single command" diff --git a/experimental/src/test/kotlin/net/corda/contracts/universal/ZeroCouponBond.kt b/experimental/src/test/kotlin/net/corda/contracts/universal/ZeroCouponBond.kt index 458bacb4bb..09b4aef290 100644 --- a/experimental/src/test/kotlin/net/corda/contracts/universal/ZeroCouponBond.kt +++ b/experimental/src/test/kotlin/net/corda/contracts/universal/ZeroCouponBond.kt @@ -70,7 +70,7 @@ class ZeroCouponBond { transaction { input { inState } output { outState } - timestamp(TEST_TX_TIME_1) + timeWindow(TEST_TX_TIME_1) tweak { command(highStreetBank.owningKey) { UniversalContract.Commands.Action("some undefined name") } @@ -88,7 +88,7 @@ class ZeroCouponBond { transaction { input { inState } output { outState } - timestamp(TEST_TX_TIME_1) + timeWindow(TEST_TX_TIME_1) command(momAndPop.owningKey) { UniversalContract.Commands.Action("execute") } this `fails with` "condition must be met" @@ -100,7 +100,7 @@ class ZeroCouponBond { transaction { input { inState } output { outStateWrong } - timestamp(TEST_TX_TIME_1) + timeWindow(TEST_TX_TIME_1) command(acmeCorp.owningKey) { UniversalContract.Commands.Action("execute") } this `fails with` "output state must match action result state" diff --git a/finance/src/main/java/net/corda/contracts/JavaCommercialPaper.java b/finance/src/main/java/net/corda/contracts/JavaCommercialPaper.java index d2bb7eb3f8..bc1d505ff9 100644 --- a/finance/src/main/java/net/corda/contracts/JavaCommercialPaper.java +++ b/finance/src/main/java/net/corda/contracts/JavaCommercialPaper.java @@ -10,7 +10,6 @@ import net.corda.core.contracts.TransactionForContract.*; import net.corda.core.contracts.clauses.*; import net.corda.core.crypto.*; import net.corda.core.identity.AbstractParty; -import net.corda.core.identity.AbstractParty; import net.corda.core.identity.AnonymousParty; import net.corda.core.identity.Party; import net.corda.core.node.services.*; @@ -20,7 +19,6 @@ import org.jetbrains.annotations.*; import java.time.*; import java.util.*; import java.util.stream.*; -import java.security.PublicKey; import static kotlin.collections.CollectionsKt.*; import static net.corda.core.contracts.ContractsDSL.*; @@ -206,14 +204,14 @@ public class JavaCommercialPaper implements Contract { if (!cmd.getSigners().contains(input.getOwner().getOwningKey())) throw new IllegalStateException("Failed requirement: the transaction is signed by the owner of the CP"); - Timestamp timestamp = tx.getTimestamp(); - Instant time = null == timestamp + TimeWindow timeWindow = tx.getTimeWindow(); + Instant time = null == timeWindow ? null - : timestamp.getBefore(); + : timeWindow.getUntilTime(); Amount> received = CashKt.sumCashBy(tx.getOutputs(), input.getOwner()); requireThat(require -> { - require.using("must be timestamped", timestamp != null); + require.using("must be timestamped", timeWindow != null); require.using("received amount equals the face value: " + received + " vs " + input.getFaceValue(), received.equals(input.getFaceValue())); require.using("the paper must have matured", time != null && !time.isBefore(input.getMaturityDate())); @@ -243,15 +241,15 @@ public class JavaCommercialPaper implements Contract { State groupingKey) { AuthenticatedObject cmd = requireSingleCommand(tx.getCommands(), Commands.Issue.class); State output = single(outputs); - Timestamp timestampCommand = tx.getTimestamp(); - Instant time = null == timestampCommand + TimeWindow timeWindowCommand = tx.getTimeWindow(); + Instant time = null == timeWindowCommand ? null - : timestampCommand.getBefore(); + : timeWindowCommand.getUntilTime(); requireThat(require -> { require.using("output values sum to more than the inputs", inputs.isEmpty()); require.using("output values sum to more than the inputs", output.faceValue.getQuantity() > 0); - require.using("must be timestamped", timestampCommand != null); + require.using("must be timestamped", timeWindowCommand != null); require.using("the maturity date is not in the past", time != null && time.isBefore(output.getMaturityDate())); require.using("output states are issued by a command signer", cmd.getSigners().contains(output.issuance.getParty().getOwningKey())); return Unit.INSTANCE; diff --git a/finance/src/main/kotlin/net/corda/contracts/CommercialPaper.kt b/finance/src/main/kotlin/net/corda/contracts/CommercialPaper.kt index 38c637ea1a..5f95d95aec 100644 --- a/finance/src/main/kotlin/net/corda/contracts/CommercialPaper.kt +++ b/finance/src/main/kotlin/net/corda/contracts/CommercialPaper.kt @@ -126,8 +126,8 @@ class CommercialPaper : Contract { groupingKey: Issued?): Set { val consumedCommands = super.verify(tx, inputs, outputs, commands, groupingKey) commands.requireSingleCommand() - val timestamp = tx.timestamp - val time = timestamp?.before ?: throw IllegalArgumentException("Issuances must be timestamped") + val timeWindow = tx.timeWindow + val time = timeWindow?.untilTime ?: throw IllegalArgumentException("Issuances must have a time-window") require(outputs.all { time < it.maturityDate }) { "maturity date is not in the past" } @@ -166,11 +166,11 @@ class CommercialPaper : Contract { // TODO: This should filter commands down to those with compatible subjects (underlying product and maturity date) // before requiring a single command val command = commands.requireSingleCommand() - val timestamp = tx.timestamp + val timeWindow = tx.timeWindow val input = inputs.single() val received = tx.outputs.sumCashBy(input.owner) - val time = timestamp?.after ?: throw IllegalArgumentException("Redemptions must be timestamped") + val time = timeWindow?.fromTime ?: throw IllegalArgumentException("Redemptions must have a time-window") requireThat { "the paper must have matured" using (time >= input.maturityDate) "the received amount equals the face value" using (received == input.faceValue) diff --git a/finance/src/main/kotlin/net/corda/contracts/CommercialPaperLegacy.kt b/finance/src/main/kotlin/net/corda/contracts/CommercialPaperLegacy.kt index 7be5b921f4..c8beea5c0e 100644 --- a/finance/src/main/kotlin/net/corda/contracts/CommercialPaperLegacy.kt +++ b/finance/src/main/kotlin/net/corda/contracts/CommercialPaperLegacy.kt @@ -61,7 +61,7 @@ class CommercialPaperLegacy : Contract { // There are two possible things that can be done with this CP. The first is trading it. The second is redeeming // it for cash on or after the maturity date. val command = tx.commands.requireSingleCommand() - val timestamp: Timestamp? = tx.timestamp + val timeWindow: TimeWindow? = tx.timeWindow // Suppress compiler warning as 'key' is an unused variable when destructuring 'groups'. @Suppress("UNUSED_VARIABLE") @@ -81,7 +81,7 @@ class CommercialPaperLegacy : Contract { // Redemption of the paper requires movement of on-ledger cash. val input = inputs.single() val received = tx.outputs.sumCashBy(input.owner) - val time = timestamp?.after ?: throw IllegalArgumentException("Redemptions must be timestamped") + val time = timeWindow?.fromTime ?: throw IllegalArgumentException("Redemptions must have a time-window") requireThat { "the paper must have matured" using (time >= input.maturityDate) "the received amount equals the face value" using (received == input.faceValue) @@ -92,7 +92,7 @@ class CommercialPaperLegacy : Contract { is Commands.Issue -> { val output = outputs.single() - val time = timestamp?.before ?: throw IllegalArgumentException("Issuances must be timestamped") + val time = timeWindow?.untilTime ?: throw IllegalArgumentException("Issuances have a time-window") requireThat { // Don't allow people to issue commercial paper under other entities identities. "output states are issued by a command signer" using diff --git a/finance/src/main/kotlin/net/corda/contracts/asset/Obligation.kt b/finance/src/main/kotlin/net/corda/contracts/asset/Obligation.kt index 9cb6508363..97b6dda9fe 100644 --- a/finance/src/main/kotlin/net/corda/contracts/asset/Obligation.kt +++ b/finance/src/main/kotlin/net/corda/contracts/asset/Obligation.kt @@ -24,36 +24,9 @@ import java.security.PublicKey import java.time.Duration import java.time.Instant import java.util.* -import kotlin.collections.Collection -import kotlin.collections.Iterable -import kotlin.collections.List -import kotlin.collections.Map -import kotlin.collections.Set -import kotlin.collections.all -import kotlin.collections.asIterable import kotlin.collections.component1 import kotlin.collections.component2 -import kotlin.collections.contains -import kotlin.collections.distinct -import kotlin.collections.emptySet -import kotlin.collections.filter -import kotlin.collections.filterIsInstance -import kotlin.collections.first -import kotlin.collections.firstOrNull -import kotlin.collections.forEach -import kotlin.collections.groupBy -import kotlin.collections.isNotEmpty -import kotlin.collections.iterator -import kotlin.collections.listOf -import kotlin.collections.map -import kotlin.collections.none -import kotlin.collections.reduce import kotlin.collections.set -import kotlin.collections.setOf -import kotlin.collections.single -import kotlin.collections.toSet -import kotlin.collections.union -import kotlin.collections.withIndex // Just a fake program identifier for now. In a real system it could be, for instance, the hash of the program bytecode. val OBLIGATION_PROGRAM_ID = Obligation() @@ -432,12 +405,12 @@ class Obligation

: Contract { if (input is State

) { val actualOutput = outputs[stateIdx] val deadline = input.dueBefore - val timestamp = tx.timestamp + val timeWindow = tx.timeWindow val expectedOutput = input.copy(lifecycle = expectedOutputLifecycle) requireThat { - "there is a timestamp from the authority" using (timestamp != null) - "the due date has passed" using (timestamp!!.after?.isAfter(deadline) ?: false) + "there is a time-window from the authority" using (timeWindow != null) + "the due date has passed" using (timeWindow!!.fromTime?.isAfter(deadline) ?: false) "input state lifecycle is correct" using (input.lifecycle == expectedInputLifecycle) "output state corresponds exactly to input state, with lifecycle changed" using (expectedOutput == actualOutput) } @@ -567,7 +540,7 @@ class Obligation

: Contract { } tx.addCommand(Commands.SetLifecycle(lifecycle), partiesUsed.map { it.owningKey }.distinct()) } - tx.setTime(issuanceDef.dueBefore, issuanceDef.timeTolerance) + tx.addTimeWindow(issuanceDef.dueBefore, issuanceDef.timeTolerance) } /** diff --git a/finance/src/main/kotlin/net/corda/flows/TwoPartyTradeFlow.kt b/finance/src/main/kotlin/net/corda/flows/TwoPartyTradeFlow.kt index 3f02121d19..49c6d7b26a 100644 --- a/finance/src/main/kotlin/net/corda/flows/TwoPartyTradeFlow.kt +++ b/finance/src/main/kotlin/net/corda/flows/TwoPartyTradeFlow.kt @@ -225,10 +225,10 @@ object TwoPartyTradeFlow { tx.addOutputState(state, tradeRequest.assetForSale.state.notary) tx.addCommand(command, tradeRequest.assetForSale.state.data.owner.owningKey) - // And add a request for timestamping: it may be that none of the contracts need this! But it can't hurt - // to have one. + // And add a request for a time-window: it may be that none of the contracts need this! + // But it can't hurt to have one. val currentTime = serviceHub.clock.instant() - tx.setTime(currentTime, 30.seconds) + tx.addTimeWindow(currentTime, 30.seconds) return Pair(tx, cashSigningPubKeys) } // DOCEND 1 diff --git a/finance/src/test/kotlin/net/corda/contracts/CommercialPaperTests.kt b/finance/src/test/kotlin/net/corda/contracts/CommercialPaperTests.kt index 11f47d4161..4b9c409a85 100644 --- a/finance/src/test/kotlin/net/corda/contracts/CommercialPaperTests.kt +++ b/finance/src/test/kotlin/net/corda/contracts/CommercialPaperTests.kt @@ -97,7 +97,7 @@ class CommercialPaperTestsGeneric { transaction("Issuance") { output("paper") { thisTest.getPaper() } command(MEGA_CORP_PUBKEY) { thisTest.getIssueCommand(DUMMY_NOTARY) } - timestamp(TEST_TX_TIME) + timeWindow(TEST_TX_TIME) this.verifies() } @@ -129,17 +129,17 @@ class CommercialPaperTestsGeneric { tweak { outputs(700.DOLLARS `issued by` issuer) - timestamp(TEST_TX_TIME + 8.days) + timeWindow(TEST_TX_TIME + 8.days) this `fails with` "received amount equals the face value" } outputs(1000.DOLLARS `issued by` issuer) tweak { - timestamp(TEST_TX_TIME + 2.days) + timeWindow(TEST_TX_TIME + 2.days) this `fails with` "must have matured" } - timestamp(TEST_TX_TIME + 8.days) + timeWindow(TEST_TX_TIME + 8.days) tweak { output { "paper".output() } @@ -156,7 +156,7 @@ class CommercialPaperTestsGeneric { transaction { output { thisTest.getPaper() } command(DUMMY_PUBKEY_1) { thisTest.getIssueCommand(DUMMY_NOTARY) } - timestamp(TEST_TX_TIME) + timeWindow(TEST_TX_TIME) this `fails with` "output states are issued by a command signer" } } @@ -166,7 +166,7 @@ class CommercialPaperTestsGeneric { transaction { output { thisTest.getPaper().withFaceValue(0.DOLLARS `issued by` issuer) } command(MEGA_CORP_PUBKEY) { thisTest.getIssueCommand(DUMMY_NOTARY) } - timestamp(TEST_TX_TIME) + timeWindow(TEST_TX_TIME) this `fails with` "output values sum to more than the inputs" } } @@ -176,7 +176,7 @@ class CommercialPaperTestsGeneric { transaction { output { thisTest.getPaper().withMaturityDate(TEST_TX_TIME - 10.days) } command(MEGA_CORP_PUBKEY) { thisTest.getIssueCommand(DUMMY_NOTARY) } - timestamp(TEST_TX_TIME) + timeWindow(TEST_TX_TIME) this `fails with` "maturity date is not in the past" } } @@ -187,7 +187,7 @@ class CommercialPaperTestsGeneric { input(thisTest.getPaper()) output { thisTest.getPaper() } command(MEGA_CORP_PUBKEY) { thisTest.getIssueCommand(DUMMY_NOTARY) } - timestamp(TEST_TX_TIME) + timeWindow(TEST_TX_TIME) this `fails with` "output values sum to more than the inputs" } } @@ -259,7 +259,7 @@ class CommercialPaperTestsGeneric { val issuance = bigCorpServices.myInfo.legalIdentity.ref(1) val issueTX: SignedTransaction = CommercialPaper().generateIssue(issuance, faceValue, TEST_TX_TIME + 30.days, DUMMY_NOTARY).apply { - setTime(TEST_TX_TIME, 30.seconds) + addTimeWindow(TEST_TX_TIME, 30.seconds) signWith(bigCorpServices.key) signWith(DUMMY_NOTARY_KEY) }.toSignedTransaction() @@ -289,7 +289,7 @@ class CommercialPaperTestsGeneric { databaseBigCorp.transaction { fun makeRedeemTX(time: Instant): Pair { val ptx = TransactionType.General.Builder(DUMMY_NOTARY) - ptx.setTime(time, 30.seconds) + ptx.addTimeWindow(time, 30.seconds) CommercialPaper().generateRedeem(ptx, moveTX.tx.outRef(1), bigCorpVaultService) ptx.signWith(aliceServices.key) ptx.signWith(bigCorpServices.key) diff --git a/finance/src/test/kotlin/net/corda/contracts/asset/ObligationTests.kt b/finance/src/test/kotlin/net/corda/contracts/asset/ObligationTests.kt index c0333a2c26..c5d3910728 100644 --- a/finance/src/test/kotlin/net/corda/contracts/asset/ObligationTests.kt +++ b/finance/src/test/kotlin/net/corda/contracts/asset/ObligationTests.kt @@ -341,7 +341,7 @@ class ObligationTests { input("Bob's $1,000,000 obligation to Alice") // Note we can sign with either key here command(ALICE_PUBKEY) { Obligation.Commands.Net(NetType.CLOSE_OUT) } - timestamp(TEST_TX_TIME) + timeWindow(TEST_TX_TIME) this.verifies() } this.verifies() @@ -357,7 +357,7 @@ class ObligationTests { input("MegaCorp's $1,000,000 obligation to Bob") output("change") { oneMillionDollars.OBLIGATION between Pair(MEGA_CORP, BOB) } command(BOB_PUBKEY, MEGA_CORP_PUBKEY) { Obligation.Commands.Net(NetType.CLOSE_OUT) } - timestamp(TEST_TX_TIME) + timeWindow(TEST_TX_TIME) this.verifies() } this.verifies() @@ -371,7 +371,7 @@ class ObligationTests { input("Bob's $1,000,000 obligation to Alice") output("change") { (oneMillionDollars.splitEvenly(2).first()).OBLIGATION between Pair(ALICE, BOB) } command(BOB_PUBKEY) { Obligation.Commands.Net(NetType.CLOSE_OUT) } - timestamp(TEST_TX_TIME) + timeWindow(TEST_TX_TIME) this `fails with` "amounts owed on input and output must match" } } @@ -383,7 +383,7 @@ class ObligationTests { input("Alice's $1,000,000 obligation to Bob") input("Bob's $1,000,000 obligation to Alice") command(MEGA_CORP_PUBKEY) { Obligation.Commands.Net(NetType.CLOSE_OUT) } - timestamp(TEST_TX_TIME) + timeWindow(TEST_TX_TIME) this `fails with` "any involved party has signed" } } @@ -398,7 +398,7 @@ class ObligationTests { input("Alice's $1,000,000 obligation to Bob") input("Bob's $1,000,000 obligation to Alice") command(ALICE_PUBKEY, BOB_PUBKEY) { Obligation.Commands.Net(NetType.PAYMENT) } - timestamp(TEST_TX_TIME) + timeWindow(TEST_TX_TIME) this.verifies() } this.verifies() @@ -412,7 +412,7 @@ class ObligationTests { input("Alice's $1,000,000 obligation to Bob") input("Bob's $1,000,000 obligation to Alice") command(BOB_PUBKEY) { Obligation.Commands.Net(NetType.PAYMENT) } - timestamp(TEST_TX_TIME) + timeWindow(TEST_TX_TIME) this `fails with` "all involved parties have signed" } } @@ -425,7 +425,7 @@ class ObligationTests { input("MegaCorp's $1,000,000 obligation to Bob") output("MegaCorp's $1,000,000 obligation to Alice") { oneMillionDollars.OBLIGATION between Pair(MEGA_CORP, ALICE) } command(ALICE_PUBKEY, BOB_PUBKEY, MEGA_CORP_PUBKEY) { Obligation.Commands.Net(NetType.PAYMENT) } - timestamp(TEST_TX_TIME) + timeWindow(TEST_TX_TIME) this.verifies() } this.verifies() @@ -439,7 +439,7 @@ class ObligationTests { input("MegaCorp's $1,000,000 obligation to Bob") output("MegaCorp's $1,000,000 obligation to Alice") { oneMillionDollars.OBLIGATION between Pair(MEGA_CORP, ALICE) } command(ALICE_PUBKEY, BOB_PUBKEY) { Obligation.Commands.Net(NetType.PAYMENT) } - timestamp(TEST_TX_TIME) + timeWindow(TEST_TX_TIME) this `fails with` "all involved parties have signed" } } @@ -527,14 +527,14 @@ class ObligationTests { @Test fun `payment default`() { - // Try defaulting an obligation without a timestamp + // Try defaulting an obligation without a time-window. ledger { cashObligationTestRoots(this) transaction("Settlement") { input("Alice's $1,000,000 obligation to Bob") output("Alice's defaulted $1,000,000 obligation to Bob") { (oneMillionDollars.OBLIGATION between Pair(ALICE, BOB)).copy(lifecycle = Lifecycle.DEFAULTED) } command(BOB_PUBKEY) { Obligation.Commands.SetLifecycle(Lifecycle.DEFAULTED) } - this `fails with` "there is a timestamp from the authority" + this `fails with` "there is a time-window from the authority" } } @@ -545,7 +545,7 @@ class ObligationTests { input(oneMillionDollars.OBLIGATION between Pair(ALICE, BOB) `at` futureTestTime) output("Alice's defaulted $1,000,000 obligation to Bob") { (oneMillionDollars.OBLIGATION between Pair(ALICE, BOB) `at` futureTestTime).copy(lifecycle = Lifecycle.DEFAULTED) } command(BOB_PUBKEY) { Obligation.Commands.SetLifecycle(Lifecycle.DEFAULTED) } - timestamp(TEST_TX_TIME) + timeWindow(TEST_TX_TIME) this `fails with` "the due date has passed" } @@ -555,7 +555,7 @@ class ObligationTests { input(oneMillionDollars.OBLIGATION between Pair(ALICE, BOB) `at` pastTestTime) output("Alice's defaulted $1,000,000 obligation to Bob") { (oneMillionDollars.OBLIGATION between Pair(ALICE, BOB) `at` pastTestTime).copy(lifecycle = Lifecycle.DEFAULTED) } command(BOB_PUBKEY) { Obligation.Commands.SetLifecycle(Lifecycle.DEFAULTED) } - timestamp(TEST_TX_TIME) + timeWindow(TEST_TX_TIME) this.verifies() } this.verifies() diff --git a/finance/src/test/kotlin/net/corda/contracts/testing/Generators.kt b/finance/src/test/kotlin/net/corda/contracts/testing/Generators.kt index 1b9789bc04..fe65daa626 100644 --- a/finance/src/test/kotlin/net/corda/contracts/testing/Generators.kt +++ b/finance/src/test/kotlin/net/corda/contracts/testing/Generators.kt @@ -75,7 +75,7 @@ class WiredTransactionGenerator : Generator(WireTransaction::cl notary = PartyGenerator().generate(random, status), signers = commands.flatMap { it.signers }, type = TransactionType.General, - timestamp = TimestampGenerator().generate(random, status) + timeWindow = TimeWindowGenerator().generate(random, status) ) } } diff --git a/node-schemas/src/test/kotlin/net/corda/node/services/vault/schemas/VaultSchemaTest.kt b/node-schemas/src/test/kotlin/net/corda/node/services/vault/schemas/VaultSchemaTest.kt index 05c5c3f903..29b19cb1e1 100644 --- a/node-schemas/src/test/kotlin/net/corda/node/services/vault/schemas/VaultSchemaTest.kt +++ b/node-schemas/src/test/kotlin/net/corda/node/services/vault/schemas/VaultSchemaTest.kt @@ -119,7 +119,7 @@ class VaultSchemaTest { val attachments = emptyList() val id = SecureHash.randomSHA256() val signers = listOf(DUMMY_NOTARY_KEY.public) - val timestamp: Timestamp? = null + val timeWindow: TimeWindow? = null transaction = LedgerTransaction( inputs, outputs, @@ -128,7 +128,7 @@ class VaultSchemaTest { id, notary, signers, - timestamp, + timeWindow, TransactionType.General ) } @@ -151,7 +151,7 @@ class VaultSchemaTest { val attachments = emptyList() val id = SecureHash.randomSHA256() val signers = listOf(DUMMY_NOTARY_KEY.public) - val timestamp: Timestamp? = null + val timeWindow: TimeWindow? = null return LedgerTransaction( inputs, outputs, @@ -160,7 +160,7 @@ class VaultSchemaTest { id, notary, signers, - timestamp, + timeWindow, TransactionType.General ) } diff --git a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt index 348699c273..05fb63cb1a 100644 --- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt @@ -509,20 +509,20 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, } open protected fun makeNotaryService(type: ServiceType, tokenizableServices: MutableList) { - val timestampChecker = TimestampChecker(platformClock, 30.seconds) + val timeWindowChecker = TimeWindowChecker(platformClock, 30.seconds) val uniquenessProvider = makeUniquenessProvider(type) tokenizableServices.add(uniquenessProvider) val notaryService = when (type) { - SimpleNotaryService.type -> SimpleNotaryService(timestampChecker, uniquenessProvider) - ValidatingNotaryService.type -> ValidatingNotaryService(timestampChecker, uniquenessProvider) - RaftNonValidatingNotaryService.type -> RaftNonValidatingNotaryService(timestampChecker, uniquenessProvider as RaftUniquenessProvider) - RaftValidatingNotaryService.type -> RaftValidatingNotaryService(timestampChecker, uniquenessProvider as RaftUniquenessProvider) + SimpleNotaryService.type -> SimpleNotaryService(timeWindowChecker, uniquenessProvider) + ValidatingNotaryService.type -> ValidatingNotaryService(timeWindowChecker, uniquenessProvider) + RaftNonValidatingNotaryService.type -> RaftNonValidatingNotaryService(timeWindowChecker, uniquenessProvider as RaftUniquenessProvider) + RaftValidatingNotaryService.type -> RaftValidatingNotaryService(timeWindowChecker, uniquenessProvider as RaftUniquenessProvider) BFTNonValidatingNotaryService.type -> with(configuration as FullNodeConfiguration) { val replicaId = bftReplicaId ?: throw IllegalArgumentException("bftReplicaId value must be specified in the configuration") BFTSMaRtConfig(notaryClusterAddresses).use { config -> val client = BFTSMaRt.Client(config, replicaId).also { tokenizableServices += it } // (Ab)use replicaId for clientId. - BFTNonValidatingNotaryService(config, services, timestampChecker, replicaId, database, client) + BFTNonValidatingNotaryService(config, services, timeWindowChecker, replicaId, database, client) } } else -> { diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/BFTNonValidatingNotaryService.kt b/node/src/main/kotlin/net/corda/node/services/transactions/BFTNonValidatingNotaryService.kt index fdc85c84d0..c039689d50 100644 --- a/node/src/main/kotlin/net/corda/node/services/transactions/BFTNonValidatingNotaryService.kt +++ b/node/src/main/kotlin/net/corda/node/services/transactions/BFTNonValidatingNotaryService.kt @@ -2,9 +2,9 @@ package net.corda.node.services.transactions import co.paralleluniverse.fibers.Suspendable import net.corda.core.crypto.DigitalSignature -import net.corda.core.identity.Party import net.corda.core.flows.FlowLogic -import net.corda.core.node.services.TimestampChecker +import net.corda.core.identity.Party +import net.corda.core.node.services.TimeWindowChecker import net.corda.core.serialization.deserialize import net.corda.core.serialization.serialize import net.corda.core.transactions.FilteredTransaction @@ -20,11 +20,11 @@ import kotlin.concurrent.thread /** * A non-validating notary service operated by a group of parties that don't necessarily trust each other. * - * A transaction is notarised when the consensus is reached by the cluster on its uniqueness, and timestamp validity. + * A transaction is notarised when the consensus is reached by the cluster on its uniqueness, and time-window validity. */ class BFTNonValidatingNotaryService(config: BFTSMaRtConfig, services: ServiceHubInternal, - timestampChecker: TimestampChecker, + timeWindowChecker: TimeWindowChecker, serverId: Int, db: Database, private val client: BFTSMaRt.Client) : NotaryService { @@ -32,7 +32,7 @@ class BFTNonValidatingNotaryService(config: BFTSMaRtConfig, val configHandle = config.handle() thread(name = "BFTSmartServer-$serverId", isDaemon = true) { configHandle.use { - Server(configHandle.path, serverId, db, "bft_smart_notary_committed_states", services, timestampChecker) + Server(configHandle.path, serverId, db, "bft_smart_notary_committed_states", services, timeWindowChecker) } } } @@ -72,7 +72,7 @@ class BFTNonValidatingNotaryService(config: BFTSMaRtConfig, db: Database, tableName: String, services: ServiceHubInternal, - timestampChecker: TimestampChecker) : BFTSMaRt.Server(configHome, id, db, tableName, services, timestampChecker) { + timeWindowChecker: TimeWindowChecker) : BFTSMaRt.Server(configHome, id, db, tableName, services, timeWindowChecker) { override fun executeCommand(command: ByteArray): ByteArray { val request = command.deserialize() @@ -86,7 +86,7 @@ class BFTNonValidatingNotaryService(config: BFTSMaRtConfig, val id = ftx.rootHash val inputs = ftx.filteredLeaves.inputs - validateTimestamp(ftx.filteredLeaves.timestamp) + validateTimeWindow(ftx.filteredLeaves.timeWindow) commitInputStates(inputs, id, callerIdentity) log.debug { "Inputs committed successfully, signing $id" } diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/BFTSMaRt.kt b/node/src/main/kotlin/net/corda/node/services/transactions/BFTSMaRt.kt index bc352301be..795a129665 100644 --- a/node/src/main/kotlin/net/corda/node/services/transactions/BFTSMaRt.kt +++ b/node/src/main/kotlin/net/corda/node/services/transactions/BFTSMaRt.kt @@ -8,13 +8,13 @@ import bftsmart.tom.server.defaultservices.DefaultRecoverable import bftsmart.tom.server.defaultservices.DefaultReplier import bftsmart.tom.util.Extractor import net.corda.core.contracts.StateRef -import net.corda.core.contracts.Timestamp +import net.corda.core.contracts.TimeWindow import net.corda.core.crypto.DigitalSignature import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SignedData import net.corda.core.crypto.sign import net.corda.core.identity.Party -import net.corda.core.node.services.TimestampChecker +import net.corda.core.node.services.TimeWindowChecker import net.corda.core.node.services.UniquenessProvider import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.SingletonSerializeAsToken @@ -147,7 +147,7 @@ object BFTSMaRt { val db: Database, tableName: String, val services: ServiceHubInternal, - val timestampChecker: TimestampChecker) : DefaultRecoverable() { + val timeWindowChecker: TimeWindowChecker) : DefaultRecoverable() { companion object { private val log = loggerFor() } @@ -174,7 +174,7 @@ object BFTSMaRt { /** * Implement logic to execute the command and commit the transaction to the log. - * Helper methods are provided for transaction processing: [commitInputStates], [validateTimestamp], and [sign]. + * Helper methods are provided for transaction processing: [commitInputStates], [validateTimeWindow], and [sign]. */ abstract fun executeCommand(command: ByteArray): ByteArray? @@ -201,9 +201,9 @@ object BFTSMaRt { } } - protected fun validateTimestamp(t: Timestamp?) { - if (t != null && !timestampChecker.isValid(t)) - throw NotaryException(NotaryError.TimestampInvalid) + protected fun validateTimeWindow(t: TimeWindow?) { + if (t != null && !timeWindowChecker.isValid(t)) + throw NotaryException(NotaryError.TimeWindowInvalid) } protected fun sign(bytes: ByteArray): DigitalSignature.WithKey { diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/NonValidatingNotaryFlow.kt b/node/src/main/kotlin/net/corda/node/services/transactions/NonValidatingNotaryFlow.kt index e8243e3a48..c6a01cec51 100644 --- a/node/src/main/kotlin/net/corda/node/services/transactions/NonValidatingNotaryFlow.kt +++ b/node/src/main/kotlin/net/corda/node/services/transactions/NonValidatingNotaryFlow.kt @@ -2,7 +2,7 @@ package net.corda.node.services.transactions import co.paralleluniverse.fibers.Suspendable import net.corda.core.identity.Party -import net.corda.core.node.services.TimestampChecker +import net.corda.core.node.services.TimeWindowChecker import net.corda.core.node.services.UniquenessProvider import net.corda.core.transactions.FilteredTransaction import net.corda.core.utilities.unwrap @@ -10,8 +10,8 @@ import net.corda.flows.NotaryFlow import net.corda.flows.TransactionParts class NonValidatingNotaryFlow(otherSide: Party, - timestampChecker: TimestampChecker, - uniquenessProvider: UniquenessProvider) : NotaryFlow.Service(otherSide, timestampChecker, uniquenessProvider) { + timeWindowChecker: TimeWindowChecker, + uniquenessProvider: UniquenessProvider) : NotaryFlow.Service(otherSide, timeWindowChecker, uniquenessProvider) { /** * The received transaction is not checked for contract-validity, as that would require fully * resolving it into a [TransactionForVerification], for which the caller would have to reveal the whole transaction @@ -26,6 +26,6 @@ class NonValidatingNotaryFlow(otherSide: Party, it.verify() it } - return TransactionParts(ftx.rootHash, ftx.filteredLeaves.inputs, ftx.filteredLeaves.timestamp) + return TransactionParts(ftx.rootHash, ftx.filteredLeaves.inputs, ftx.filteredLeaves.timeWindow) } } \ No newline at end of file diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/RaftNonValidatingNotaryService.kt b/node/src/main/kotlin/net/corda/node/services/transactions/RaftNonValidatingNotaryService.kt index fee9df8674..614dfdeb36 100644 --- a/node/src/main/kotlin/net/corda/node/services/transactions/RaftNonValidatingNotaryService.kt +++ b/node/src/main/kotlin/net/corda/node/services/transactions/RaftNonValidatingNotaryService.kt @@ -2,16 +2,16 @@ package net.corda.node.services.transactions import net.corda.core.flows.FlowLogic import net.corda.core.identity.Party -import net.corda.core.node.services.TimestampChecker +import net.corda.core.node.services.TimeWindowChecker /** A non-validating notary service operated by a group of mutually trusting parties, uses the Raft algorithm to achieve consensus. */ -class RaftNonValidatingNotaryService(val timestampChecker: TimestampChecker, +class RaftNonValidatingNotaryService(val timeWindowChecker: TimeWindowChecker, val uniquenessProvider: RaftUniquenessProvider) : NotaryService { companion object { val type = SimpleNotaryService.type.getSubType("raft") } override val serviceFlowFactory: (Party, Int) -> FlowLogic = { otherParty, _ -> - NonValidatingNotaryFlow(otherParty, timestampChecker, uniquenessProvider) + NonValidatingNotaryFlow(otherParty, timeWindowChecker, uniquenessProvider) } } diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/RaftValidatingNotaryService.kt b/node/src/main/kotlin/net/corda/node/services/transactions/RaftValidatingNotaryService.kt index 624df8db65..ff0217d12d 100644 --- a/node/src/main/kotlin/net/corda/node/services/transactions/RaftValidatingNotaryService.kt +++ b/node/src/main/kotlin/net/corda/node/services/transactions/RaftValidatingNotaryService.kt @@ -2,16 +2,16 @@ package net.corda.node.services.transactions import net.corda.core.flows.FlowLogic import net.corda.core.identity.Party -import net.corda.core.node.services.TimestampChecker +import net.corda.core.node.services.TimeWindowChecker /** A validating notary service operated by a group of mutually trusting parties, uses the Raft algorithm to achieve consensus. */ -class RaftValidatingNotaryService(val timestampChecker: TimestampChecker, +class RaftValidatingNotaryService(val timeWindowChecker: TimeWindowChecker, val uniquenessProvider: RaftUniquenessProvider) : NotaryService { companion object { val type = ValidatingNotaryService.type.getSubType("raft") } override val serviceFlowFactory: (Party, Int) -> FlowLogic = { otherParty, _ -> - ValidatingNotaryFlow(otherParty, timestampChecker, uniquenessProvider) + ValidatingNotaryFlow(otherParty, timeWindowChecker, uniquenessProvider) } } diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/SimpleNotaryService.kt b/node/src/main/kotlin/net/corda/node/services/transactions/SimpleNotaryService.kt index 4e5731d64c..5ac707bc9e 100644 --- a/node/src/main/kotlin/net/corda/node/services/transactions/SimpleNotaryService.kt +++ b/node/src/main/kotlin/net/corda/node/services/transactions/SimpleNotaryService.kt @@ -3,17 +3,17 @@ package net.corda.node.services.transactions import net.corda.core.flows.FlowLogic import net.corda.core.identity.Party import net.corda.core.node.services.ServiceType -import net.corda.core.node.services.TimestampChecker +import net.corda.core.node.services.TimeWindowChecker import net.corda.core.node.services.UniquenessProvider /** A simple Notary service that does not perform transaction validation */ -class SimpleNotaryService(val timestampChecker: TimestampChecker, +class SimpleNotaryService(val timeWindowChecker: TimeWindowChecker, val uniquenessProvider: UniquenessProvider) : NotaryService { companion object { val type = ServiceType.notary.getSubType("simple") } override val serviceFlowFactory: (Party, Int) -> FlowLogic = { otherParty, _ -> - NonValidatingNotaryFlow(otherParty, timestampChecker, uniquenessProvider) + NonValidatingNotaryFlow(otherParty, timeWindowChecker, uniquenessProvider) } } diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/ValidatingNotaryFlow.kt b/node/src/main/kotlin/net/corda/node/services/transactions/ValidatingNotaryFlow.kt index 61aa033940..d30180db05 100644 --- a/node/src/main/kotlin/net/corda/node/services/transactions/ValidatingNotaryFlow.kt +++ b/node/src/main/kotlin/net/corda/node/services/transactions/ValidatingNotaryFlow.kt @@ -3,7 +3,7 @@ package net.corda.node.services.transactions import co.paralleluniverse.fibers.Suspendable import net.corda.core.contracts.TransactionVerificationException import net.corda.core.identity.Party -import net.corda.core.node.services.TimestampChecker +import net.corda.core.node.services.TimeWindowChecker import net.corda.core.node.services.UniquenessProvider import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.WireTransaction @@ -18,9 +18,9 @@ import java.security.SignatureException * indeed valid. */ class ValidatingNotaryFlow(otherSide: Party, - timestampChecker: TimestampChecker, + timeWindowChecker: TimeWindowChecker, uniquenessProvider: UniquenessProvider) : - NotaryFlow.Service(otherSide, timestampChecker, uniquenessProvider) { + NotaryFlow.Service(otherSide, timeWindowChecker, uniquenessProvider) { /** * The received transaction is checked for contract-validity, which requires fully resolving it into a * [TransactionForVerification], for which the caller also has to to reveal the whole transaction @@ -32,7 +32,7 @@ class ValidatingNotaryFlow(otherSide: Party, checkSignatures(stx) val wtx = stx.tx validateTransaction(wtx) - return TransactionParts(wtx.id, wtx.inputs, wtx.timestamp) + return TransactionParts(wtx.id, wtx.inputs, wtx.timeWindow) } private fun checkSignatures(stx: SignedTransaction) { diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/ValidatingNotaryService.kt b/node/src/main/kotlin/net/corda/node/services/transactions/ValidatingNotaryService.kt index 60766b085a..72b819e90a 100644 --- a/node/src/main/kotlin/net/corda/node/services/transactions/ValidatingNotaryService.kt +++ b/node/src/main/kotlin/net/corda/node/services/transactions/ValidatingNotaryService.kt @@ -3,17 +3,17 @@ package net.corda.node.services.transactions import net.corda.core.flows.FlowLogic import net.corda.core.identity.Party import net.corda.core.node.services.ServiceType -import net.corda.core.node.services.TimestampChecker +import net.corda.core.node.services.TimeWindowChecker import net.corda.core.node.services.UniquenessProvider /** A Notary service that validates the transaction chain of the submitted transaction before committing it */ -class ValidatingNotaryService(val timestampChecker: TimestampChecker, +class ValidatingNotaryService(val timeWindowChecker: TimeWindowChecker, val uniquenessProvider: UniquenessProvider) : NotaryService { companion object { val type = ServiceType.notary.getSubType("validating") } override val serviceFlowFactory: (Party, Int) -> FlowLogic = { otherParty, _ -> - ValidatingNotaryFlow(otherParty, timestampChecker, uniquenessProvider) + ValidatingNotaryFlow(otherParty, timeWindowChecker, uniquenessProvider) } } diff --git a/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt b/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt index 1cde75adcf..0a59f2d54d 100644 --- a/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt +++ b/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt @@ -474,7 +474,7 @@ class TwoPartyTradeFlowTests { @Test fun `dependency with error on seller side`() { ledger { - runWithError(false, true, "must be timestamped") + runWithError(false, true, "Issuances must have a time-window") } } @@ -602,7 +602,7 @@ class TwoPartyTradeFlowTests { // Put a broken command on so at least a signature is created command(issuer.owningKey) { Cash.Commands.Move() } } - timestamp(TEST_TX_TIME) + timeWindow(TEST_TX_TIME) if (withError) { this.fails() } else { @@ -642,7 +642,7 @@ class TwoPartyTradeFlowTests { } command(MEGA_CORP_PUBKEY) { CommercialPaper.Commands.Issue() } if (!withError) - timestamp(time = TEST_TX_TIME) + timeWindow(time = TEST_TX_TIME) if (attachmentID != null) attachment(attachmentID) if (withError) { diff --git a/node/src/test/kotlin/net/corda/node/services/NotaryChangeTests.kt b/node/src/test/kotlin/net/corda/node/services/NotaryChangeTests.kt index c0be61f475..3216dfe83b 100644 --- a/node/src/test/kotlin/net/corda/node/services/NotaryChangeTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/NotaryChangeTests.kt @@ -170,7 +170,7 @@ fun issueMultiPartyState(nodeA: AbstractNode, nodeB: AbstractNode, notaryNode: A fun issueInvalidState(node: AbstractNode, notary: Party): StateAndRef<*> { val tx = DummyContract.generateInitial(Random().nextInt(), notary, node.info.legalIdentity.ref(0)) - tx.setTime(Instant.now(), 30.seconds) + tx.addTimeWindow(Instant.now(), 30.seconds) val stx = node.services.signInitialTransaction(tx) node.services.recordTransactions(listOf(stx)) return StateAndRef(tx.outputStates().first(), StateRef(stx.id, 0)) diff --git a/node/src/test/kotlin/net/corda/node/services/database/RequeryConfigurationTest.kt b/node/src/test/kotlin/net/corda/node/services/database/RequeryConfigurationTest.kt index 447769ea45..6d892f456c 100644 --- a/node/src/test/kotlin/net/corda/node/services/database/RequeryConfigurationTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/database/RequeryConfigurationTest.kt @@ -167,7 +167,7 @@ class RequeryConfigurationTest { notary = DUMMY_NOTARY, signers = emptyList(), type = TransactionType.General, - timestamp = null + timeWindow = null ) return SignedTransaction(wtx.serialized, listOf(DigitalSignature.WithKey(NullPublicKey, ByteArray(1)))) } diff --git a/node/src/test/kotlin/net/corda/node/services/persistence/DBTransactionStorageTests.kt b/node/src/test/kotlin/net/corda/node/services/persistence/DBTransactionStorageTests.kt index 981a1ed894..24c2b17dba 100644 --- a/node/src/test/kotlin/net/corda/node/services/persistence/DBTransactionStorageTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/persistence/DBTransactionStorageTests.kt @@ -154,7 +154,7 @@ class DBTransactionStorageTests { notary = DUMMY_NOTARY, signers = emptyList(), type = TransactionType.General, - timestamp = null + timeWindow = null ) return SignedTransaction(wtx.serialized, listOf(DigitalSignature.WithKey(NullPublicKey, ByteArray(1)))) } diff --git a/node/src/test/kotlin/net/corda/node/services/transactions/NotaryServiceTests.kt b/node/src/test/kotlin/net/corda/node/services/transactions/NotaryServiceTests.kt index 408cd5a545..eaf55f338e 100644 --- a/node/src/test/kotlin/net/corda/node/services/transactions/NotaryServiceTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/transactions/NotaryServiceTests.kt @@ -39,11 +39,11 @@ class NotaryServiceTests { net.runNetwork() // Clear network map registration messages } - @Test fun `should sign a unique transaction with a valid timestamp`() { + @Test fun `should sign a unique transaction with a valid time-window`() { val stx = run { val inputState = issueState(clientNode) val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState) - tx.setTime(Instant.now(), 30.seconds) + tx.addTimeWindow(Instant.now(), 30.seconds) clientNode.services.signInitialTransaction(tx) } @@ -52,7 +52,7 @@ class NotaryServiceTests { signatures.forEach { it.verify(stx.id) } } - @Test fun `should sign a unique transaction without a timestamp`() { + @Test fun `should sign a unique transaction without a time-window`() { val stx = run { val inputState = issueState(clientNode) val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState) @@ -64,18 +64,18 @@ class NotaryServiceTests { signatures.forEach { it.verify(stx.id) } } - @Test fun `should report error for transaction with an invalid timestamp`() { + @Test fun `should report error for transaction with an invalid time-window`() { val stx = run { val inputState = issueState(clientNode) val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState) - tx.setTime(Instant.now().plusSeconds(3600), 30.seconds) + tx.addTimeWindow(Instant.now().plusSeconds(3600), 30.seconds) clientNode.services.signInitialTransaction(tx) } val future = runNotaryClient(stx) val ex = assertFailsWith(NotaryException::class) { future.getOrThrow() } - assertThat(ex.error).isInstanceOf(NotaryError.TimestampInvalid::class.java) + assertThat(ex.error).isInstanceOf(NotaryError.TimeWindowInvalid::class.java) } @Test fun `should sign identical transaction multiple times (signing is idempotent)`() { diff --git a/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt b/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt index db8374cf34..a268106931 100644 --- a/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt @@ -701,7 +701,7 @@ class VaultQueryTests { val issuance = MEGA_CORP.ref(1) val commercialPaper = CommercialPaper().generateIssue(issuance, faceValue, TEST_TX_TIME + 30.days, DUMMY_NOTARY).apply { - setTime(TEST_TX_TIME, 30.seconds) + addTimeWindow(TEST_TX_TIME, 30.seconds) signWith(MEGA_CORP_KEY) signWith(DUMMY_NOTARY_KEY) }.toSignedTransaction() diff --git a/samples/attachment-demo/src/main/kotlin/net/corda/attachmentdemo/AttachmentDemo.kt b/samples/attachment-demo/src/main/kotlin/net/corda/attachmentdemo/AttachmentDemo.kt index 745d83e4cf..ad2bce7ed5 100644 --- a/samples/attachment-demo/src/main/kotlin/net/corda/attachmentdemo/AttachmentDemo.kt +++ b/samples/attachment-demo/src/main/kotlin/net/corda/attachmentdemo/AttachmentDemo.kt @@ -24,7 +24,6 @@ import net.corda.node.driver.poll import java.io.InputStream import java.net.HttpURLConnection import java.net.URL -import java.security.PublicKey import java.util.concurrent.Executors import java.util.jar.JarInputStream import javax.servlet.http.HttpServletResponse.SC_OK diff --git a/samples/bank-of-corda-demo/src/integration-test/kotlin/net/corda/bank/BankOfCordaHttpAPITest.kt b/samples/bank-of-corda-demo/src/integration-test/kotlin/net/corda/bank/BankOfCordaHttpAPITest.kt index 06192cca30..dbd82ff985 100644 --- a/samples/bank-of-corda-demo/src/integration-test/kotlin/net/corda/bank/BankOfCordaHttpAPITest.kt +++ b/samples/bank-of-corda-demo/src/integration-test/kotlin/net/corda/bank/BankOfCordaHttpAPITest.kt @@ -8,8 +8,6 @@ import net.corda.core.node.services.ServiceInfo import net.corda.node.driver.driver import net.corda.node.services.transactions.SimpleNotaryService import net.corda.testing.BOC -import net.corda.testing.http.HttpUtils -import org.bouncycastle.asn1.x500.X500Name import org.junit.Test import kotlin.test.assertTrue diff --git a/samples/irs-demo/src/main/kotlin/net/corda/irs/api/InterestRateSwapAPI.kt b/samples/irs-demo/src/main/kotlin/net/corda/irs/api/InterestRateSwapAPI.kt index 8f09afaebf..fcbbf31c21 100644 --- a/samples/irs-demo/src/main/kotlin/net/corda/irs/api/InterestRateSwapAPI.kt +++ b/samples/irs-demo/src/main/kotlin/net/corda/irs/api/InterestRateSwapAPI.kt @@ -2,7 +2,6 @@ package net.corda.irs.api import net.corda.client.rpc.notUsed import net.corda.core.contracts.filterStatesOfType -import net.corda.core.identity.Party import net.corda.core.getOrThrow import net.corda.core.messaging.CordaRPCOps import net.corda.core.messaging.startFlow diff --git a/samples/irs-demo/src/main/kotlin/net/corda/irs/contract/IRS.kt b/samples/irs-demo/src/main/kotlin/net/corda/irs/contract/IRS.kt index 4c21148852..5674787976 100644 --- a/samples/irs-demo/src/main/kotlin/net/corda/irs/contract/IRS.kt +++ b/samples/irs-demo/src/main/kotlin/net/corda/irs/contract/IRS.kt @@ -6,7 +6,6 @@ import net.corda.core.crypto.SecureHash import net.corda.core.crypto.containsAny import net.corda.core.flows.FlowLogicRefFactory import net.corda.core.identity.AbstractParty -import net.corda.core.identity.AnonymousParty import net.corda.core.identity.Party import net.corda.core.node.services.ServiceType import net.corda.core.serialization.CordaSerializable @@ -459,7 +458,7 @@ class InterestRateSwap : Contract { fixingCalendar, index, indexSource, indexTenor) } - override fun verify(tx: TransactionForContract) = verifyClause(tx, AllOf(Clauses.Timestamped(), Clauses.Group()), tx.commands.select()) + override fun verify(tx: TransactionForContract) = verifyClause(tx, AllOf(Clauses.TimeWindow(), Clauses.Group()), tx.commands.select()) interface Clauses { /** @@ -515,13 +514,13 @@ class InterestRateSwap : Contract { } } - class Timestamped : Clause() { + class TimeWindow : Clause() { override fun verify(tx: TransactionForContract, inputs: List, outputs: List, commands: List>, groupingKey: Unit?): Set { - require(tx.timestamp?.midpoint != null) { "must be timestamped" } + require(tx.timeWindow?.midpoint != null) { "must be have a time-window)" } // We return an empty set because we don't process any commands return emptySet() } diff --git a/samples/irs-demo/src/main/kotlin/net/corda/irs/flows/FixingFlow.kt b/samples/irs-demo/src/main/kotlin/net/corda/irs/flows/FixingFlow.kt index 045e56230c..7937b05908 100644 --- a/samples/irs-demo/src/main/kotlin/net/corda/irs/flows/FixingFlow.kt +++ b/samples/irs-demo/src/main/kotlin/net/corda/irs/flows/FixingFlow.kt @@ -77,9 +77,9 @@ object FixingFlow { override fun beforeSigning(fix: Fix) { newDeal.generateFix(ptx, StateAndRef(txState, handshake.payload.ref), fix) - // And add a request for timestamping: it may be that none of the contracts need this! But it can't hurt - // to have one. - ptx.setTime(serviceHub.clock.instant(), 30.seconds) + // And add a request for a time-window: it may be that none of the contracts need this! + // But it can't hurt to have one. + ptx.addTimeWindow(serviceHub.clock.instant(), 30.seconds) } @Suspendable diff --git a/samples/irs-demo/src/main/kotlin/net/corda/irs/flows/UpdateBusinessDayFlow.kt b/samples/irs-demo/src/main/kotlin/net/corda/irs/flows/UpdateBusinessDayFlow.kt index fd6d7c79cf..63f3215bd8 100644 --- a/samples/irs-demo/src/main/kotlin/net/corda/irs/flows/UpdateBusinessDayFlow.kt +++ b/samples/irs-demo/src/main/kotlin/net/corda/irs/flows/UpdateBusinessDayFlow.kt @@ -1,10 +1,10 @@ package net.corda.irs.flows import co.paralleluniverse.fibers.Suspendable -import net.corda.core.identity.Party import net.corda.core.flows.FlowLogic import net.corda.core.flows.InitiatingFlow import net.corda.core.flows.StartableByRPC +import net.corda.core.identity.Party import net.corda.core.node.CordaPluginRegistry import net.corda.core.node.NodeInfo import net.corda.core.node.PluginServiceHub @@ -66,7 +66,7 @@ object UpdateBusinessDayFlow { /** * Returns recipients ordered by legal name, with notary nodes taking priority over party nodes. * Ordering is required so that we avoid situations where on clock update a party starts a scheduled flow, but - * the notary or counterparty still use the old clock, so the timestamp on the transaction does not validate. + * the notary or counterparty still use the old clock, so the time-window on the transaction does not validate. */ private fun getRecipients(): Iterable { val notaryNodes = serviceHub.networkMapCache.notaryNodes diff --git a/samples/irs-demo/src/main/kotlin/net/corda/irs/plugin/IRSPlugin.kt b/samples/irs-demo/src/main/kotlin/net/corda/irs/plugin/IRSPlugin.kt index 343ebccb79..14519804e2 100644 --- a/samples/irs-demo/src/main/kotlin/net/corda/irs/plugin/IRSPlugin.kt +++ b/samples/irs-demo/src/main/kotlin/net/corda/irs/plugin/IRSPlugin.kt @@ -1,6 +1,5 @@ package net.corda.irs.plugin -import net.corda.core.identity.Party import net.corda.core.node.CordaPluginRegistry import net.corda.irs.api.InterestRateSwapAPI import net.corda.irs.flows.FixingFlow diff --git a/samples/irs-demo/src/main/kotlin/net/corda/simulation/TradeSimulation.kt b/samples/irs-demo/src/main/kotlin/net/corda/simulation/TradeSimulation.kt deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/samples/irs-demo/src/test/kotlin/net/corda/irs/testing/IRSTests.kt b/samples/irs-demo/src/test/kotlin/net/corda/irs/testing/IRSTests.kt index 6ca77b8058..199d00c6ac 100644 --- a/samples/irs-demo/src/test/kotlin/net/corda/irs/testing/IRSTests.kt +++ b/samples/irs-demo/src/test/kotlin/net/corda/irs/testing/IRSTests.kt @@ -1,7 +1,6 @@ package net.corda.irs.testing import net.corda.core.contracts.* -import net.corda.core.identity.AnonymousParty import net.corda.core.seconds import net.corda.core.transactions.SignedTransaction import net.corda.core.utilities.DUMMY_NOTARY @@ -224,7 +223,7 @@ class IRSTests { calculation = dummyIRS.calculation, common = dummyIRS.common, notary = DUMMY_NOTARY).apply { - setTime(TEST_TX_TIME, 30.seconds) + addTimeWindow(TEST_TX_TIME, 30.seconds) signWith(MEGA_CORP_KEY) signWith(MINI_CORP_KEY) signWith(DUMMY_NOTARY_KEY) @@ -310,7 +309,7 @@ class IRSTests { val fixing = Fix(nextFix, "0.052".percent.value) InterestRateSwap().generateFix(tx, previousTXN.tx.outRef(0), fixing) with(tx) { - setTime(TEST_TX_TIME, 30.seconds) + addTimeWindow(TEST_TX_TIME, 30.seconds) signWith(MEGA_CORP_KEY) signWith(MINI_CORP_KEY) signWith(DUMMY_NOTARY_KEY) @@ -375,7 +374,7 @@ class IRSTests { transaction("Agreement") { output("irs post agreement") { singleIRS() } command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) + timeWindow(TEST_TX_TIME) this.verifies() } @@ -393,7 +392,7 @@ class IRSTests { command(ORACLE_PUBKEY) { InterestRateSwap.Commands.Refix(Fix(FixOf("ICE LIBOR", ld, Tenor("3M")), bd)) } - timestamp(TEST_TX_TIME) + timeWindow(TEST_TX_TIME) this.verifies() } } @@ -406,7 +405,7 @@ class IRSTests { input { irs } output("irs post agreement") { irs } command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) + timeWindow(TEST_TX_TIME) this `fails with` "There are no in states for an agreement" } } @@ -420,7 +419,7 @@ class IRSTests { irs.copy(calculation = irs.calculation.copy(fixedLegPaymentSchedule = emptySchedule)) } command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) + timeWindow(TEST_TX_TIME) this `fails with` "There are events in the fix schedule" } } @@ -434,7 +433,7 @@ class IRSTests { irs.copy(calculation = irs.calculation.copy(floatingLegPaymentSchedule = emptySchedule)) } command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) + timeWindow(TEST_TX_TIME) this `fails with` "There are events in the float schedule" } } @@ -447,7 +446,7 @@ class IRSTests { irs.copy(irs.fixedLeg.copy(notional = irs.fixedLeg.notional.copy(quantity = 0))) } command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) + timeWindow(TEST_TX_TIME) this `fails with` "All notionals must be non zero" } @@ -456,7 +455,7 @@ class IRSTests { irs.copy(irs.fixedLeg.copy(notional = irs.floatingLeg.notional.copy(quantity = 0))) } command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) + timeWindow(TEST_TX_TIME) this `fails with` "All notionals must be non zero" } } @@ -470,7 +469,7 @@ class IRSTests { modifiedIRS } command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) + timeWindow(TEST_TX_TIME) this `fails with` "The fixed leg rate must be positive" } } @@ -487,7 +486,7 @@ class IRSTests { modifiedIRS } command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) + timeWindow(TEST_TX_TIME) this `fails with` "The currency of the notionals must be the same" } } @@ -501,7 +500,7 @@ class IRSTests { modifiedIRS } command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) + timeWindow(TEST_TX_TIME) this `fails with` "All leg notionals must be the same" } } @@ -515,7 +514,7 @@ class IRSTests { modifiedIRS1 } command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) + timeWindow(TEST_TX_TIME) this `fails with` "The effective date is before the termination date for the fixed leg" } @@ -525,7 +524,7 @@ class IRSTests { modifiedIRS2 } command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) + timeWindow(TEST_TX_TIME) this `fails with` "The effective date is before the termination date for the floating leg" } } @@ -540,7 +539,7 @@ class IRSTests { modifiedIRS3 } command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) + timeWindow(TEST_TX_TIME) this `fails with` "The termination dates are aligned" } @@ -551,7 +550,7 @@ class IRSTests { modifiedIRS4 } command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) + timeWindow(TEST_TX_TIME) this `fails with` "The effective dates are aligned" } } @@ -565,7 +564,7 @@ class IRSTests { transaction { output("irs post agreement") { singleIRS() } command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) + timeWindow(TEST_TX_TIME) this.verifies() } @@ -586,7 +585,7 @@ class IRSTests { command(ORACLE_PUBKEY) { InterestRateSwap.Commands.Refix(Fix(FixOf("ICE LIBOR", ld, Tenor("3M")), bd)) } - timestamp(TEST_TX_TIME) + timeWindow(TEST_TX_TIME) output { newIRS } this.verifies() } @@ -594,7 +593,7 @@ class IRSTests { // This test makes sure that verify confirms the fixing was applied and there is a difference in the old and new tweak { command(ORACLE_PUBKEY) { InterestRateSwap.Commands.Refix(Fix(FixOf("ICE LIBOR", ld, Tenor("3M")), bd)) } - timestamp(TEST_TX_TIME) + timeWindow(TEST_TX_TIME) output { oldIRS } this `fails with` "There is at least one difference in the IRS floating leg payment schedules" } @@ -602,7 +601,7 @@ class IRSTests { // This tests tries to sneak in a change to another fixing (which may or may not be the latest one) tweak { command(ORACLE_PUBKEY) { InterestRateSwap.Commands.Refix(Fix(FixOf("ICE LIBOR", ld, Tenor("3M")), bd)) } - timestamp(TEST_TX_TIME) + timeWindow(TEST_TX_TIME) val firstResetKey = newIRS.calculation.floatingLegPaymentSchedule.keys.toList()[1] val firstResetValue = newIRS.calculation.floatingLegPaymentSchedule[firstResetKey] @@ -623,7 +622,7 @@ class IRSTests { // This tests modifies the payment currency for the fixing tweak { command(ORACLE_PUBKEY) { InterestRateSwap.Commands.Refix(Fix(FixOf("ICE LIBOR", ld, Tenor("3M")), bd)) } - timestamp(TEST_TX_TIME) + timeWindow(TEST_TX_TIME) val latestReset = newIRS.calculation.floatingLegPaymentSchedule.filter { it.value.rate is FixedRate }.maxBy { it.key } val modifiedLatestResetValue = latestReset!!.value.copy(notional = Amount(latestReset.value.notional.quantity, Currency.getInstance("JPY"))) @@ -666,7 +665,7 @@ class IRSTests { ) } command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) + timeWindow(TEST_TX_TIME) this.verifies() } @@ -681,7 +680,7 @@ class IRSTests { ) } command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) + timeWindow(TEST_TX_TIME) this.verifies() } @@ -710,7 +709,7 @@ class IRSTests { command(ORACLE_PUBKEY) { InterestRateSwap.Commands.Refix(Fix(FixOf("ICE LIBOR", ld1, Tenor("3M")), bd1)) } - timestamp(TEST_TX_TIME) + timeWindow(TEST_TX_TIME) this.verifies() } } diff --git a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/contracts/OGTrade.kt b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/contracts/OGTrade.kt index 97cc7dc43b..15f39c7ebf 100644 --- a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/contracts/OGTrade.kt +++ b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/contracts/OGTrade.kt @@ -9,20 +9,20 @@ import java.math.BigDecimal * Specifies the contract between two parties that trade an OpenGamma IRS. Currently can only agree to trade. */ data class OGTrade(override val legalContractReference: SecureHash = SecureHash.sha256("OGTRADE.KT")) : Contract { - override fun verify(tx: TransactionForContract) = verifyClause(tx, AllOf(Clauses.Timestamped(), Clauses.Group()), tx.commands.select()) + override fun verify(tx: TransactionForContract) = verifyClause(tx, AllOf(Clauses.TimeWindowed(), Clauses.Group()), tx.commands.select()) interface Commands : CommandData { class Agree : TypeOnlyCommandData(), Commands // Both sides agree to trade } interface Clauses { - class Timestamped : Clause() { + class TimeWindowed : Clause() { override fun verify(tx: TransactionForContract, inputs: List, outputs: List, commands: List>, groupingKey: Unit?): Set { - require(tx.timestamp?.midpoint != null) { "must be timestamped" } + require(tx.timeWindow?.midpoint != null) { "must have a time-window" } // We return an empty set because we don't process any commands return emptySet() } diff --git a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/contracts/PortfolioSwap.kt b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/contracts/PortfolioSwap.kt index 4dad44ad41..bd464ae552 100644 --- a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/contracts/PortfolioSwap.kt +++ b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/contracts/PortfolioSwap.kt @@ -10,7 +10,7 @@ import net.corda.core.crypto.SecureHash * of the portfolio arbitrarily. */ data class PortfolioSwap(override val legalContractReference: SecureHash = SecureHash.sha256("swordfish")) : Contract { - override fun verify(tx: TransactionForContract) = verifyClause(tx, AllOf(Clauses.Timestamped(), Clauses.Group()), tx.commands.select()) + override fun verify(tx: TransactionForContract) = verifyClause(tx, AllOf(Clauses.TimeWindowed(), Clauses.Group()), tx.commands.select()) interface Commands : CommandData { class Agree : TypeOnlyCommandData(), Commands // Both sides agree to portfolio @@ -18,13 +18,13 @@ data class PortfolioSwap(override val legalContractReference: SecureHash = Secur } interface Clauses { - class Timestamped : Clause() { + class TimeWindowed : Clause() { override fun verify(tx: TransactionForContract, inputs: List, outputs: List, commands: List>, groupingKey: Unit?): Set { - require(tx.timestamp?.midpoint != null) { "must be timestamped" } + require(tx.timeWindow?.midpoint != null) { "must have a time-window)" } // We return an empty set because we don't process any commands return emptySet() } diff --git a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/SimmFlow.kt b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/SimmFlow.kt index 94061ba0d5..251a5436ed 100644 --- a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/SimmFlow.kt +++ b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/SimmFlow.kt @@ -13,7 +13,6 @@ import net.corda.core.contracts.StateRef import net.corda.core.flows.FlowLogic import net.corda.core.flows.InitiatingFlow import net.corda.core.flows.StartableByRPC -import net.corda.core.identity.AnonymousParty import net.corda.core.identity.Party import net.corda.core.node.PluginServiceHub import net.corda.core.node.services.dealsWith diff --git a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/StateRevisionFlow.kt b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/StateRevisionFlow.kt index d31711549b..889a7071b1 100644 --- a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/StateRevisionFlow.kt +++ b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/StateRevisionFlow.kt @@ -8,7 +8,6 @@ import net.corda.core.transactions.SignedTransaction import net.corda.flows.AbstractStateReplacementFlow import net.corda.flows.StateReplacementException import net.corda.vega.contracts.RevisionedState -import java.security.PublicKey /** * Flow that generates an update on a mutable deal state and commits the resulting transaction reaching consensus @@ -20,7 +19,7 @@ object StateRevisionFlow { override fun assembleTx(): Pair> { val state = originalState.state.data val tx = state.generateRevision(originalState.state.notary, originalState, modification) - tx.setTime(serviceHub.clock.instant(), 30.seconds) + tx.addTimeWindow(serviceHub.clock.instant(), 30.seconds) val stx = serviceHub.signInitialTransaction(tx) return Pair(stx, state.participants) diff --git a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/services/SimmService.kt b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/services/SimmService.kt index 06d14023d7..d1f43d93b8 100644 --- a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/services/SimmService.kt +++ b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/services/SimmService.kt @@ -10,7 +10,6 @@ import com.opengamma.strata.market.curve.CurveName import com.opengamma.strata.market.param.CurrencyParameterSensitivities import com.opengamma.strata.market.param.CurrencyParameterSensitivity import com.opengamma.strata.market.param.TenorDateParameterMetadata -import net.corda.core.identity.Party import net.corda.core.node.CordaPluginRegistry import net.corda.core.serialization.SerializationCustomization import net.corda.vega.analytics.CordaMarketData diff --git a/samples/simm-valuation-demo/src/test/kotlin/net/corda/vega/SwapExample.kt b/samples/simm-valuation-demo/src/test/kotlin/net/corda/vega/SwapExample.kt index 1afb906701..96c22c135f 100644 --- a/samples/simm-valuation-demo/src/test/kotlin/net/corda/vega/SwapExample.kt +++ b/samples/simm-valuation-demo/src/test/kotlin/net/corda/vega/SwapExample.kt @@ -52,7 +52,7 @@ fun main(args: Array) { class SwapExample { - val VALUATION_DATE = LocalDate.of(2016, 6, 6) + val VALUATION_DATE = LocalDate.of(2016, 6, 6)!! fun main(@Suppress("UNUSED_PARAMETER") args: Array) { val curveGroupDefinition = loadCurveGroup() diff --git a/samples/trader-demo/src/main/kotlin/net/corda/traderdemo/flow/SellerFlow.kt b/samples/trader-demo/src/main/kotlin/net/corda/traderdemo/flow/SellerFlow.kt index 8a6239684b..3a7ecba1d7 100644 --- a/samples/trader-demo/src/main/kotlin/net/corda/traderdemo/flow/SellerFlow.kt +++ b/samples/trader-demo/src/main/kotlin/net/corda/traderdemo/flow/SellerFlow.kt @@ -10,8 +10,8 @@ import net.corda.core.days import net.corda.core.flows.FlowLogic import net.corda.core.flows.InitiatingFlow import net.corda.core.flows.StartableByRPC -import net.corda.core.identity.Party import net.corda.core.identity.AbstractParty +import net.corda.core.identity.Party import net.corda.core.node.NodeInfo import net.corda.core.seconds import net.corda.core.transactions.SignedTransaction @@ -19,7 +19,6 @@ import net.corda.core.utilities.ProgressTracker import net.corda.flows.NotaryFlow import net.corda.flows.TwoPartyTradeFlow import net.corda.testing.BOC -import java.security.PublicKey import java.time.Instant import java.util.* @@ -82,13 +81,13 @@ class SellerFlow(val otherParty: Party, // Attach the prospectus. tx.addAttachment(serviceHub.storageService.attachments.openAttachment(PROSPECTUS_HASH)!!.id) - // Requesting timestamping, all CP must be timestamped. - tx.setTime(Instant.now(), 30.seconds) + // Requesting a time-window to be set, all CP must have a validation window. + tx.addTimeWindow(Instant.now(), 30.seconds) // Sign it as ourselves. tx.signWith(keyPair) - // Get the notary to sign the timestamp + // Get the notary to sign the time-window. val notarySigs = subFlow(NotaryFlow.Client(tx.toSignedTransaction(false))) notarySigs.forEach { tx.addSignatureUnchecked(it) } diff --git a/test-utils/src/main/kotlin/net/corda/testing/TestDSL.kt b/test-utils/src/main/kotlin/net/corda/testing/TestDSL.kt index 8566851baa..7a0e41094b 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/TestDSL.kt +++ b/test-utils/src/main/kotlin/net/corda/testing/TestDSL.kt @@ -145,8 +145,8 @@ data class TestTransactionDSLInterpreter private constructor( return EnforceVerifyOrFail.Token } - override fun timestamp(data: Timestamp) { - transactionBuilder.setTime(data) + override fun timeWindow(data: TimeWindow) { + transactionBuilder.addTimeWindow(data) } override fun tweak( diff --git a/test-utils/src/main/kotlin/net/corda/testing/TransactionDSLInterpreter.kt b/test-utils/src/main/kotlin/net/corda/testing/TransactionDSLInterpreter.kt index 27d69dcc2e..b806e699de 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/TransactionDSLInterpreter.kt +++ b/test-utils/src/main/kotlin/net/corda/testing/TransactionDSLInterpreter.kt @@ -1,8 +1,8 @@ package net.corda.testing import net.corda.core.contracts.* -import net.corda.core.identity.Party import net.corda.core.crypto.SecureHash +import net.corda.core.identity.Party import net.corda.core.seconds import net.corda.core.transactions.TransactionBuilder import net.corda.core.utilities.DUMMY_NOTARY @@ -51,10 +51,10 @@ interface TransactionDSLInterpreter : Verifies, OutputStateLookup { fun _command(signers: List, commandData: CommandData) /** - * Adds a timestamp to the transaction. - * @param data The [TimestampCommand]. + * Adds a time-window to the transaction. + * @param data the [TimeWindow] (validation window). */ - fun timestamp(data: Timestamp) + fun timeWindow(data: TimeWindow) /** * Creates a local scoped copy of the transaction. @@ -115,11 +115,11 @@ class TransactionDSL(val interpreter: T) : Tr fun command(signer: PublicKey, commandData: CommandData) = _command(listOf(signer), commandData) /** - * Adds a timestamp command to the transaction. - * @param time The [Instant] of the [TimestampCommand]. - * @param tolerance The tolerance of the [TimestampCommand]. + * Adds a [TimeWindow] command to the transaction. + * @param time The [Instant] of the [TimeWindow]. + * @param tolerance The tolerance of the [TimeWindow]. */ @JvmOverloads - fun timestamp(time: Instant, tolerance: Duration = 30.seconds) = - timestamp(Timestamp(time, tolerance)) + fun timeWindow(time: Instant, tolerance: Duration = 30.seconds) = + timeWindow(TimeWindow.withTolerance(time, tolerance)) } From 35ee60f12b9fb2ebe25610d506447e6824e4037d Mon Sep 17 00:00:00 2001 From: Chris Rankin Date: Thu, 25 May 2017 14:12:58 +0100 Subject: [PATCH 004/126] Require user R3CEV for DemoBench DMG signing key. (#737) --- tools/demobench/build.gradle | 9 +++++++-- .../package/macosx/Corda DemoBench-post-image.sh | 4 ++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/tools/demobench/build.gradle b/tools/demobench/build.gradle index 6005379e4b..245842bde6 100644 --- a/tools/demobench/build.gradle +++ b/tools/demobench/build.gradle @@ -9,6 +9,7 @@ buildscript { ext.pkg_outDir = "$buildDir/javapackage" ext.dist_source = "$pkg_source/demobench-$version" ext.pkg_version = "$version".indexOf('-') >= 0 ? "$version".substring(0, "$version".indexOf('-')) : version + ext.pkg_macosxKeyUserName = 'R3CEV' repositories { mavenLocal() @@ -160,8 +161,9 @@ task javapackage(dependsOn: distZip) { include '**/*.wsf' include '**/*.manifest' } - filter { - line -> line.replaceAll('@pkg_version@', pkg_version) + filter { line -> + line.replaceAll('@pkg_version@', pkg_version) + .replaceAll('@signingKeyUserName@', pkg_macosxKeyUserName) } into "$pkg_source/package" } @@ -193,6 +195,9 @@ task javapackage(dependsOn: distZip) { } } + // This is specific to MacOSX packager. + bundleArgument(arg: 'mac.signing-key-user-name', value: pkg_macosxKeyUserName) + platform { property(name: 'java.util.logging.config.class', value: 'net.corda.demobench.config.LoggingConfig') property(name: 'org.jboss.logging.provider', value: 'slf4j') diff --git a/tools/demobench/package/macosx/Corda DemoBench-post-image.sh b/tools/demobench/package/macosx/Corda DemoBench-post-image.sh index c38febc5f0..0e0f57cbf6 100644 --- a/tools/demobench/package/macosx/Corda DemoBench-post-image.sh +++ b/tools/demobench/package/macosx/Corda DemoBench-post-image.sh @@ -9,7 +9,7 @@ function signApplication() { # Resign the embedded JRE because we have included "bin/java" # after javapackager had already signed the JRE installation. - if ! (codesign --force --sign "$IDENTITY" --verbose "$APPDIR/Contents/PlugIns/Java.runtime"); then + if ! (codesign --force --sign "$IDENTITY" --preserve-metadata=identifier,entitlements,requirements --verbose "$APPDIR/Contents/PlugIns/Java.runtime"); then echo "**** Failed to resign the embedded JVM" return 1 fi @@ -27,7 +27,7 @@ fi cd .. # Sign the application using a 'Developer ID Application' key on our keychain. -if ! (signApplication "Corda DemoBench.app" "Developer ID Application: "); then +if ! (signApplication "Corda DemoBench.app" "Developer ID Application: @signingKeyUserName@"); then echo "**** Failed to sign the application - ABORT SIGNING" fi From bcf4c4a2bbe37a03ba0419ab462351420d5bb9dc Mon Sep 17 00:00:00 2001 From: Chris Rankin Date: Thu, 25 May 2017 15:24:18 +0100 Subject: [PATCH 005/126] Document how we should test DemoBench. (#742) --- tools/demobench/README.md | 119 +++++++++++++++++++ tools/demobench/demobench-configure-bank.png | Bin 0 -> 62526 bytes tools/demobench/demobench-dashboard.png | Bin 0 -> 128002 bytes tools/demobench/demobench-initial.png | Bin 0 -> 43631 bytes tools/demobench/demobench-notary.png | Bin 0 -> 83497 bytes tools/demobench/demobench-save-profile.png | Bin 0 -> 104748 bytes 6 files changed, 119 insertions(+) create mode 100644 tools/demobench/README.md create mode 100644 tools/demobench/demobench-configure-bank.png create mode 100644 tools/demobench/demobench-dashboard.png create mode 100644 tools/demobench/demobench-initial.png create mode 100644 tools/demobench/demobench-notary.png create mode 100644 tools/demobench/demobench-save-profile.png diff --git a/tools/demobench/README.md b/tools/demobench/README.md new file mode 100644 index 0000000000..dc42716039 --- /dev/null +++ b/tools/demobench/README.md @@ -0,0 +1,119 @@ +# DemoBench + +DemoBench is a standalone desktop application that makes it easy to configure +and launch local Corda nodes. Its general usage is documented +[here](https://docs.corda.net/demobench.html). + +## Running locally + +**MacOSX/Linux:** + + ./gradlew tools:demobench:installDist + cd tools/demobench/build/install/demobench + bin/demobench + +**Windows:** + + gradlew tools:demobench:installDist + cd tools\demobench\build\install\demobench + +and then + + bin\demobench + +or, if Windows complains that the command line is too long: + + java -Djava.util.logging.config.class=net.corda.demobench.config.LoggingConfig -jar lib\demobench-$version.jar + +## Testing +### The Notary Node + +When launched, DemoBench will look something like this: + +![DemoBench at launch](demobench-initial.png) + +Clicking the `Start node` button should launch a new Notary node. + +![Notary node](demobench-notary.png) + +The tab should display the correct national flag for the node's geographical +location. The `View Database`, `Launch Web Server` and `Launch Explorer` buttons +will be disabled until the node has finished booting, at which point the node +statistics (`States in vault`, `Known transactions` and `Balance`) will become +populated too. + +The Corda node should boot into a shell with a command prompt. Type `help` at +this command prompt to list the commands available, followed by `dashboard`. + +![Dashboard for Notary node](demobench-dashboard.png) + +Press `q` to exit the dashboard, and then check the tab's buttons: + +- Press `View Database` to launch the H2 database's Web console in your browser. +Pressing this button again should launch a second console session. +- Press the `Launch Web Server` button to launch the Corda Webserver for this +node. Once booted, it should open your browser to a page saying: +> ### Installed CorDaps +> No installed custom CorDapps + +- The button's text should now have changed to `Reopen web site`. Pressing the +button again should open a new session in your browser. + +- Press the `Launch Explorer` button to launch the [Node Explorer](https://docs.corda.net/node-explorer.html) for this notary. You should be logged into the +Explorer automatically. The `Launch Explorer` button should now remain disabled +until you close this node's Explorer again. + +### The Bank Node + +Click the `Add Node` button, and DemoBench will ask you to configure another +node in a new tab. + +![Configure Bank Node](demobench-configure-bank.png) + +This time, there will be additional services available. Select `corda.cash` and +`corda.issuer.GBP`, and then press the `Start node` button. + +When you press the `Launch Web Server` this time, your browser should open to a +page saying: +> ### Installed CorDapps +> **net.corda.bank.plugin.BankOfCordaPlugin**
+> net.corda.bank.api.BankOfCordaWebApi: +> - POST issue-asset-request +> - GET date + +Clicking on the `GET date` link should return today's date within a JSON document. + +Launch the bank's Node Explorer, and check the network view. The Notary node +should be displayed in Rome, whereas the Bank of Breakfast Tea should be in +Liverpool. + +## Saving / Loading profiles + +Choose `File/Save As` from DemoBench's main menu. + +![Save Profile Dialogue](demobench-save-profile.png) + +Save the profile and then examine its contents (ZIP format). It should look +something like: + +``` + Length Date Time Name +--------- ---------- ----- ---- + 0 05-25-2017 11:57 notary/ + 490 05-25-2017 11:57 notary/node.conf + 0 05-25-2017 11:57 notary/plugins/ + 0 05-25-2017 11:57 bankofbreakfasttea/ + 673 05-25-2017 11:57 bankofbreakfasttea/node.conf + 0 05-25-2017 11:57 bankofbreakfasttea/plugins/ +--------- ------- + 1163 6 files +``` + +Now choose `File/Open` from the main menu, and select the profile that you have +just saved. DemoBench should close the two existing tabs and then relaunch the +Notary and Bank nodes. + +## Exiting DemoBench + +Close DemoBench as a normal application on your platform; it should close any +open Node Explorers before exiting. diff --git a/tools/demobench/demobench-configure-bank.png b/tools/demobench/demobench-configure-bank.png new file mode 100644 index 0000000000000000000000000000000000000000..5e2c01211b75612f9fbb62dd9fb8d14ac45125bc GIT binary patch literal 62526 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�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 E0R)o^ZvX%Q literal 0 HcmV?d00001 diff --git a/tools/demobench/demobench-notary.png b/tools/demobench/demobench-notary.png new file mode 100644 index 0000000000000000000000000000000000000000..519df2fac1203a429f10fa280ddf7fbe6748f4f8 GIT binary patch literal 83497 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 literal 0 HcmV?d00001 diff --git a/tools/demobench/demobench-save-profile.png b/tools/demobench/demobench-save-profile.png new file mode 100644 index 0000000000000000000000000000000000000000..c03c2787451ab55dc81adde1e0bc06f8278f455e GIT binary patch literal 104748 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ν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 Date: Thu, 25 May 2017 17:18:51 +0100 Subject: [PATCH 006/126] Forbid internal classes from being serialised. (#655) --- core/src/main/kotlin/net/corda/core/Utils.kt | 5 ++++- node-api/src/main/kotlin/net/corda/nodeapi/RPCStructures.kt | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/core/src/main/kotlin/net/corda/core/Utils.kt b/core/src/main/kotlin/net/corda/core/Utils.kt index 89fd25e6e9..0e92a0614c 100644 --- a/core/src/main/kotlin/net/corda/core/Utils.kt +++ b/core/src/main/kotlin/net/corda/core/Utils.kt @@ -472,4 +472,7 @@ fun Class.checkNotUnorderedHashMap() { if (HashMap::class.java.isAssignableFrom(this) && !LinkedHashMap::class.java.isAssignableFrom(this)) { throw NotSerializableException("Map type $this is unstable under iteration. Suggested fix: use LinkedHashMap instead.") } -} \ No newline at end of file +} + +fun Class<*>.requireExternal(msg: String = "Internal class") + = require(!name.startsWith("net.corda.node.") && !name.contains(".internal.")) { "$msg: $name" } diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/RPCStructures.kt b/node-api/src/main/kotlin/net/corda/nodeapi/RPCStructures.kt index bda75a2bd4..d1c090f2ca 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/RPCStructures.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/RPCStructures.kt @@ -5,6 +5,7 @@ package net.corda.nodeapi import com.esotericsoftware.kryo.Registration import com.esotericsoftware.kryo.Serializer import com.google.common.util.concurrent.ListenableFuture +import net.corda.core.requireExternal import net.corda.core.serialization.* import net.corda.core.toFuture import net.corda.core.toObservable @@ -60,6 +61,7 @@ class RPCKryo(observableSerializer: Serializer>) : CordaKryo(mak } override fun getRegistration(type: Class<*>): Registration { + type.requireExternal("RPC not allowed to deserialise internal classes") if (Observable::class.java != type && Observable::class.java.isAssignableFrom(type)) { return super.getRegistration(Observable::class.java) } From 851cccbf7e2d4c3a219ce4633f76f305f1318271 Mon Sep 17 00:00:00 2001 From: Andrzej Cichocki Date: Thu, 25 May 2017 17:31:14 +0100 Subject: [PATCH 007/126] Don't persist loaded keyPair to the keystore when owningKey is composite (#744) --- .../net/corda/node/internal/AbstractNode.kt | 44 ++++++++++++------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt index 05fb63cb1a..fb50a92c07 100644 --- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt @@ -61,7 +61,6 @@ import org.jetbrains.exposed.sql.Database import org.slf4j.Logger import java.io.IOException import java.lang.reflect.Modifier.* -import java.net.InetAddress import java.net.URL import java.nio.file.FileAlreadyExistsException import java.nio.file.Path @@ -589,10 +588,11 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, stateMachineRecordedTransactionMappingStorage: StateMachineRecordedTransactionMappingStorage) = StorageServiceImpl(attachments, transactionStorage, stateMachineRecordedTransactionMappingStorage) - protected fun obtainLegalIdentity(): Party = obtainKeyPair().first - protected fun obtainLegalIdentityKey(): KeyPair = obtainKeyPair().second + protected fun obtainLegalIdentity(): Party = identityKeyPair.first + protected fun obtainLegalIdentityKey(): KeyPair = identityKeyPair.second + private val identityKeyPair by lazy { obtainKeyPair("identity", configuration.myLegalName) } - private fun obtainKeyPair(serviceId: String = "identity", serviceName: X500Name = configuration.myLegalName): Pair { + private fun obtainKeyPair(serviceId: String, serviceName: X500Name): Pair { // Load the private identity key, creating it if necessary. The identity key is a long term well known key that // is distributed to other peers and we use it (or a key signed by it) when we need to do something // "permissioned". The identity file is what gets distributed and contains the node's legal name along with @@ -600,22 +600,19 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, // the legal name is actually validated in some way. // TODO: Integrate with Key management service? - val keystore = KeyStoreUtilities.loadKeyStore(configuration.nodeKeystore, configuration.keyStorePassword) - val clientCA = keystore.getCertificateAndKeyPair(X509Utilities.CORDA_CLIENT_CA, configuration.keyStorePassword) + val keyStore = KeyStoreWrapper(configuration.nodeKeystore, configuration.keyStorePassword) val privateKeyAlias = "$serviceId-private-key" val privKeyFile = configuration.baseDirectory / privateKeyAlias val pubIdentityFile = configuration.baseDirectory / "$serviceId-public" - - val identityAndKey = if (configuration.nodeKeystore.exists() && keystore.containsAlias(privateKeyAlias)) { + val identityAndKey = keyStore.certificateAndKeyPair(privateKeyAlias)?.let { (cert, keyPair) -> // Get keys from keystore. - val (cert, keyPair) = keystore.getCertificateAndKeyPair(privateKeyAlias, configuration.keyStorePassword) val loadedServiceName = X509CertificateHolder(cert.encoded).subject - if (X509CertificateHolder(cert.encoded).subject != serviceName) { + if (loadedServiceName != serviceName) { throw ConfigurationException("The legal name in the config file doesn't match the stored identity keystore:" + "$serviceName vs $loadedServiceName") } Pair(Party(loadedServiceName, keyPair.public), keyPair) - } else if (privKeyFile.exists()) { + } ?: if (privKeyFile.exists()) { // Get keys from key file. // TODO: this is here to smooth out the key storage transition, remove this in future release. // Check that the identity in the config file matches the identity file we have stored to disk. @@ -627,17 +624,15 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, "$serviceName vs ${myIdentity.name}") // Load the private key. val keyPair = privKeyFile.readAll().deserialize() - val cert = X509Utilities.createCertificate(CertificateType.IDENTITY, clientCA.certificate, clientCA.keyPair, serviceName, keyPair.public) - keystore.addOrReplaceKey(privateKeyAlias, keyPair.private, configuration.keyStorePassword.toCharArray(), arrayOf(cert, *keystore.getCertificateChain(X509Utilities.CORDA_CLIENT_CA))) - keystore.save(configuration.nodeKeystore, configuration.keyStorePassword) + if (myIdentity.owningKey !is CompositeKey) { // TODO: Support case where owningKey is a composite key. + keyStore.save(serviceName, privateKeyAlias, keyPair) + } Pair(myIdentity, keyPair) } else { // Create new keys and store in keystore. log.info("Identity key not found, generating fresh key!") val keyPair: KeyPair = generateKeyPair() - val cert = X509Utilities.createCertificate(CertificateType.IDENTITY, clientCA.certificate, clientCA.keyPair, serviceName, keyPair.public) - keystore.addOrReplaceKey(privateKeyAlias, keyPair.private, configuration.keyStorePassword.toCharArray(), arrayOf(cert, *keystore.getCertificateChain(X509Utilities.CORDA_CLIENT_CA))) - keystore.save(configuration.nodeKeystore, configuration.keyStorePassword) + keyStore.save(serviceName, privateKeyAlias, keyPair) Pair(Party(serviceName, keyPair.public), keyPair) } partyKeys += identityAndKey.second @@ -664,3 +659,18 @@ sealed class ServiceFlowInfo { data class Core(val factory: (Party, Int) -> FlowLogic<*>) : ServiceFlowInfo() data class CorDapp(val version: Int, val factory: (Party) -> FlowLogic<*>) : ServiceFlowInfo() } + +private class KeyStoreWrapper(private val storePath: Path, private val storePassword: String) { + private val keyStore = KeyStoreUtilities.loadKeyStore(storePath, storePassword) + + fun certificateAndKeyPair(alias: String): CertificateAndKeyPair? { + return if (keyStore.containsAlias(alias)) keyStore.getCertificateAndKeyPair(alias, storePassword) else null + } + + fun save(serviceName: X500Name, privateKeyAlias: String, keyPair: KeyPair) { + val clientCA = keyStore.getCertificateAndKeyPair(X509Utilities.CORDA_CLIENT_CA, storePassword) + val cert = X509Utilities.createCertificate(CertificateType.IDENTITY, clientCA.certificate, clientCA.keyPair, serviceName, keyPair.public) + keyStore.addOrReplaceKey(privateKeyAlias, keyPair.private, storePassword.toCharArray(), arrayOf(cert, *keyStore.getCertificateChain(X509Utilities.CORDA_CLIENT_CA))) + keyStore.save(storePath, storePassword) + } +} From 0fc38d71dcbe47dee5f77c5b785c71aa1c830e6e Mon Sep 17 00:00:00 2001 From: Matthew Nesbit Date: Fri, 26 May 2017 09:39:42 +0100 Subject: [PATCH 008/126] Ignore the flaky sandbox test, which keeps throwing stackoverflow exceptions. --- .../test/java/net/corda/sandbox/WhitelistClassLoaderTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/experimental/sandbox/src/test/java/net/corda/sandbox/WhitelistClassLoaderTest.java b/experimental/sandbox/src/test/java/net/corda/sandbox/WhitelistClassLoaderTest.java index 3c427527c6..91d455b0d2 100644 --- a/experimental/sandbox/src/test/java/net/corda/sandbox/WhitelistClassLoaderTest.java +++ b/experimental/sandbox/src/test/java/net/corda/sandbox/WhitelistClassLoaderTest.java @@ -67,6 +67,8 @@ public class WhitelistClassLoaderTest { assertNotNull("Created object appears to be null", o); } + //TODO This code frequently throws StackOverflowException, despite this being explicitly what the code is trying to prevent!! + @Ignore @Test(expected = ClassNotFoundException.class) public void given_OverlyDeeplyTransitivelyLinkedClasses_then_ClassCanBeLoaded() throws Exception { Class clz = wlcl.loadClass("transitive.Chain4498"); From a8d4dccea4fbcd97e28fcd2e6f32c739711425f0 Mon Sep 17 00:00:00 2001 From: Ross Nicoll Date: Tue, 16 May 2017 15:30:26 +0100 Subject: [PATCH 009/126] Infrastructure for confidential identities * De-anonymise parties in AbstractStateReplacementFlow flows * Convert transaction key negotiation to a subflow instead of utility functions * Add serialization support for CertPath * Restructure cash flows so that a counterparty flow can be added later --- .../net/corda/jackson/JacksonSupport.kt | 11 +-- .../net/corda/core/crypto/X509Utilities.kt | 3 + .../kotlin/net/corda/core/flows/TxKeyFlow.kt | 95 +++++++++++++++++++ .../core/node/services/IdentityService.kt | 23 +++++ .../net/corda/core/node/services/Services.kt | 17 +++- .../net/corda/flows/TxKeyFlowUtilities.kt | 41 -------- .../kotlin/net/corda/core/flows/TxKeyFlow.kt | 55 ----------- .../net/corda/core/flows/TxKeyFlowTests.kt | 53 +++++++++++ .../core/flows/TxKeyFlowUtilitiesTests.kt | 40 -------- .../net/corda/contracts/asset/CashTests.kt | 2 +- .../net/corda/node/internal/AbstractNode.kt | 6 +- .../identity/InMemoryIdentityService.kt | 11 ++- .../keys/E2ETestKeyManagementService.kt | 9 +- .../net/corda/node/services/keys/KMSUtils.kt | 37 ++++++++ .../keys/PersistentKeyManagementService.kt | 9 +- .../statemachine/StateMachineManager.kt | 2 +- .../events/NodeSchedulerServiceTest.kt | 4 +- .../network/InMemoryIdentityServiceTests.kt | 10 ++ .../kotlin/net/corda/testing/node/MockNode.kt | 9 +- .../net/corda/testing/node/MockServices.kt | 15 ++- .../net/corda/testing/node/SimpleNode.kt | 7 +- 21 files changed, 295 insertions(+), 164 deletions(-) create mode 100644 core/src/main/kotlin/net/corda/core/flows/TxKeyFlow.kt delete mode 100644 core/src/main/kotlin/net/corda/flows/TxKeyFlowUtilities.kt delete mode 100644 core/src/test/kotlin/net/corda/core/flows/TxKeyFlow.kt create mode 100644 core/src/test/kotlin/net/corda/core/flows/TxKeyFlowTests.kt delete mode 100644 core/src/test/kotlin/net/corda/core/flows/TxKeyFlowUtilitiesTests.kt create mode 100644 node/src/main/kotlin/net/corda/node/services/keys/KMSUtils.kt diff --git a/client/jackson/src/main/kotlin/net/corda/jackson/JacksonSupport.kt b/client/jackson/src/main/kotlin/net/corda/jackson/JacksonSupport.kt index 100fc2f2f7..4439cb0be5 100644 --- a/client/jackson/src/main/kotlin/net/corda/jackson/JacksonSupport.kt +++ b/client/jackson/src/main/kotlin/net/corda/jackson/JacksonSupport.kt @@ -20,7 +20,6 @@ import net.corda.core.serialization.OpaqueBytes import net.corda.core.serialization.deserialize import net.corda.core.serialization.serialize import net.i2p.crypto.eddsa.EdDSAPublicKey -import org.bouncycastle.asn1.ASN1InputStream import org.bouncycastle.asn1.x500.X500Name import java.math.BigDecimal import java.security.PublicKey @@ -39,28 +38,28 @@ object JacksonSupport { interface PartyObjectMapper { @Deprecated("Use partyFromX500Name instead") fun partyFromName(partyName: String): Party? - fun partyFromPrincipal(principal: X500Name): Party? + fun partyFromX500Name(name: X500Name): Party? fun partyFromKey(owningKey: PublicKey): Party? } class RpcObjectMapper(val rpc: CordaRPCOps, factory: JsonFactory) : PartyObjectMapper, ObjectMapper(factory) { @Suppress("OverridingDeprecatedMember", "DEPRECATION") override fun partyFromName(partyName: String): Party? = rpc.partyFromName(partyName) - override fun partyFromPrincipal(principal: X500Name): Party? = rpc.partyFromX500Name(principal) + override fun partyFromX500Name(name: X500Name): Party? = rpc.partyFromX500Name(name) override fun partyFromKey(owningKey: PublicKey): Party? = rpc.partyFromKey(owningKey) } class IdentityObjectMapper(val identityService: IdentityService, factory: JsonFactory) : PartyObjectMapper, ObjectMapper(factory) { @Suppress("OverridingDeprecatedMember", "DEPRECATION") override fun partyFromName(partyName: String): Party? = identityService.partyFromName(partyName) - override fun partyFromPrincipal(principal: X500Name): Party? = identityService.partyFromX500Name(principal) + override fun partyFromX500Name(name: X500Name): Party? = identityService.partyFromX500Name(name) override fun partyFromKey(owningKey: PublicKey): Party? = identityService.partyFromKey(owningKey) } class NoPartyObjectMapper(factory: JsonFactory) : PartyObjectMapper, ObjectMapper(factory) { @Suppress("OverridingDeprecatedMember", "DEPRECATION") override fun partyFromName(partyName: String): Party? = throw UnsupportedOperationException() - override fun partyFromPrincipal(principal: X500Name): Party? = throw UnsupportedOperationException() + override fun partyFromX500Name(name: X500Name): Party? = throw UnsupportedOperationException() override fun partyFromKey(owningKey: PublicKey): Party? = throw UnsupportedOperationException() } @@ -170,7 +169,7 @@ object JacksonSupport { // how to parse the content return if (parser.text.contains("=")) { val principal = X500Name(parser.text) - mapper.partyFromPrincipal(principal) ?: throw JsonParseException(parser, "Could not find a Party with name ${principal}") + mapper.partyFromX500Name(principal) ?: throw JsonParseException(parser, "Could not find a Party with name ${principal}") } else { val key = try { parsePublicKeyBase58(parser.text) diff --git a/core/src/main/kotlin/net/corda/core/crypto/X509Utilities.kt b/core/src/main/kotlin/net/corda/core/crypto/X509Utilities.kt index f8a3ec7c5d..706ffdbd26 100644 --- a/core/src/main/kotlin/net/corda/core/crypto/X509Utilities.kt +++ b/core/src/main/kotlin/net/corda/core/crypto/X509Utilities.kt @@ -1,6 +1,8 @@ package net.corda.core.crypto import net.corda.core.crypto.Crypto.generateKeyPair +import net.corda.core.identity.Party +import net.corda.core.node.ServiceHub import org.bouncycastle.asn1.ASN1Encodable import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.asn1.x500.X500NameBuilder @@ -24,6 +26,7 @@ import java.time.temporal.ChronoUnit import java.util.* object X509Utilities { + val DEFAULT_IDENTITY_SIGNATURE_SCHEME = Crypto.EDDSA_ED25519_SHA512 val DEFAULT_TLS_SIGNATURE_SCHEME = Crypto.ECDSA_SECP256R1_SHA256 // Aliases for private keys and certificates. diff --git a/core/src/main/kotlin/net/corda/core/flows/TxKeyFlow.kt b/core/src/main/kotlin/net/corda/core/flows/TxKeyFlow.kt new file mode 100644 index 0000000000..32ba268709 --- /dev/null +++ b/core/src/main/kotlin/net/corda/core/flows/TxKeyFlow.kt @@ -0,0 +1,95 @@ +package net.corda.core.flows + +import co.paralleluniverse.fibers.Suspendable +import net.corda.core.identity.AnonymousParty +import net.corda.core.identity.Party +import net.corda.core.utilities.ProgressTracker +import net.corda.core.utilities.unwrap +import org.bouncycastle.asn1.x500.X500Name +import java.security.cert.CertPath +import java.security.cert.X509Certificate + +/** + * Very basic flow which exchanges transaction key and certificate paths between two parties in a transaction. + * This is intended for use as a subflow of another flow. + */ +object TxKeyFlow { + abstract class AbstractIdentityFlow(val otherSide: Party, val revocationEnabled: Boolean): FlowLogic>() { + fun validateIdentity(untrustedIdentity: Pair): AnonymousIdentity { + val (wellKnownCert, certPath) = untrustedIdentity + val theirCert = certPath.certificates.last() + // TODO: Don't trust self-signed certificates + return if (theirCert is X509Certificate) { + val certName = X500Name(theirCert.subjectDN.name) + if (certName == otherSide.name) { + val anonymousParty = AnonymousParty(theirCert.publicKey) + serviceHub.identityService.registerPath(wellKnownCert, anonymousParty, certPath) + AnonymousIdentity(certPath, theirCert, anonymousParty) + } else + throw IllegalStateException("Expected certificate subject to be ${otherSide.name} but found ${certName}") + } else + throw IllegalStateException("Expected an X.509 certificate but received ${theirCert.javaClass.name}") + } + } + + @StartableByRPC + @InitiatingFlow + class Requester(otherSide: Party, + revocationEnabled: Boolean, + override val progressTracker: ProgressTracker) : AbstractIdentityFlow(otherSide, revocationEnabled) { + constructor(otherSide: Party, + revocationEnabled: Boolean) : this(otherSide, revocationEnabled, tracker()) + + companion object { + object AWAITING_KEY : ProgressTracker.Step("Awaiting key") + + fun tracker() = ProgressTracker(AWAITING_KEY) + } + + @Suspendable + override fun call(): Map { + progressTracker.currentStep = AWAITING_KEY + val myIdentityFragment = serviceHub.keyManagementService.freshKeyAndCert(serviceHub.myInfo.legalIdentity, revocationEnabled) + val theirIdentity = receive>(otherSide).unwrap { validateIdentity(it) } + send(otherSide, myIdentityFragment) + return mapOf(Pair(otherSide, AnonymousIdentity(myIdentityFragment)), + Pair(serviceHub.myInfo.legalIdentity, theirIdentity)) + } + } + + /** + * Flow which waits for a key request from a counterparty, generates a new key and then returns it to the + * counterparty and as the result from the flow. + */ + class Provider(otherSide: Party, + revocationEnabled: Boolean, + override val progressTracker: ProgressTracker) : AbstractIdentityFlow(otherSide,revocationEnabled) { + constructor(otherSide: Party, + revocationEnabled: Boolean = false) : this(otherSide, revocationEnabled, tracker()) + + companion object { + object SENDING_KEY : ProgressTracker.Step("Sending key") + + fun tracker() = ProgressTracker(SENDING_KEY) + } + + @Suspendable + override fun call(): Map { + progressTracker.currentStep = SENDING_KEY + val myIdentityFragment = serviceHub.keyManagementService.freshKeyAndCert(serviceHub.myInfo.legalIdentity, revocationEnabled) + send(otherSide, myIdentityFragment) + val theirIdentity = receive>(otherSide).unwrap { validateIdentity(it) } + return mapOf(Pair(otherSide, AnonymousIdentity(myIdentityFragment)), + Pair(serviceHub.myInfo.legalIdentity, theirIdentity)) + } + } + + data class AnonymousIdentity( + val certPath: CertPath, + val certificate: X509Certificate, + val identity: AnonymousParty) { + constructor(myIdentity: Pair) : this(myIdentity.second, + myIdentity.first, + AnonymousParty(myIdentity.second.certificates.last().publicKey)) + } +} diff --git a/core/src/main/kotlin/net/corda/core/node/services/IdentityService.kt b/core/src/main/kotlin/net/corda/core/node/services/IdentityService.kt index 4dafa52ef0..d066d1007c 100644 --- a/core/src/main/kotlin/net/corda/core/node/services/IdentityService.kt +++ b/core/src/main/kotlin/net/corda/core/node/services/IdentityService.kt @@ -1,6 +1,7 @@ package net.corda.core.node.services import net.corda.core.contracts.PartyAndReference +import net.corda.core.crypto.toStringShort import net.corda.core.identity.AbstractParty import net.corda.core.identity.AnonymousParty import net.corda.core.identity.Party @@ -55,9 +56,31 @@ interface IdentityService { fun partyFromName(name: String): Party? fun partyFromX500Name(principal: X500Name): Party? + /** + * Resolve the well known identity of a party. If the party passed in is already a well known identity + * (i.e. a [Party]) this returns it as-is. + * + * @return the well known identity, or null if unknown. + */ fun partyFromAnonymous(party: AbstractParty): Party? + + /** + * Resolve the well known identity of a party. If the party passed in is already a well known identity + * (i.e. a [Party]) this returns it as-is. + * + * @return the well known identity, or null if unknown. + */ fun partyFromAnonymous(partyRef: PartyAndReference) = partyFromAnonymous(partyRef.party) + /** + * Resolve the well known identity of a party. Throws an exception if the party cannot be identified. + * If the party passed in is already a well known identity (i.e. a [Party]) this returns it as-is. + * + * @return the well known identity. + * @throws IllegalArgumentException + */ + fun requirePartyFromAnonymous(party: AbstractParty): Party + /** * Get the certificate chain showing an anonymous party is owned by the given party. */ diff --git a/core/src/main/kotlin/net/corda/core/node/services/Services.kt b/core/src/main/kotlin/net/corda/core/node/services/Services.kt index 6116441b0a..65fd283927 100644 --- a/core/src/main/kotlin/net/corda/core/node/services/Services.kt +++ b/core/src/main/kotlin/net/corda/core/node/services/Services.kt @@ -3,10 +3,10 @@ package net.corda.core.node.services import co.paralleluniverse.fibers.Suspendable import com.google.common.util.concurrent.ListenableFuture import net.corda.core.contracts.* -import net.corda.core.crypto.DigitalSignature -import net.corda.core.crypto.SecureHash +import net.corda.core.crypto.* import net.corda.core.flows.FlowException import net.corda.core.identity.AbstractParty +import net.corda.core.identity.AnonymousParty import net.corda.core.identity.Party import net.corda.core.node.services.vault.PageSpecification import net.corda.core.node.services.vault.QueryCriteria @@ -20,6 +20,8 @@ import net.corda.core.transactions.WireTransaction import rx.Observable import java.io.InputStream import java.security.PublicKey +import java.security.cert.CertPath +import java.security.cert.X509Certificate import java.time.Instant import java.util.* @@ -385,6 +387,17 @@ interface KeyManagementService { @Suspendable fun freshKey(): PublicKey + /** + * Generates a new random [KeyPair], adds it to the internal key storage, then generates a corresponding + * [X509Certificate] and adds it to the identity service. + * + * @param identity identity to generate a key and certificate for. Must be an identity this node has CA privileges for. + * @param revocationEnabled whether to check revocation status of certificates in the certificate path. + * @return X.509 certificate and path to the trust root. + */ + @Suspendable + fun freshKeyAndCert(identity: Party, revocationEnabled: Boolean): Pair + /** Using the provided signing [PublicKey] internally looks up the matching [PrivateKey] and signs the data. * @param bytes The data to sign over using the chosen key. * @param publicKey The [PublicKey] partner to an internally held [PrivateKey], either derived from the node's primary identity, diff --git a/core/src/main/kotlin/net/corda/flows/TxKeyFlowUtilities.kt b/core/src/main/kotlin/net/corda/flows/TxKeyFlowUtilities.kt deleted file mode 100644 index 8e7d85b240..0000000000 --- a/core/src/main/kotlin/net/corda/flows/TxKeyFlowUtilities.kt +++ /dev/null @@ -1,41 +0,0 @@ -package net.corda.flows - -import co.paralleluniverse.fibers.Suspendable -import net.corda.core.flows.FlowLogic -import net.corda.core.identity.Party -import net.corda.core.serialization.CordaSerializable -import net.corda.core.utilities.unwrap -import java.security.PublicKey -import java.security.cert.Certificate - -object TxKeyFlowUtilities { - /** - * Receive a key from a counterparty. This would normally be triggered by a flow as part of a transaction assembly - * process. - */ - @Suspendable - fun receiveKey(flow: FlowLogic<*>, otherSide: Party): Pair { - val untrustedKey = flow.receive(otherSide) - return untrustedKey.unwrap { - // TODO: Verify the certificate connects the given key to the counterparty, once we have certificates - Pair(it.key, it.certificate) - } - } - - /** - * Generates a new key and then returns it to the counterparty and as the result from the function. Note that this - * is an expensive operation, and should only be called once the calling flow has confirmed it wants to be part of - * a transaction with the counterparty, in order to avoid a DoS risk. - */ - @Suspendable - fun provideKey(flow: FlowLogic<*>, otherSide: Party): PublicKey { - val key = flow.serviceHub.keyManagementService.freshKey() - // TODO: Generate and sign certificate for the key, once we have signing support for composite keys - // (in this case the legal identity key) - flow.send(otherSide, ProvidedTransactionKey(key, null)) - return key - } - - @CordaSerializable - data class ProvidedTransactionKey(val key: PublicKey, val certificate: Certificate?) -} diff --git a/core/src/test/kotlin/net/corda/core/flows/TxKeyFlow.kt b/core/src/test/kotlin/net/corda/core/flows/TxKeyFlow.kt deleted file mode 100644 index 78f18c3171..0000000000 --- a/core/src/test/kotlin/net/corda/core/flows/TxKeyFlow.kt +++ /dev/null @@ -1,55 +0,0 @@ -package net.corda.core.flows - -import co.paralleluniverse.fibers.Suspendable -import net.corda.core.identity.Party -import net.corda.core.utilities.ProgressTracker -import net.corda.flows.TxKeyFlowUtilities -import java.security.PublicKey -import java.security.cert.Certificate - -/** - * Very basic flow which requests a transaction key from a counterparty, used for testing [TxKeyFlowUtilities]. - * This MUST not be provided on any real node, as the ability for arbitrary parties to request keys would enable - * DoS of the node, as key generation/storage is vastly more expensive than submitting a request. - */ -object TxKeyFlow { - - @InitiatingFlow - class Requester(val otherSide: Party, - override val progressTracker: ProgressTracker) : FlowLogic>() { - constructor(otherSide: Party) : this(otherSide, tracker()) - - companion object { - object AWAITING_KEY : ProgressTracker.Step("Awaiting key") - - fun tracker() = ProgressTracker(AWAITING_KEY) - } - - @Suspendable - override fun call(): Pair { - progressTracker.currentStep = AWAITING_KEY - return TxKeyFlowUtilities.receiveKey(this, otherSide) - } - } - - /** - * Flow which waits for a key request from a counterparty, generates a new key and then returns it to the - * counterparty and as the result from the flow. - */ - class Provider(val otherSide: Party, - override val progressTracker: ProgressTracker) : FlowLogic() { - constructor(otherSide: Party) : this(otherSide, tracker()) - - companion object { - object SENDING_KEY : ProgressTracker.Step("Sending key") - - fun tracker() = ProgressTracker(SENDING_KEY) - } - - @Suspendable - override fun call(): PublicKey { - progressTracker.currentStep = SENDING_KEY - return TxKeyFlowUtilities.provideKey(this, otherSide) - } - } -} diff --git a/core/src/test/kotlin/net/corda/core/flows/TxKeyFlowTests.kt b/core/src/test/kotlin/net/corda/core/flows/TxKeyFlowTests.kt new file mode 100644 index 0000000000..44c1f86731 --- /dev/null +++ b/core/src/test/kotlin/net/corda/core/flows/TxKeyFlowTests.kt @@ -0,0 +1,53 @@ +package net.corda.core.flows + +import net.corda.core.getOrThrow +import net.corda.core.identity.AbstractParty +import net.corda.core.identity.Party +import net.corda.core.utilities.ALICE +import net.corda.core.utilities.BOB +import net.corda.core.utilities.DUMMY_NOTARY +import net.corda.testing.node.MockNetwork +import org.junit.Before +import org.junit.Test +import kotlin.test.assertEquals +import kotlin.test.assertNotEquals + +class TxKeyFlowTests { + lateinit var net: MockNetwork + + @Before + fun before() { + net = MockNetwork(false) + } + + @Test + fun `issue key`() { + // We run this in parallel threads to help catch any race conditions that may exist. + net = MockNetwork(false, true) + + // Set up values we'll need + val revocationEnabled = false + val notaryNode = net.createNotaryNode(null, DUMMY_NOTARY.name) + val aliceNode = net.createPartyNode(notaryNode.info.address, ALICE.name) + val bobNode = net.createPartyNode(notaryNode.info.address, BOB.name) + val alice: Party = aliceNode.services.myInfo.legalIdentity + val bob: Party = bobNode.services.myInfo.legalIdentity + aliceNode.services.identityService.registerIdentity(bob) + aliceNode.services.identityService.registerIdentity(notaryNode.info.legalIdentity) + bobNode.services.identityService.registerIdentity(alice) + bobNode.services.identityService.registerIdentity(notaryNode.info.legalIdentity) + + // Run the flows + bobNode.registerServiceFlow(TxKeyFlow.Requester::class) { TxKeyFlow.Provider(it) } + val requesterFlow = aliceNode.services.startFlow(TxKeyFlow.Requester(bob, revocationEnabled)) + + // Get the results + val actual: Map = requesterFlow.resultFuture.getOrThrow() + assertEquals(2, actual.size) + // Verify that the generated anonymous identities do not match the well known identities + val aliceAnonymousIdentity = actual[alice] ?: throw IllegalStateException() + val bobAnonymousIdentity = actual[bob] ?: throw IllegalStateException() + assertNotEquals(alice, aliceAnonymousIdentity.identity) + assertNotEquals(bob, bobAnonymousIdentity.identity) + } +} diff --git a/core/src/test/kotlin/net/corda/core/flows/TxKeyFlowUtilitiesTests.kt b/core/src/test/kotlin/net/corda/core/flows/TxKeyFlowUtilitiesTests.kt deleted file mode 100644 index 662a807269..0000000000 --- a/core/src/test/kotlin/net/corda/core/flows/TxKeyFlowUtilitiesTests.kt +++ /dev/null @@ -1,40 +0,0 @@ -package net.corda.core.flows - -import net.corda.core.identity.Party -import net.corda.core.utilities.ALICE -import net.corda.core.utilities.BOB -import net.corda.core.utilities.DUMMY_NOTARY -import net.corda.testing.node.MockNetwork -import org.junit.Before -import org.junit.Test -import java.security.PublicKey -import kotlin.test.assertNotNull - -class TxKeyFlowUtilitiesTests { - lateinit var net: MockNetwork - - @Before - fun before() { - net = MockNetwork(false) - } - - @Test - fun `issue key`() { - // We run this in parallel threads to help catch any race conditions that may exist. - net = MockNetwork(false, true) - - // Set up values we'll need - val notaryNode = net.createNotaryNode(null, DUMMY_NOTARY.name) - val aliceNode = net.createPartyNode(notaryNode.info.address, ALICE.name) - val bobNode = net.createPartyNode(notaryNode.info.address, BOB.name) - val bobKey: Party = bobNode.services.myInfo.legalIdentity - - // Run the flows - bobNode.registerServiceFlow(TxKeyFlow.Requester::class) { TxKeyFlow.Provider(it) } - val requesterFlow = aliceNode.services.startFlow(TxKeyFlow.Requester(bobKey)) - - // Get the results - val actual: PublicKey = requesterFlow.resultFuture.get().first - assertNotNull(actual) - } -} diff --git a/finance/src/test/kotlin/net/corda/contracts/asset/CashTests.kt b/finance/src/test/kotlin/net/corda/contracts/asset/CashTests.kt index bbb6e1aaf1..637d5d62a5 100644 --- a/finance/src/test/kotlin/net/corda/contracts/asset/CashTests.kt +++ b/finance/src/test/kotlin/net/corda/contracts/asset/CashTests.kt @@ -58,7 +58,7 @@ class CashTests { database = dataSourceAndDatabase.second database.transaction { services = object : MockServices() { - override val keyManagementService: MockKeyManagementService = MockKeyManagementService(MINI_CORP_KEY, MEGA_CORP_KEY, OUR_KEY) + override val keyManagementService: MockKeyManagementService = MockKeyManagementService(identityService, MINI_CORP_KEY, MEGA_CORP_KEY, OUR_KEY) override val vaultService: VaultService = makeVaultService(dataSourceProps) override fun recordTransactions(txs: Iterable) { diff --git a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt index fb50a92c07..dbe68f221c 100644 --- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt @@ -306,7 +306,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, // Place the long term identity key in the KMS. Eventually, this is likely going to be separated again because // the KMS is meant for derived temporary keys used in transactions, and we're not supposed to sign things with // the identity key. But the infrastructure to make that easy isn't here yet. - keyManagement = makeKeyManagementService() + keyManagement = makeKeyManagementService(identity) scheduler = NodeSchedulerService(services, database, unfinishedSchedules = busyNodeLatch) val tokenizableServices = mutableListOf(storage, net, vault, keyManagement, identity, platformClock, scheduler) @@ -501,7 +501,9 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, "has any other map node been configured.") } - protected open fun makeKeyManagementService(): KeyManagementService = PersistentKeyManagementService(partyKeys) + protected open fun makeKeyManagementService(identityService: IdentityService): KeyManagementService { + return PersistentKeyManagementService(identityService, partyKeys) + } open protected fun makeNetworkMapService() { inNodeNetworkMapService = PersistentNetworkMapService(services, configuration.minimumPlatformVersion) diff --git a/node/src/main/kotlin/net/corda/node/services/identity/InMemoryIdentityService.kt b/node/src/main/kotlin/net/corda/node/services/identity/InMemoryIdentityService.kt index 25ebc637a4..a1f16b0b7d 100644 --- a/node/src/main/kotlin/net/corda/node/services/identity/InMemoryIdentityService.kt +++ b/node/src/main/kotlin/net/corda/node/services/identity/InMemoryIdentityService.kt @@ -54,8 +54,17 @@ class InMemoryIdentityService(identities: Iterable = emptySet(), @Deprecated("Use partyFromX500Name") override fun partyFromName(name: String): Party? = principalToParties[X500Name(name)] override fun partyFromX500Name(principal: X500Name): Party? = principalToParties[principal] - override fun partyFromAnonymous(party: AbstractParty): Party? = partyFromKey(party.owningKey) + override fun partyFromAnonymous(party: AbstractParty): Party? { + return if (party is Party) { + party + } else { + partyFromKey(party.owningKey) + } + } override fun partyFromAnonymous(partyRef: PartyAndReference) = partyFromAnonymous(partyRef.party) + override fun requirePartyFromAnonymous(party: AbstractParty): Party { + return partyFromAnonymous(party) ?: throw IllegalStateException("Could not deanonymise party ${party.owningKey.toStringShort()}") + } @Throws(IdentityService.UnknownAnonymousPartyException::class) override fun assertOwnership(party: Party, anonymousParty: AnonymousParty) { diff --git a/node/src/main/kotlin/net/corda/node/services/keys/E2ETestKeyManagementService.kt b/node/src/main/kotlin/net/corda/node/services/keys/E2ETestKeyManagementService.kt index 6030118332..cb4d6ca321 100644 --- a/node/src/main/kotlin/net/corda/node/services/keys/E2ETestKeyManagementService.kt +++ b/node/src/main/kotlin/net/corda/node/services/keys/E2ETestKeyManagementService.kt @@ -5,11 +5,15 @@ import net.corda.core.crypto.DigitalSignature import net.corda.core.crypto.generateKeyPair import net.corda.core.crypto.keys import net.corda.core.crypto.sign +import net.corda.core.identity.Party +import net.corda.core.node.services.IdentityService import net.corda.core.node.services.KeyManagementService import net.corda.core.serialization.SingletonSerializeAsToken import java.security.KeyPair import java.security.PrivateKey import java.security.PublicKey +import java.security.cert.CertPath +import java.security.cert.X509Certificate import java.util.* import javax.annotation.concurrent.ThreadSafe @@ -25,7 +29,8 @@ import javax.annotation.concurrent.ThreadSafe * etc. */ @ThreadSafe -class E2ETestKeyManagementService(initialKeys: Set) : SingletonSerializeAsToken(), KeyManagementService { +class E2ETestKeyManagementService(val identityService: IdentityService, + initialKeys: Set) : SingletonSerializeAsToken(), KeyManagementService { private class InnerState { val keys = HashMap() } @@ -51,6 +56,8 @@ class E2ETestKeyManagementService(initialKeys: Set) : SingletonSerializ return keyPair.public } + override fun freshKeyAndCert(identity: Party, revocationEnabled: Boolean): Pair = freshKeyAndCert(this, identityService, identity, revocationEnabled) + private fun getSigningKeyPair(publicKey: PublicKey): KeyPair { return mutex.locked { val pk = publicKey.keys.first { keys.containsKey(it) } diff --git a/node/src/main/kotlin/net/corda/node/services/keys/KMSUtils.kt b/node/src/main/kotlin/net/corda/node/services/keys/KMSUtils.kt new file mode 100644 index 0000000000..24d7fd51bc --- /dev/null +++ b/node/src/main/kotlin/net/corda/node/services/keys/KMSUtils.kt @@ -0,0 +1,37 @@ +package net.corda.node.services.keys + +import net.corda.core.crypto.CertificateType +import net.corda.core.crypto.Crypto +import net.corda.core.crypto.X509Utilities +import net.corda.core.identity.AnonymousParty +import net.corda.core.identity.Party +import net.corda.core.node.services.IdentityService +import net.corda.core.node.services.KeyManagementService +import java.security.cert.CertPath +import java.security.cert.X509Certificate + +/** + * Generates a new random [KeyPair], adds it to the internal key storage, then generates a corresponding + * [X509Certificate] and adds it to the identity service. + * + * @param keyManagementService key service to use when generating the new key. + * @param identityService identity service to use when registering the certificate. + * @param identity identity to generate a key and certificate for. Must be an identity this node has CA privileges for. + * @param revocationEnabled whether to check revocation status of certificates in the certificate path. + * @return X.509 certificate and path to the trust root. + */ +fun freshKeyAndCert(keyManagementService: KeyManagementService, + identityService: IdentityService, + identity: Party, + revocationEnabled: Boolean = false): Pair { + val ourPublicKey = keyManagementService.freshKey() + // FIXME: Use the actual certificate for the identity the flow is presenting themselves as + val issuerKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_IDENTITY_SIGNATURE_SCHEME) + val issuerCertificate = X509Utilities.createSelfSignedCACertificate(identity.name, issuerKey) + val ourCertificate = X509Utilities.createCertificate(CertificateType.IDENTITY, issuerCertificate, issuerKey, identity.name, ourPublicKey) + val ourCertPath = X509Utilities.createCertificatePath(issuerCertificate, ourCertificate, revocationEnabled = revocationEnabled) + identityService.registerPath(issuerCertificate, + AnonymousParty(ourPublicKey), + ourCertPath) + return Pair(issuerCertificate, ourCertPath) +} \ No newline at end of file diff --git a/node/src/main/kotlin/net/corda/node/services/keys/PersistentKeyManagementService.kt b/node/src/main/kotlin/net/corda/node/services/keys/PersistentKeyManagementService.kt index 643dcdf05d..532e05605b 100644 --- a/node/src/main/kotlin/net/corda/node/services/keys/PersistentKeyManagementService.kt +++ b/node/src/main/kotlin/net/corda/node/services/keys/PersistentKeyManagementService.kt @@ -5,6 +5,8 @@ import net.corda.core.crypto.DigitalSignature import net.corda.core.crypto.generateKeyPair import net.corda.core.crypto.keys import net.corda.core.crypto.sign +import net.corda.core.identity.Party +import net.corda.core.node.services.IdentityService import net.corda.core.node.services.KeyManagementService import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.node.utilities.* @@ -13,6 +15,8 @@ import org.jetbrains.exposed.sql.statements.InsertStatement import java.security.KeyPair import java.security.PrivateKey import java.security.PublicKey +import java.security.cert.CertPath +import java.security.cert.X509Certificate /** * A persistent re-implementation of [E2ETestKeyManagementService] to support node re-start. @@ -21,7 +25,8 @@ import java.security.PublicKey * * This class needs database transactions to be in-flight during method calls and init. */ -class PersistentKeyManagementService(initialKeys: Set) : SingletonSerializeAsToken(), KeyManagementService { +class PersistentKeyManagementService(val identityService: IdentityService, + initialKeys: Set) : SingletonSerializeAsToken(), KeyManagementService { private object Table : JDBCHashedTable("${NODE_DATABASE_PREFIX}our_key_pairs") { val publicKey = publicKey("public_key") @@ -62,6 +67,8 @@ class PersistentKeyManagementService(initialKeys: Set) : SingletonSeria return keyPair.public } + override fun freshKeyAndCert(identity: Party, revocationEnabled: Boolean): Pair = freshKeyAndCert(this, identityService, identity, revocationEnabled) + private fun getSigningKeyPair(publicKey: PublicKey): KeyPair { return mutex.locked { val pk = publicKey.keys.first { keys.containsKey(it) } diff --git a/node/src/main/kotlin/net/corda/node/services/statemachine/StateMachineManager.kt b/node/src/main/kotlin/net/corda/node/services/statemachine/StateMachineManager.kt index 9e249ef0f0..c20c5d84c2 100644 --- a/node/src/main/kotlin/net/corda/node/services/statemachine/StateMachineManager.kt +++ b/node/src/main/kotlin/net/corda/node/services/statemachine/StateMachineManager.kt @@ -348,7 +348,7 @@ class StateMachineManager(val serviceHub: ServiceHubInternal, val serviceFlowInfo = serviceHub.getServiceFlowFactory(sessionInit.clientFlowClass) if (serviceFlowInfo == null) { logger.warn("${sessionInit.clientFlowClass} has not been registered with a service flow: $sessionInit") - sendSessionReject("Don't know ${sessionInit.clientFlowClass.name}") + sendSessionReject("${sessionInit.clientFlowClass.name} has not been registered with a service flow") return } diff --git a/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt b/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt index 51c9f06c92..28366cb7dd 100644 --- a/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt @@ -12,6 +12,7 @@ import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.core.utilities.ALICE_KEY import net.corda.core.utilities.DUMMY_NOTARY import net.corda.node.services.MockServiceHubInternal +import net.corda.node.services.identity.InMemoryIdentityService import net.corda.node.services.persistence.DBCheckpointStorage import net.corda.node.services.statemachine.FlowLogicRefFactoryImpl import net.corda.node.services.statemachine.StateMachineManager @@ -75,9 +76,10 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() { val dataSourceAndDatabase = configureDatabase(dataSourceProps) dataSource = dataSourceAndDatabase.first database = dataSourceAndDatabase.second + val identityService = InMemoryIdentityService() + val kms = MockKeyManagementService(identityService, ALICE_KEY) database.transaction { - val kms = MockKeyManagementService(ALICE_KEY) val nullIdentity = X500Name("cn=None") val mockMessagingService = InMemoryMessagingNetwork(false).InMemoryMessaging( false, diff --git a/node/src/test/kotlin/net/corda/node/services/network/InMemoryIdentityServiceTests.kt b/node/src/test/kotlin/net/corda/node/services/network/InMemoryIdentityServiceTests.kt index ce8c330e1d..03672b3833 100644 --- a/node/src/test/kotlin/net/corda/node/services/network/InMemoryIdentityServiceTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/network/InMemoryIdentityServiceTests.kt @@ -115,4 +115,14 @@ class InMemoryIdentityServiceTests { service.assertOwnership(bob, anonymousAlice) } } + + /** + * Ensure if we feed in a full identity, we get the same identity back. + */ + @Test + fun `deanonymising a well known identity`() { + val expected = ALICE + val actual = InMemoryIdentityService().partyFromAnonymous(expected) + assertEquals(expected, actual) + } } diff --git a/test-utils/src/main/kotlin/net/corda/testing/node/MockNode.kt b/test-utils/src/main/kotlin/net/corda/testing/node/MockNode.kt index 4905acec1d..b1606ec9fb 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/node/MockNode.kt +++ b/test-utils/src/main/kotlin/net/corda/testing/node/MockNode.kt @@ -171,8 +171,8 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false, override fun makeVaultService(dataSourceProperties: Properties): VaultService = NodeVaultService(services, dataSourceProperties) - override fun makeKeyManagementService(): KeyManagementService { - return E2ETestKeyManagementService(partyKeys + (overrideServices?.values ?: emptySet())) + override fun makeKeyManagementService(identityService: IdentityService): KeyManagementService { + return E2ETestKeyManagementService(identityService, partyKeys + (overrideServices?.values ?: emptySet())) } override fun startMessagingService(rpcOps: RPCOps) { @@ -370,6 +370,11 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false, repeat(numPartyNodes) { nodes += createPartyNode(mapNode.info.address) } + nodes.forEach { node -> + nodes.map { it.info.legalIdentity }.forEach { identity -> + node.services.identityService.registerIdentity(identity) + } + } return BasketOfNodes(nodes, notaryNode, mapNode) } diff --git a/test-utils/src/main/kotlin/net/corda/testing/node/MockServices.kt b/test-utils/src/main/kotlin/net/corda/testing/node/MockServices.kt index 7eb9e8c5dc..c50f00a420 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/node/MockServices.kt +++ b/test-utils/src/main/kotlin/net/corda/testing/node/MockServices.kt @@ -1,11 +1,8 @@ package net.corda.testing.node import net.corda.core.contracts.Attachment -import net.corda.core.contracts.PartyAndReference import net.corda.core.crypto.* import net.corda.core.flows.StateMachineRunId -import net.corda.core.identity.AbstractParty -import net.corda.core.identity.AnonymousParty import net.corda.core.identity.Party import net.corda.core.messaging.SingleMessageRecipient import net.corda.core.node.NodeInfo @@ -15,6 +12,7 @@ import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.core.transactions.SignedTransaction import net.corda.core.utilities.DUMMY_NOTARY import net.corda.node.services.identity.InMemoryIdentityService +import net.corda.node.services.keys.freshKeyAndCert import net.corda.node.services.persistence.InMemoryStateMachineRecordedTransactionMappingStorage import net.corda.node.services.schema.HibernateObserver import net.corda.node.services.schema.NodeSchemaService @@ -23,7 +21,6 @@ import net.corda.node.services.vault.NodeVaultService import net.corda.testing.MEGA_CORP import net.corda.testing.MINI_CORP import net.corda.testing.MOCK_VERSION_INFO -import org.bouncycastle.asn1.x500.X500Name import rx.Observable import rx.subjects.PublishSubject import java.io.ByteArrayInputStream @@ -38,7 +35,6 @@ import java.security.cert.CertPath import java.security.cert.X509Certificate import java.time.Clock import java.util.* -import java.util.concurrent.ConcurrentHashMap import java.util.jar.JarInputStream import javax.annotation.concurrent.ThreadSafe @@ -64,8 +60,8 @@ open class MockServices(vararg val keys: KeyPair) : ServiceHub { } override val storageService: TxWritableStorageService = MockStorageService() - override val identityService: IdentityService = InMemoryIdentityService(listOf(MEGA_CORP, MINI_CORP, DUMMY_NOTARY)) - override val keyManagementService: KeyManagementService = MockKeyManagementService(*keys) + override final val identityService: IdentityService = InMemoryIdentityService(listOf(MEGA_CORP, MINI_CORP, DUMMY_NOTARY)) + override val keyManagementService: KeyManagementService = MockKeyManagementService(identityService, *keys) override val vaultService: VaultService get() = throw UnsupportedOperationException() override val networkMapCache: NetworkMapCache get() = throw UnsupportedOperationException() @@ -81,7 +77,8 @@ open class MockServices(vararg val keys: KeyPair) : ServiceHub { } } -class MockKeyManagementService(vararg initialKeys: KeyPair) : SingletonSerializeAsToken(), KeyManagementService { +class MockKeyManagementService(val identityService: IdentityService, + vararg initialKeys: KeyPair) : SingletonSerializeAsToken(), KeyManagementService { private val keyStore: MutableMap = initialKeys.associateByTo(HashMap(), { it.public }, { it.private }) override val keys: Set get() = keyStore.keys @@ -94,6 +91,8 @@ class MockKeyManagementService(vararg initialKeys: KeyPair) : SingletonSerialize return k.public } + override fun freshKeyAndCert(identity: Party, revocationEnabled: Boolean): Pair = freshKeyAndCert(this, identityService, identity, revocationEnabled) + private fun getSigningKeyPair(publicKey: PublicKey): KeyPair { val pk = publicKey.keys.first { keyStore.containsKey(it) } return KeyPair(pk, keyStore[pk]!!) diff --git a/test-utils/src/main/kotlin/net/corda/testing/node/SimpleNode.kt b/test-utils/src/main/kotlin/net/corda/testing/node/SimpleNode.kt index 29c4d8042d..ea70e70a25 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/node/SimpleNode.kt +++ b/test-utils/src/main/kotlin/net/corda/testing/node/SimpleNode.kt @@ -6,10 +6,12 @@ import com.google.common.util.concurrent.SettableFuture import net.corda.core.crypto.commonName import net.corda.core.crypto.generateKeyPair import net.corda.core.messaging.RPCOps +import net.corda.core.node.services.IdentityService import net.corda.core.node.services.KeyManagementService import net.corda.node.services.RPCUserServiceImpl import net.corda.node.services.api.MonitoringService import net.corda.node.services.config.NodeConfiguration +import net.corda.node.services.identity.InMemoryIdentityService import net.corda.node.services.keys.E2ETestKeyManagementService import net.corda.node.services.messaging.ArtemisMessagingServer import net.corda.node.services.messaging.NodeMessagingClient @@ -26,7 +28,7 @@ import kotlin.concurrent.thread /** * This is a bare-bones node which can only send and receive messages. It doesn't register with a network map service or - * any other such task that would make it functionable in a network and thus left to the user to do so manually. + * any other such task that would make it functional in a network and thus left to the user to do so manually. */ class SimpleNode(val config: NodeConfiguration, val address: HostAndPort = freeLocalHostAndPort(), rpcAddress: HostAndPort = freeLocalHostAndPort()) : AutoCloseable { @@ -35,7 +37,8 @@ class SimpleNode(val config: NodeConfiguration, val address: HostAndPort = freeL val userService = RPCUserServiceImpl(config.rpcUsers) val monitoringService = MonitoringService(MetricRegistry()) val identity: KeyPair = generateKeyPair() - val keyService: KeyManagementService = E2ETestKeyManagementService(setOf(identity)) + val identityService: IdentityService = InMemoryIdentityService() + val keyService: KeyManagementService = E2ETestKeyManagementService(identityService, setOf(identity)) val executor = ServiceAffinityExecutor(config.myLegalName.commonName, 1) val broker = ArtemisMessagingServer(config, address, rpcAddress, InMemoryNetworkMapCache(), userService) val networkMapRegistrationFuture: SettableFuture = SettableFuture.create() From 2d36e3ed1d0c032640dc2dd00cdf315eb47e674a Mon Sep 17 00:00:00 2001 From: Chris Rankin Date: Fri, 26 May 2017 12:41:56 +0100 Subject: [PATCH 010/126] Assign correct RPC permission to run attachment demo. (#745) --- samples/attachment-demo/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/attachment-demo/build.gradle b/samples/attachment-demo/build.gradle index 54f265af43..99454ee5d1 100644 --- a/samples/attachment-demo/build.gradle +++ b/samples/attachment-demo/build.gradle @@ -42,7 +42,7 @@ dependencies { } task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { - ext.rpcUsers = [['username': "demo", 'password': "demo", 'permissions': ["StartFlow.net.corda.flows.FinalityFlow"]]] + ext.rpcUsers = [['username': "demo", 'password': "demo", 'permissions': ["StartFlow.net.corda.attachmentdemo.AttachmentDemoFlow"]]] directory "./build/nodes" networkMap "CN=Notary Service,O=R3,OU=corda,L=London,C=UK" From bb0cc852954ee9eac2883e3eed3c7ce4f7d3678b Mon Sep 17 00:00:00 2001 From: Chris Rankin Date: Fri, 26 May 2017 15:28:22 +0100 Subject: [PATCH 011/126] Allow RPC for internal classes with special serialisers. (#751) Also ensure that HashCheckingStream validates the hash afterwards. --- .../kotlin/net/corda/nodeapi/RPCStructures.kt | 2 +- .../persistence/NodeAttachmentService.kt | 52 ++++++++++++++++--- 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/RPCStructures.kt b/node-api/src/main/kotlin/net/corda/nodeapi/RPCStructures.kt index d1c090f2ca..16be6048b5 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/RPCStructures.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/RPCStructures.kt @@ -61,7 +61,6 @@ class RPCKryo(observableSerializer: Serializer>) : CordaKryo(mak } override fun getRegistration(type: Class<*>): Registration { - type.requireExternal("RPC not allowed to deserialise internal classes") if (Observable::class.java != type && Observable::class.java.isAssignableFrom(type)) { return super.getRegistration(Observable::class.java) } @@ -71,6 +70,7 @@ class RPCKryo(observableSerializer: Serializer>) : CordaKryo(mak if (ListenableFuture::class.java != type && ListenableFuture::class.java.isAssignableFrom(type)) { return super.getRegistration(ListenableFuture::class.java) } + type.requireExternal("RPC not allowed to deserialise internal classes") return super.getRegistration(type) } } diff --git a/node/src/main/kotlin/net/corda/node/services/persistence/NodeAttachmentService.kt b/node/src/main/kotlin/net/corda/node/services/persistence/NodeAttachmentService.kt index b92446e44a..4f69c4dc7b 100644 --- a/node/src/main/kotlin/net/corda/node/services/persistence/NodeAttachmentService.kt +++ b/node/src/main/kotlin/net/corda/node/services/persistence/NodeAttachmentService.kt @@ -2,6 +2,7 @@ package net.corda.node.services.persistence import com.codahale.metrics.MetricRegistry import com.google.common.annotations.VisibleForTesting +import com.google.common.hash.HashCode import com.google.common.hash.Hashing import com.google.common.hash.HashingInputStream import com.google.common.io.CountingInputStream @@ -24,6 +25,7 @@ import net.corda.node.services.persistence.schemas.AttachmentEntity import net.corda.node.services.persistence.schemas.Models import java.io.ByteArrayInputStream import java.io.FilterInputStream +import java.io.IOException import java.io.InputStream import java.nio.file.FileAlreadyExistsException import java.nio.file.Path @@ -57,16 +59,14 @@ class NodeAttachmentService(override var storePath: Path, dataSourceProperties: } @CordaSerializable - class HashMismatchException(val expected: SecureHash, val actual: SecureHash) : Exception() { - override fun toString() = "File $expected hashed to $actual: corruption in attachment store?" - } + class HashMismatchException(val expected: SecureHash, val actual: SecureHash) : RuntimeException("File $expected hashed to $actual: corruption in attachment store?") /** * Wraps a stream and hashes data as it is read: if the entire stream is consumed, then at the end the hash of - * the read data is compared to the [expected] hash and [HashMismatchException] is thrown by [close] if they didn't - * match. The goal of this is to detect cases where attachments in the store have been tampered with or corrupted - * and no longer match their file name. It won't always work: if we read a zip for our own uses and skip around - * inside it, we haven't read the whole file, so we can't check the hash. But when copying it over the network + * the read data is compared to the [expected] hash and [HashMismatchException] is thrown by either [read] or [close] + * if they didn't match. The goal of this is to detect cases where attachments in the store have been tampered with + * or corrupted and no longer match their file name. It won't always work: if we read a zip for our own uses and skip + * around inside it, we haven't read the whole file, so we can't check the hash. But when copying it over the network * this will provide an additional safety check against user error. */ @VisibleForTesting @CordaSerializable @@ -75,15 +75,51 @@ class NodeAttachmentService(override var storePath: Path, dataSourceProperties: input: InputStream, private val counter: CountingInputStream = CountingInputStream(input), private val stream: HashingInputStream = HashingInputStream(Hashing.sha256(), counter)) : FilterInputStream(stream) { + @Throws(IOException::class) override fun close() { super.close() + validate() + } + // Possibly not used, but implemented anyway to fulfil the [FilterInputStream] contract. + @Throws(IOException::class) + override fun read(): Int { + return super.read().apply { + if (this == -1) { + validate() + } + } + } + + // This is invoked by [InputStreamSerializer], which does NOT close the stream afterwards. + @Throws(IOException::class) + override fun read(b: ByteArray?, off: Int, len: Int): Int { + return super.read(b, off, len).apply { + if (this == -1) { + validate() + } + } + } + + private fun validate() { if (counter.count != expectedSize.toLong()) return - val actual = SecureHash.SHA256(stream.hash().asBytes()) + val actual = SecureHash.SHA256(hash.asBytes()) if (actual != expected) throw HashMismatchException(expected, actual) } + + private var _hash: HashCode? = null // Backing field for hash property + private val hash: HashCode get() { + var h = _hash + return if (h == null) { + h = stream.hash() + _hash = h + h + } else { + h + } + } } private class AttachmentImpl(override val id: SecureHash, dataLoader: () -> ByteArray, private val checkOnLoad: Boolean) : AbstractAttachment(dataLoader), SerializeAsToken { From 0fd897527a9968184c2b50a8a3a04ecffbc31a48 Mon Sep 17 00:00:00 2001 From: Chris Rankin Date: Tue, 30 May 2017 14:55:58 +0100 Subject: [PATCH 012/126] Extend smoke test to cover opening attachments. (#760) --- .../kotlin/rpc/StandaloneCordaRPClientTest.kt | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/client/rpc/src/smoke-test/kotlin/net/corda/kotlin/rpc/StandaloneCordaRPClientTest.kt b/client/rpc/src/smoke-test/kotlin/net/corda/kotlin/rpc/StandaloneCordaRPClientTest.kt index f7863c4029..790cbd8ce6 100644 --- a/client/rpc/src/smoke-test/kotlin/net/corda/kotlin/rpc/StandaloneCordaRPClientTest.kt +++ b/client/rpc/src/smoke-test/kotlin/net/corda/kotlin/rpc/StandaloneCordaRPClientTest.kt @@ -1,5 +1,7 @@ package net.corda.kotlin.rpc +import com.google.common.hash.Hashing +import com.google.common.hash.HashingInputStream import java.io.FilterInputStream import java.io.InputStream import java.nio.file.Path @@ -11,6 +13,7 @@ import kotlin.test.* import net.corda.client.rpc.CordaRPCConnection import net.corda.client.rpc.notUsed import net.corda.core.contracts.* +import net.corda.core.crypto.SecureHash import net.corda.core.getOrThrow import net.corda.core.identity.Party import net.corda.core.messaging.CordaRPCOps @@ -23,6 +26,7 @@ import net.corda.core.utilities.DUMMY_NOTARY import net.corda.core.utilities.loggerFor import net.corda.flows.CashIssueFlow import net.corda.nodeapi.User +import org.apache.commons.io.output.NullOutputStream import org.junit.After import org.junit.Before import org.junit.Test @@ -71,11 +75,17 @@ class StandaloneCordaRPClientTest { } @Test - fun `test attachment upload`() { + fun `test attachments`() { val attachment = sizedInputStreamAndHash(attachmentSize) assertFalse(rpcProxy.attachmentExists(attachment.sha256)) val id = WrapperStream(attachment.inputStream).use { rpcProxy.uploadAttachment(it) } - assertEquals(id, attachment.sha256, "Attachment has incorrect SHA256 hash") + assertEquals(attachment.sha256, id, "Attachment has incorrect SHA256 hash") + + val hash = HashingInputStream(Hashing.sha256(), rpcProxy.openAttachment(id)).use { it -> + it.copyTo(NullOutputStream()) + SecureHash.SHA256(it.hash().asBytes()) + } + assertEquals(attachment.sha256, hash) } @Test From c003ec004251a5ce787f70b03b533217d03ed9df Mon Sep 17 00:00:00 2001 From: Ross Nicoll Date: Wed, 24 May 2017 17:41:59 +0100 Subject: [PATCH 013/126] Replace X509Certificate with X509CertificateHolder Replace X509Certificate with X509CertificateHolder for consistency in implementation of how X.509 certificates are managed. Using the Java standard class entails the actual implementing class being one of several options depending how a certificate is built, which makes serialization/deserialization with Kryo inconsistent as some of these forms cannot be directly built from outside restricted classes. --- .../kotlin/net/corda/core/crypto/Crypto.kt | 84 ++++++++++++++++--- .../net/corda/core/crypto/CryptoUtils.kt | 1 + .../corda/core/crypto/KeyStoreUtilities.kt | 27 +++++- .../net/corda/core/crypto/X509Utilities.kt | 46 +++++----- .../kotlin/net/corda/core/flows/TxKeyFlow.kt | 13 +-- .../kotlin/net/corda/core/identity/Party.kt | 4 +- .../core/node/services/IdentityService.kt | 3 +- .../net/corda/core/node/services/Services.kt | 10 ++- .../serialization/DefaultKryoCustomizer.kt | 6 +- .../net/corda/core/serialization/Kryo.kt | 12 +-- .../core/crypto/X509NameConstraintsTest.kt | 14 ++-- .../corda/core/crypto/X509UtilitiesTest.kt | 83 ++++++++++-------- .../net/corda/core/serialization/KryoTests.kt | 7 +- .../messaging/MQSecurityAsNodeTest.kt | 5 +- .../net/corda/node/internal/AbstractNode.kt | 5 +- .../identity/InMemoryIdentityService.kt | 7 +- .../keys/E2ETestKeyManagementService.kt | 5 +- .../net/corda/node/services/keys/KMSUtils.kt | 7 +- .../keys/PersistentKeyManagementService.kt | 6 +- .../messaging/ArtemisMessagingServer.kt | 7 +- .../services/network/NetworkMapService.kt | 4 +- .../registration/NetworkRegistrationHelper.kt | 9 +- .../NetworkisRegistrationHelperTest.kt | 5 +- .../net/corda/testing/node/MockServices.kt | 4 +- .../net/corda/testing/node/SimpleNode.kt | 5 +- 25 files changed, 257 insertions(+), 122 deletions(-) diff --git a/core/src/main/kotlin/net/corda/core/crypto/Crypto.kt b/core/src/main/kotlin/net/corda/core/crypto/Crypto.kt index 1f5f7693e2..cd4c28f497 100644 --- a/core/src/main/kotlin/net/corda/core/crypto/Crypto.kt +++ b/core/src/main/kotlin/net/corda/core/crypto/Crypto.kt @@ -9,6 +9,7 @@ import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec import org.bouncycastle.asn1.ASN1EncodableVector import org.bouncycastle.asn1.ASN1ObjectIdentifier +import org.bouncycastle.asn1.ASN1Sequence import org.bouncycastle.asn1.DERSequence import org.bouncycastle.asn1.bc.BCObjectIdentifiers import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers @@ -19,8 +20,9 @@ import org.bouncycastle.asn1.x509.Extension import org.bouncycastle.asn1.x509.NameConstraints import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo import org.bouncycastle.asn1.x9.X9ObjectIdentifiers +import org.bouncycastle.cert.X509CertificateHolder +import org.bouncycastle.cert.X509v3CertificateBuilder import org.bouncycastle.cert.bc.BcX509ExtensionUtils -import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey @@ -29,6 +31,8 @@ import org.bouncycastle.jcajce.provider.asymmetric.rsa.BCRSAPublicKey import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter import org.bouncycastle.jce.ECNamedCurveTable import org.bouncycastle.jce.provider.BouncyCastleProvider +import org.bouncycastle.operator.ContentSigner +import org.bouncycastle.operator.jcajce.JcaContentVerifierProviderBuilder import org.bouncycastle.pkcs.PKCS10CertificationRequest import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider @@ -42,7 +46,6 @@ import java.math.BigInteger import java.security.* import java.security.KeyFactory import java.security.KeyPairGenerator -import java.security.cert.X509Certificate import java.security.spec.InvalidKeySpecException import java.security.spec.PKCS8EncodedKeySpec import java.security.spec.X509EncodedKeySpec @@ -559,20 +562,25 @@ object Crypto { } /** - * Use bouncy castle utilities to sign completed X509 certificate with CA cert private key. + * Build a partial X.509 certificate ready for signing. + * + * @param issuer name of the issuing entity. + * @param subject name of the certificate subject. + * @param subjectPublicKey public key of the certificate subject. + * @param validityWindow the time period the certificate is valid for. + * @param nameConstraints any name constraints to impose on certificates signed by the generated certificate. */ - fun createCertificate(certificateType: CertificateType, issuer: X500Name, issuerKeyPair: KeyPair, + fun createCertificate(certificateType: CertificateType, issuer: X500Name, subject: X500Name, subjectPublicKey: PublicKey, validityWindow: Pair, - nameConstraints: NameConstraints? = null): X509Certificate { + nameConstraints: NameConstraints? = null): X509v3CertificateBuilder { - val signatureScheme = findSignatureScheme(issuerKeyPair.private) - val provider = providerMap[signatureScheme.providerName] val serial = BigInteger.valueOf(random63BitValue()) val keyPurposes = DERSequence(ASN1EncodableVector().apply { certificateType.purposes.forEach { add(it) } }) + val subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(ASN1Sequence.getInstance(subjectPublicKey.encoded)) val builder = JcaX509v3CertificateBuilder(issuer, serial, validityWindow.first, validityWindow.second, subject, subjectPublicKey) - .addExtension(Extension.subjectKeyIdentifier, false, BcX509ExtensionUtils().createSubjectKeyIdentifier(SubjectPublicKeyInfo.getInstance(subjectPublicKey.encoded))) + .addExtension(Extension.subjectKeyIdentifier, false, BcX509ExtensionUtils().createSubjectKeyIdentifier(subjectPublicKeyInfo)) .addExtension(Extension.basicConstraints, certificateType.isCA, BasicConstraints(certificateType.isCA)) .addExtension(Extension.keyUsage, false, certificateType.keyUsage) .addExtension(Extension.extendedKeyUsage, false, keyPurposes) @@ -580,11 +588,52 @@ object Crypto { if (nameConstraints != null) { builder.addExtension(Extension.nameConstraints, true, nameConstraints) } + return builder + } + + /** + * Build and sign an X.509 certificate with the given signer. + * + * @param issuer name of the issuing entity. + * @param issuerSigner content signer to sign the certificate with. + * @param subject name of the certificate subject. + * @param subjectPublicKey public key of the certificate subject. + * @param validityWindow the time period the certificate is valid for. + * @param nameConstraints any name constraints to impose on certificates signed by the generated certificate. + */ + fun createCertificate(certificateType: CertificateType, issuer: X500Name, issuerSigner: ContentSigner, + subject: X500Name, subjectPublicKey: PublicKey, + validityWindow: Pair, + nameConstraints: NameConstraints? = null): X509CertificateHolder { + val builder = createCertificate(certificateType, issuer, subject, subjectPublicKey, validityWindow, nameConstraints) + return builder.build(issuerSigner).apply { + require(isValidOn(Date())) + } + } + + /** + * Build and sign an X.509 certificate with CA cert private key. + * + * @param issuer name of the issuing entity. + * @param issuerKeyPair the public & private key to sign the certificate with. + * @param subject name of the certificate subject. + * @param subjectPublicKey public key of the certificate subject. + * @param validityWindow the time period the certificate is valid for. + * @param nameConstraints any name constraints to impose on certificates signed by the generated certificate. + */ + fun createCertificate(certificateType: CertificateType, issuer: X500Name, issuerKeyPair: KeyPair, + subject: X500Name, subjectPublicKey: PublicKey, + validityWindow: Pair, + nameConstraints: NameConstraints? = null): X509CertificateHolder { + + val signatureScheme = findSignatureScheme(issuerKeyPair.private) + val provider = providerMap[signatureScheme.providerName] + val builder = createCertificate(certificateType, issuer, subject, subjectPublicKey, validityWindow, nameConstraints) val signer = ContentSignerBuilder.build(signatureScheme, issuerKeyPair.private, provider) - return JcaX509CertificateConverter().setProvider(provider).getCertificate(builder.build(signer)).apply { - checkValidity(Date()) - verify(issuerKeyPair.public, provider) + return builder.build(signer).apply { + require(isValidOn(Date())) + require(isSignatureValid(JcaContentVerifierProviderBuilder().build(issuerKeyPair.public))) } } @@ -671,6 +720,19 @@ object Crypto { } } + /** + * Convert a public key to a supported implementation. This method is usually required to retrieve a key from an + * [X509CertificateHolder]. + * + * @param key a public key. + * @return a supported implementation of the input public key. + * @throws IllegalArgumentException on not supported scheme or if the given key specification + * is inappropriate for a supported key factory to produce a private key. + */ + fun toSupportedPublicKey(key: SubjectPublicKeyInfo): PublicKey { + return Crypto.decodePublicKey(key.encoded) + } + /** * Convert a public key to a supported implementation. This can be used to convert a SUN's EC key to an BC key. * This method is usually required to retrieve a key (via its corresponding cert) from JKS keystores that by default return SUN implementations. diff --git a/core/src/main/kotlin/net/corda/core/crypto/CryptoUtils.kt b/core/src/main/kotlin/net/corda/core/crypto/CryptoUtils.kt index c55d515d74..83df4d82ad 100644 --- a/core/src/main/kotlin/net/corda/core/crypto/CryptoUtils.kt +++ b/core/src/main/kotlin/net/corda/core/crypto/CryptoUtils.kt @@ -22,6 +22,7 @@ val NULL_PARTY = AnonymousParty(NullPublicKey) // TODO: Clean up this duplication between Null and Dummy public key @CordaSerializable +@Deprecated("Has encoding format problems, consider entropyToKeyPair() instead") class DummyPublicKey(val s: String) : PublicKey, Comparable { override fun getAlgorithm() = "DUMMY" override fun getEncoded() = s.toByteArray() diff --git a/core/src/main/kotlin/net/corda/core/crypto/KeyStoreUtilities.kt b/core/src/main/kotlin/net/corda/core/crypto/KeyStoreUtilities.kt index 138eed3c56..21ec1094ee 100644 --- a/core/src/main/kotlin/net/corda/core/crypto/KeyStoreUtilities.kt +++ b/core/src/main/kotlin/net/corda/core/crypto/KeyStoreUtilities.kt @@ -3,6 +3,10 @@ package net.corda.core.crypto import net.corda.core.exists import net.corda.core.read import net.corda.core.write +import org.bouncycastle.cert.X509CertificateHolder +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter +import org.bouncycastle.cert.path.CertPath +import org.bouncycastle.crypto.util.PublicKeyFactory import java.io.IOException import java.io.InputStream import java.io.OutputStream @@ -67,6 +71,19 @@ object KeyStoreUtilities { } } +/** + * Helper extension method to add, or overwrite any key data in store. + * @param alias name to record the private key and certificate chain under. + * @param key cryptographic key to store. + * @param password password for unlocking the key entry in the future. This does not have to be the same password as any keys stored, + * but for SSL purposes this is recommended. + * @param chain the sequence of certificates starting with the public key certificate for this key and extending to the root CA cert. + */ +fun KeyStore.addOrReplaceKey(alias: String, key: Key, password: CharArray, chain: CertPath) { + val converter = JcaX509CertificateConverter() + addOrReplaceKey(alias, key, password, chain.certificates.map { it -> converter.getCertificate(it) }.toTypedArray()) +} + /** * Helper extension method to add, or overwrite any key data in store. * @param alias name to record the private key and certificate chain under. @@ -122,8 +139,9 @@ fun KeyStore.getKeyPair(alias: String, keyPassword: String): KeyPair = getCertif * @param keyPassword The password for the PrivateKey (not the store access password). */ fun KeyStore.getCertificateAndKeyPair(alias: String, keyPassword: String): CertificateAndKeyPair { - val cert = getCertificate(alias) as X509Certificate - return CertificateAndKeyPair(cert, KeyPair(Crypto.toSupportedPublicKey(cert.publicKey), getSupportedKey(alias, keyPassword))) + val cert = getX509Certificate(alias) + val publicKey = Crypto.toSupportedPublicKey(cert.subjectPublicKeyInfo) + return CertificateAndKeyPair(cert, KeyPair(publicKey, getSupportedKey(alias, keyPassword))) } /** @@ -131,7 +149,10 @@ fun KeyStore.getCertificateAndKeyPair(alias: String, keyPassword: String): Certi * @param alias The name to lookup the Key and Certificate chain from. * @return The X509Certificate found in the KeyStore under the specified alias. */ -fun KeyStore.getX509Certificate(alias: String): X509Certificate = getCertificate(alias) as X509Certificate +fun KeyStore.getX509Certificate(alias: String): X509CertificateHolder { + val encoded = getCertificate(alias)?.encoded ?: throw IllegalArgumentException("No certificate under alias \"${alias}\"") + return X509CertificateHolder(encoded) +} /** * Extract a private key from a KeyStore file assuming storage alias is known. diff --git a/core/src/main/kotlin/net/corda/core/crypto/X509Utilities.kt b/core/src/main/kotlin/net/corda/core/crypto/X509Utilities.kt index 706ffdbd26..865ab09c8e 100644 --- a/core/src/main/kotlin/net/corda/core/crypto/X509Utilities.kt +++ b/core/src/main/kotlin/net/corda/core/crypto/X509Utilities.kt @@ -1,16 +1,17 @@ package net.corda.core.crypto import net.corda.core.crypto.Crypto.generateKeyPair -import net.corda.core.identity.Party -import net.corda.core.node.ServiceHub +import net.corda.core.mapToArray import org.bouncycastle.asn1.ASN1Encodable import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.asn1.x500.X500NameBuilder import org.bouncycastle.asn1.x500.style.BCStyle import org.bouncycastle.asn1.x509.* import org.bouncycastle.cert.X509CertificateHolder +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter import org.bouncycastle.openssl.jcajce.JcaPEMWriter import org.bouncycastle.util.io.pem.PemReader +import java.io.ByteArrayInputStream import java.io.FileReader import java.io.FileWriter import java.io.InputStream @@ -62,7 +63,7 @@ object X509Utilities { * @param after duration to roll forward returned end date relative to current date. * @param parent if provided certificate whose validity should bound the date interval returned. */ - private fun getCertificateValidityWindow(before: Duration, after: Duration, parent: X509Certificate? = null): Pair { + fun getCertificateValidityWindow(before: Duration, after: Duration, parent: X509CertificateHolder? = null): Pair { val startOfDayUTC = Instant.now().truncatedTo(ChronoUnit.DAYS) val notBefore = max(startOfDayUTC - before, parent?.notBefore) val notAfter = min(startOfDayUTC + after, parent?.notAfter) @@ -104,10 +105,9 @@ object X509Utilities { * Create a de novo root self-signed X509 v3 CA cert. */ @JvmStatic - fun createSelfSignedCACertificate(subject: X500Name, keyPair: KeyPair, validityWindow: Pair = DEFAULT_VALIDITY_WINDOW): X509Certificate { + fun createSelfSignedCACertificate(subject: X500Name, keyPair: KeyPair, validityWindow: Pair = DEFAULT_VALIDITY_WINDOW): X509CertificateHolder { val window = getCertificateValidityWindow(validityWindow.first, validityWindow.second) - val cert = Crypto.createCertificate(CertificateType.ROOT_CA, subject, keyPair, subject, keyPair.public, window) - return cert + return Crypto.createCertificate(CertificateType.ROOT_CA, subject, keyPair, subject, keyPair.public, window) } /** @@ -122,13 +122,12 @@ object X509Utilities { */ @JvmStatic fun createCertificate(certificateType: CertificateType, - issuerCertificate: X509Certificate, issuerKeyPair: KeyPair, + issuerCertificate: X509CertificateHolder, issuerKeyPair: KeyPair, subject: X500Name, subjectPublicKey: PublicKey, validityWindow: Pair = DEFAULT_VALIDITY_WINDOW, - nameConstraints: NameConstraints? = null): X509Certificate { + nameConstraints: NameConstraints? = null): X509CertificateHolder { val window = getCertificateValidityWindow(validityWindow.first, validityWindow.second, issuerCertificate) - val cert = Crypto.createCertificate(certificateType, issuerCertificate.subject, issuerKeyPair, subject, subjectPublicKey, window, nameConstraints) - return cert + return Crypto.createCertificate(certificateType, issuerCertificate.subject, issuerKeyPair, subject, subjectPublicKey, window, nameConstraints) } /** @@ -139,17 +138,19 @@ object X509Utilities { * @param certificates certificates in the path. * @param revocationEnabled whether revocation of certificates in the path should be checked. */ - fun createCertificatePath(trustedRoot: X509Certificate, vararg certificates: X509Certificate, revocationEnabled: Boolean): CertPath { + fun createCertificatePath(trustedRoot: X509CertificateHolder, vararg certificates: X509CertificateHolder, revocationEnabled: Boolean): CertPath { val certFactory = CertificateFactory.getInstance("X509") - val params = PKIXParameters(setOf(TrustAnchor(trustedRoot, null))) + val trustedRootX509 = certFactory.generateCertificate(ByteArrayInputStream(trustedRoot.encoded)) as X509Certificate + val params = PKIXParameters(setOf(TrustAnchor(trustedRootX509, null))) params.isRevocationEnabled = revocationEnabled - return certFactory.generateCertPath(certificates.toList()) + return certFactory.generateCertPath(certificates.map { certFactory.generateCertificate(ByteArrayInputStream(it.encoded)) }.toList()) } - fun validateCertificateChain(trustedRoot: X509Certificate, vararg certificates: Certificate) { + fun validateCertificateChain(trustedRoot: X509CertificateHolder, vararg certificates: Certificate) { require(certificates.isNotEmpty()) { "Certificate path must contain at least one certificate" } + val converter = JcaX509CertificateConverter() val certFactory = CertificateFactory.getInstance("X509") - val params = PKIXParameters(setOf(TrustAnchor(trustedRoot, null))) + val params = PKIXParameters(setOf(TrustAnchor(converter.getCertificate(trustedRoot), null))) params.isRevocationEnabled = false val certPath = certFactory.generateCertPath(certificates.toList()) val pathValidator = CertPathValidator.getInstance("PKIX") @@ -162,7 +163,7 @@ object X509Utilities { * @param filename Target filename. */ @JvmStatic - fun saveCertificateAsPEMFile(x509Certificate: X509Certificate, filename: Path) { + fun saveCertificateAsPEMFile(x509Certificate: X509CertificateHolder, filename: Path) { FileWriter(filename.toFile()).use { JcaPEMWriter(it).use { it.writeObject(x509Certificate) @@ -176,11 +177,12 @@ object X509Utilities { * @return The X509Certificate that was encoded in the file. */ @JvmStatic - fun loadCertificateFromPEMFile(filename: Path): X509Certificate { + fun loadCertificateFromPEMFile(filename: Path): X509CertificateHolder { val reader = PemReader(FileReader(filename.toFile())) val pemObject = reader.readPemObject() - return CertificateStream(pemObject.content.inputStream()).nextCertificate().apply { - checkValidity() + val cert = X509CertificateHolder(pemObject.content) + return cert.apply { + isValidOn(Date()) } } @@ -221,7 +223,7 @@ object X509Utilities { CORDA_CLIENT_CA, clientKey.private, keyPass, - arrayOf(clientCACert, intermediateCACert, rootCACert)) + org.bouncycastle.cert.path.CertPath(arrayOf(clientCACert, intermediateCACert, rootCACert))) clientCAKeystore.save(clientCAKeystorePath, storePassword) val tlsKeystore = KeyStoreUtilities.loadOrCreateKeyStore(sslKeyStorePath, storePassword) @@ -229,7 +231,7 @@ object X509Utilities { CORDA_CLIENT_TLS, tlsKey.private, keyPass, - arrayOf(clientTLSCert, clientCACert, intermediateCACert, rootCACert)) + org.bouncycastle.cert.path.CertPath(arrayOf(clientTLSCert, clientCACert, intermediateCACert, rootCACert))) tlsKeystore.save(sslKeyStorePath, storePassword) } @@ -286,7 +288,7 @@ class CertificateStream(val input: InputStream) { fun nextCertificate(): X509Certificate = certificateFactory.generateCertificate(input) as X509Certificate } -data class CertificateAndKeyPair(val certificate: X509Certificate, val keyPair: KeyPair) +data class CertificateAndKeyPair(val certificate: X509CertificateHolder, val keyPair: KeyPair) enum class CertificateType(val keyUsage: KeyUsage, vararg val purposes: KeyPurposeId, val isCA: Boolean) { ROOT_CA(KeyUsage(KeyUsage.digitalSignature or KeyUsage.keyCertSign or KeyUsage.cRLSign), KeyPurposeId.id_kp_serverAuth, KeyPurposeId.id_kp_clientAuth, KeyPurposeId.anyExtendedKeyUsage, isCA = true), diff --git a/core/src/main/kotlin/net/corda/core/flows/TxKeyFlow.kt b/core/src/main/kotlin/net/corda/core/flows/TxKeyFlow.kt index 32ba268709..05a48c6895 100644 --- a/core/src/main/kotlin/net/corda/core/flows/TxKeyFlow.kt +++ b/core/src/main/kotlin/net/corda/core/flows/TxKeyFlow.kt @@ -6,6 +6,7 @@ import net.corda.core.identity.Party import net.corda.core.utilities.ProgressTracker import net.corda.core.utilities.unwrap import org.bouncycastle.asn1.x500.X500Name +import org.bouncycastle.cert.X509CertificateHolder import java.security.cert.CertPath import java.security.cert.X509Certificate @@ -15,7 +16,7 @@ import java.security.cert.X509Certificate */ object TxKeyFlow { abstract class AbstractIdentityFlow(val otherSide: Party, val revocationEnabled: Boolean): FlowLogic>() { - fun validateIdentity(untrustedIdentity: Pair): AnonymousIdentity { + fun validateIdentity(untrustedIdentity: Pair): AnonymousIdentity { val (wellKnownCert, certPath) = untrustedIdentity val theirCert = certPath.certificates.last() // TODO: Don't trust self-signed certificates @@ -24,7 +25,7 @@ object TxKeyFlow { if (certName == otherSide.name) { val anonymousParty = AnonymousParty(theirCert.publicKey) serviceHub.identityService.registerPath(wellKnownCert, anonymousParty, certPath) - AnonymousIdentity(certPath, theirCert, anonymousParty) + AnonymousIdentity(certPath, X509CertificateHolder(theirCert.encoded), anonymousParty) } else throw IllegalStateException("Expected certificate subject to be ${otherSide.name} but found ${certName}") } else @@ -50,7 +51,7 @@ object TxKeyFlow { override fun call(): Map { progressTracker.currentStep = AWAITING_KEY val myIdentityFragment = serviceHub.keyManagementService.freshKeyAndCert(serviceHub.myInfo.legalIdentity, revocationEnabled) - val theirIdentity = receive>(otherSide).unwrap { validateIdentity(it) } + val theirIdentity = receive>(otherSide).unwrap { validateIdentity(it) } send(otherSide, myIdentityFragment) return mapOf(Pair(otherSide, AnonymousIdentity(myIdentityFragment)), Pair(serviceHub.myInfo.legalIdentity, theirIdentity)) @@ -78,7 +79,7 @@ object TxKeyFlow { progressTracker.currentStep = SENDING_KEY val myIdentityFragment = serviceHub.keyManagementService.freshKeyAndCert(serviceHub.myInfo.legalIdentity, revocationEnabled) send(otherSide, myIdentityFragment) - val theirIdentity = receive>(otherSide).unwrap { validateIdentity(it) } + val theirIdentity = receive>(otherSide).unwrap { validateIdentity(it) } return mapOf(Pair(otherSide, AnonymousIdentity(myIdentityFragment)), Pair(serviceHub.myInfo.legalIdentity, theirIdentity)) } @@ -86,9 +87,9 @@ object TxKeyFlow { data class AnonymousIdentity( val certPath: CertPath, - val certificate: X509Certificate, + val certificate: X509CertificateHolder, val identity: AnonymousParty) { - constructor(myIdentity: Pair) : this(myIdentity.second, + constructor(myIdentity: Pair) : this(myIdentity.second, myIdentity.first, AnonymousParty(myIdentity.second.certificates.last().publicKey)) } diff --git a/core/src/main/kotlin/net/corda/core/identity/Party.kt b/core/src/main/kotlin/net/corda/core/identity/Party.kt index b94f266b8c..45486049e8 100644 --- a/core/src/main/kotlin/net/corda/core/identity/Party.kt +++ b/core/src/main/kotlin/net/corda/core/identity/Party.kt @@ -26,8 +26,8 @@ import java.security.PublicKey * * @see CompositeKey */ -class Party(val name: X500Name, owningKey: PublicKey) : AbstractParty(owningKey) { - constructor(certAndKey: CertificateAndKeyPair) : this(X500Name(certAndKey.certificate.subjectDN.name), certAndKey.keyPair.public) +open class Party(val name: X500Name, owningKey: PublicKey) : AbstractParty(owningKey) { + constructor(certAndKey: CertificateAndKeyPair) : this(certAndKey.certificate.subject, certAndKey.keyPair.public) override fun toString() = name.toString() override fun nameOrNull(): X500Name? = name diff --git a/core/src/main/kotlin/net/corda/core/node/services/IdentityService.kt b/core/src/main/kotlin/net/corda/core/node/services/IdentityService.kt index d066d1007c..71cb0c7b38 100644 --- a/core/src/main/kotlin/net/corda/core/node/services/IdentityService.kt +++ b/core/src/main/kotlin/net/corda/core/node/services/IdentityService.kt @@ -6,6 +6,7 @@ import net.corda.core.identity.AbstractParty import net.corda.core.identity.AnonymousParty import net.corda.core.identity.Party import org.bouncycastle.asn1.x500.X500Name +import org.bouncycastle.cert.X509CertificateHolder import java.security.PublicKey import java.security.cert.CertPath import java.security.cert.X509Certificate @@ -30,7 +31,7 @@ interface IdentityService { */ // TODO: Move this into internal identity service once available @Throws(IllegalArgumentException::class) - fun registerPath(trustedRoot: X509Certificate, anonymousParty: AnonymousParty, path: CertPath) + fun registerPath(trustedRoot: X509CertificateHolder, anonymousParty: AnonymousParty, path: CertPath) /** * Asserts that an anonymous party maps to the given full party, by looking up the certificate chain associated with diff --git a/core/src/main/kotlin/net/corda/core/node/services/Services.kt b/core/src/main/kotlin/net/corda/core/node/services/Services.kt index 65fd283927..a673001f05 100644 --- a/core/src/main/kotlin/net/corda/core/node/services/Services.kt +++ b/core/src/main/kotlin/net/corda/core/node/services/Services.kt @@ -3,10 +3,12 @@ package net.corda.core.node.services import co.paralleluniverse.fibers.Suspendable import com.google.common.util.concurrent.ListenableFuture import net.corda.core.contracts.* -import net.corda.core.crypto.* +import net.corda.core.crypto.CompositeKey +import net.corda.core.crypto.DigitalSignature +import net.corda.core.crypto.SecureHash +import net.corda.core.crypto.keys import net.corda.core.flows.FlowException import net.corda.core.identity.AbstractParty -import net.corda.core.identity.AnonymousParty import net.corda.core.identity.Party import net.corda.core.node.services.vault.PageSpecification import net.corda.core.node.services.vault.QueryCriteria @@ -17,6 +19,8 @@ import net.corda.core.toFuture import net.corda.core.transactions.LedgerTransaction import net.corda.core.transactions.TransactionBuilder import net.corda.core.transactions.WireTransaction +import org.bouncycastle.cert.X509CertificateHolder +import org.bouncycastle.operator.ContentSigner import rx.Observable import java.io.InputStream import java.security.PublicKey @@ -396,7 +400,7 @@ interface KeyManagementService { * @return X.509 certificate and path to the trust root. */ @Suspendable - fun freshKeyAndCert(identity: Party, revocationEnabled: Boolean): Pair + fun freshKeyAndCert(identity: Party, revocationEnabled: Boolean): Pair /** Using the provided signing [PublicKey] internally looks up the matching [PrivateKey] and signs the data. * @param bytes The data to sign over using the chosen key. diff --git a/core/src/main/kotlin/net/corda/core/serialization/DefaultKryoCustomizer.kt b/core/src/main/kotlin/net/corda/core/serialization/DefaultKryoCustomizer.kt index 825ce18a20..a88e2ec073 100644 --- a/core/src/main/kotlin/net/corda/core/serialization/DefaultKryoCustomizer.kt +++ b/core/src/main/kotlin/net/corda/core/serialization/DefaultKryoCustomizer.kt @@ -18,6 +18,7 @@ import net.corda.core.utilities.NonEmptySetSerializer import net.i2p.crypto.eddsa.EdDSAPrivateKey import net.i2p.crypto.eddsa.EdDSAPublicKey import org.bouncycastle.asn1.x500.X500Name +import org.bouncycastle.cert.X509CertificateHolder import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey import org.bouncycastle.jcajce.provider.asymmetric.rsa.BCRSAPrivateCrtKey @@ -102,11 +103,8 @@ object DefaultKryoCustomizer { register(CertPath::class.java, CertPathSerializer) register(X509CertPath::class.java, CertPathSerializer) - // TODO: We shouldn't need to serialize raw certificates, and if we do then we need a cleaner solution - // than this mess. - val x509CertObjectClazz = Class.forName("org.bouncycastle.jcajce.provider.asymmetric.x509.X509CertificateObject") - register(x509CertObjectClazz, X509CertificateSerializer) register(X500Name::class.java, X500NameSerializer) + register(X509CertificateHolder::class.java, X509CertificateSerializer) register(BCECPrivateKey::class.java, PrivateKeySerializer) register(BCECPublicKey::class.java, PublicKeySerializer) diff --git a/core/src/main/kotlin/net/corda/core/serialization/Kryo.kt b/core/src/main/kotlin/net/corda/core/serialization/Kryo.kt index a4315ee500..5a68d5a5c5 100644 --- a/core/src/main/kotlin/net/corda/core/serialization/Kryo.kt +++ b/core/src/main/kotlin/net/corda/core/serialization/Kryo.kt @@ -20,6 +20,7 @@ import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec import org.bouncycastle.asn1.ASN1InputStream import org.bouncycastle.asn1.x500.X500Name +import org.bouncycastle.cert.X509CertificateHolder import org.slf4j.Logger import org.slf4j.LoggerFactory import java.io.ByteArrayInputStream @@ -632,16 +633,15 @@ object CertPathSerializer : Serializer() { } /** - * For serialising an [CX509Certificate] in an X.500 standard format. + * For serialising an [CX509CertificateHolder] in an X.500 standard format. */ @ThreadSafe -object X509CertificateSerializer : Serializer() { - val factory = CertificateFactory.getInstance("X.509") - override fun read(kryo: Kryo, input: Input, type: Class): X509Certificate { - return factory.generateCertificate(input) as X509Certificate +object X509CertificateSerializer : Serializer() { + override fun read(kryo: Kryo, input: Input, type: Class): X509CertificateHolder { + return X509CertificateHolder(input.readBytes()) } - override fun write(kryo: Kryo, output: Output, obj: X509Certificate) { + override fun write(kryo: Kryo, output: Output, obj: X509CertificateHolder) { output.writeBytes(obj.encoded) } } diff --git a/core/src/test/kotlin/net/corda/core/crypto/X509NameConstraintsTest.kt b/core/src/test/kotlin/net/corda/core/crypto/X509NameConstraintsTest.kt index 2d687df267..beceab89f1 100644 --- a/core/src/test/kotlin/net/corda/core/crypto/X509NameConstraintsTest.kt +++ b/core/src/test/kotlin/net/corda/core/crypto/X509NameConstraintsTest.kt @@ -1,22 +1,23 @@ package net.corda.core.crypto +import net.corda.core.mapToArray import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.asn1.x509.GeneralName import org.bouncycastle.asn1.x509.GeneralSubtree import org.bouncycastle.asn1.x509.NameConstraints +import org.bouncycastle.cert.X509CertificateHolder +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter import org.bouncycastle.jce.provider.BouncyCastleProvider import org.junit.Test import java.security.KeyStore -import java.security.cert.CertPathValidator -import java.security.cert.CertPathValidatorException -import java.security.cert.CertificateFactory -import java.security.cert.PKIXParameters +import java.security.cert.* import kotlin.test.assertFailsWith import kotlin.test.assertTrue class X509NameConstraintsTest { private fun makeKeyStores(subjectName: X500Name, nameConstraints: NameConstraints): Pair { + val converter = JcaX509CertificateConverter() val rootKeys = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) val rootCACert = X509Utilities.createSelfSignedCACertificate(X509Utilities.getDevX509Name("Corda Root CA"), rootKeys) @@ -29,14 +30,15 @@ class X509NameConstraintsTest { val keyPass = "password" val trustStore = KeyStore.getInstance(KeyStoreUtilities.KEYSTORE_TYPE) trustStore.load(null, keyPass.toCharArray()) - trustStore.addOrReplaceCertificate(X509Utilities.CORDA_ROOT_CA, rootCACert) + trustStore.addOrReplaceCertificate(X509Utilities.CORDA_ROOT_CA, converter.getCertificate(rootCACert)) val tlsKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) val tlsCert = X509Utilities.createCertificate(CertificateType.TLS, clientCACert, clientCAKeyPair, subjectName, tlsKey.public) val keyStore = KeyStore.getInstance(KeyStoreUtilities.KEYSTORE_TYPE) keyStore.load(null, keyPass.toCharArray()) - keyStore.addOrReplaceKey(X509Utilities.CORDA_CLIENT_TLS, tlsKey.private, keyPass.toCharArray(), arrayOf(tlsCert, clientCACert, intermediateCACert, rootCACert)) + keyStore.addOrReplaceKey(X509Utilities.CORDA_CLIENT_TLS, tlsKey.private, keyPass.toCharArray(), + listOf(tlsCert, clientCACert, intermediateCACert, rootCACert).mapToArray(converter::getCertificate)) return Pair(keyStore, trustStore) } diff --git a/core/src/test/kotlin/net/corda/core/crypto/X509UtilitiesTest.kt b/core/src/test/kotlin/net/corda/core/crypto/X509UtilitiesTest.kt index 2a25d8c60f..811c88495a 100644 --- a/core/src/test/kotlin/net/corda/core/crypto/X509UtilitiesTest.kt +++ b/core/src/test/kotlin/net/corda/core/crypto/X509UtilitiesTest.kt @@ -5,29 +5,35 @@ import net.corda.core.crypto.Crypto.generateKeyPair import net.corda.core.crypto.X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME import net.corda.core.crypto.X509Utilities.createSelfSignedCACertificate import net.corda.core.div +import net.corda.core.mapToArray import net.corda.testing.MEGA_CORP import net.corda.testing.getTestX509Name import org.bouncycastle.asn1.x500.X500Name +import org.bouncycastle.asn1.x509.BasicConstraints +import org.bouncycastle.asn1.x509.Extension +import org.bouncycastle.asn1.x509.KeyUsage +import org.bouncycastle.cert.X509CertificateHolder +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter +import org.bouncycastle.operator.jcajce.JcaContentVerifierProviderBuilder import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder import java.io.DataInputStream import java.io.DataOutputStream import java.io.IOException +import java.math.BigInteger import java.net.InetAddress import java.net.InetSocketAddress import java.nio.file.Path import java.security.KeyStore import java.security.PrivateKey import java.security.SecureRandom +import java.security.cert.Certificate import java.security.cert.X509Certificate import java.util.* import javax.net.ssl.* import kotlin.concurrent.thread -import kotlin.test.assertEquals -import kotlin.test.assertFalse -import kotlin.test.assertNotNull -import kotlin.test.assertTrue +import kotlin.test.* class X509UtilitiesTest { @Rule @@ -38,12 +44,14 @@ class X509UtilitiesTest { fun `create valid self-signed CA certificate`() { val caKey = generateKeyPair(DEFAULT_TLS_SIGNATURE_SCHEME) val caCert = createSelfSignedCACertificate(getTestX509Name("Test Cert"), caKey) - assertTrue { caCert.subjectDN.name.contains("CN=Test Cert") } // using our subject common name - assertEquals(caCert.issuerDN, caCert.subjectDN) //self-signed - caCert.checkValidity(Date()) // throws on verification problems - caCert.verify(caKey.public) // throws on verification problems - assertTrue { caCert.keyUsage[5] } // Bit 5 == keyCertSign according to ASN.1 spec (see full comment on KeyUsage property) - assertTrue { caCert.basicConstraints > 0 } // This returns the signing path length Would be -1 for non-CA certificate + assertTrue { caCert.subject.commonName == "Test Cert" } // using our subject common name + assertEquals(caCert.issuer, caCert.subject) //self-signed + caCert.isValidOn(Date()) // throws on verification problems + caCert.isSignatureValid(JcaContentVerifierProviderBuilder().build(caKey.public)) // throws on verification problems + val basicConstraints = BasicConstraints.getInstance(caCert.getExtension(Extension.basicConstraints).parsedValue) + val keyUsage = KeyUsage.getInstance(caCert.getExtension(Extension.keyUsage).parsedValue) + assertFalse { keyUsage.hasUsages(5) } // Bit 5 == keyCertSign according to ASN.1 spec (see full comment on KeyUsage property) + assertNull(basicConstraints.pathLenConstraint) // No length constraint specified on this CA certificate } @Test @@ -60,29 +68,33 @@ class X509UtilitiesTest { fun `create valid server certificate chain`() { val caKey = generateKeyPair(DEFAULT_TLS_SIGNATURE_SCHEME) val caCert = createSelfSignedCACertificate(getTestX509Name("Test CA Cert"), caKey) - val subjectDN = getTestX509Name("Server Cert") + val subject = getTestX509Name("Server Cert") val keyPair = generateKeyPair(DEFAULT_TLS_SIGNATURE_SCHEME) - val serverCert = X509Utilities.createCertificate(CertificateType.TLS, caCert, caKey, subjectDN, keyPair.public) - assertTrue { serverCert.subjectDN.name.contains("CN=Server Cert") } // using our subject common name - assertEquals(caCert.issuerDN, serverCert.issuerDN) // Issued by our CA cert - serverCert.checkValidity(Date()) // throws on verification problems - serverCert.verify(caKey.public) // throws on verification problems - assertFalse { serverCert.keyUsage[5] } // Bit 5 == keyCertSign according to ASN.1 spec (see full comment on KeyUsage property) - assertTrue { serverCert.basicConstraints == -1 } // This returns the signing path length should be -1 for non-CA certificate + val serverCert = X509Utilities.createCertificate(CertificateType.TLS, caCert, caKey, subject, keyPair.public) + assertTrue { serverCert.subject.toString().contains("CN=Server Cert") } // using our subject common name + assertEquals(caCert.issuer, serverCert.issuer) // Issued by our CA cert + serverCert.isValidOn(Date()) // throws on verification problems + serverCert.isSignatureValid(JcaContentVerifierProviderBuilder().build(caKey.public)) // throws on verification problems + val basicConstraints = BasicConstraints.getInstance(serverCert.getExtension(Extension.basicConstraints).parsedValue) + val keyUsage = KeyUsage.getInstance(serverCert.getExtension(Extension.keyUsage).parsedValue) + assertFalse { keyUsage.hasUsages(5) } // Bit 5 == keyCertSign according to ASN.1 spec (see full comment on KeyUsage property) + assertNull(basicConstraints.pathLenConstraint) // Non-CA certificate } @Test fun `storing EdDSA key in java keystore`() { val tmpKeyStore = tempFile("keystore.jks") + val converter = JcaX509CertificateConverter() val keyPair = generateKeyPair(EDDSA_ED25519_SHA512) val selfSignCert = createSelfSignedCACertificate(X500Name("CN=Test"), keyPair) - assertEquals(selfSignCert.publicKey, keyPair.public) + assertTrue(Arrays.equals(selfSignCert.subjectPublicKeyInfo.encoded, keyPair.public.encoded)) // Save the EdDSA private key with self sign cert in the keystore. val keyStore = KeyStoreUtilities.loadOrCreateKeyStore(tmpKeyStore, "keystorepass") - keyStore.setKeyEntry("Key", keyPair.private, "password".toCharArray(), arrayOf(selfSignCert)) + keyStore.setKeyEntry("Key", keyPair.private, "password".toCharArray(), + listOf(selfSignCert).mapToArray(converter::getCertificate)) keyStore.save(tmpKeyStore, "keystorepass") // Load the keystore from file and make sure keys are intact. @@ -105,8 +117,10 @@ class X509UtilitiesTest { val edDSACert = X509Utilities.createCertificate(CertificateType.TLS, ecDSACert, ecDSAKey, X500Name("CN=TestEdDSA"), edDSAKeypair.public) // Save the EdDSA private key with cert chains. + val converter = JcaX509CertificateConverter() val keyStore = KeyStoreUtilities.loadOrCreateKeyStore(tmpKeyStore, "keystorepass") - keyStore.setKeyEntry("Key", edDSAKeypair.private, "password".toCharArray(), arrayOf(ecDSACert, edDSACert)) + keyStore.setKeyEntry("Key", edDSAKeypair.private, "password".toCharArray(), + listOf(ecDSACert, edDSACert).mapToArray(converter::getCertificate)) keyStore.save(tmpKeyStore, "keystorepass") // Load the keystore from file and make sure keys are intact. @@ -182,23 +196,24 @@ class X509UtilitiesTest { val serverKeyStore = KeyStoreUtilities.loadKeyStore(tmpServerKeyStore, "serverstorepass") val serverCertAndKey = serverKeyStore.getCertificateAndKeyPair(X509Utilities.CORDA_CLIENT_CA, "serverkeypass") - serverCertAndKey.certificate.checkValidity(Date()) - serverCertAndKey.certificate.verify(caCertAndKey.certificate.publicKey) + serverCertAndKey.certificate.isValidOn(Date()) + serverCertAndKey.certificate.isSignatureValid(JcaContentVerifierProviderBuilder().build(caCertAndKey.certificate.subjectPublicKeyInfo)) - assertTrue { serverCertAndKey.certificate.subjectDN.name.contains(MEGA_CORP.name.commonName) } + assertTrue { serverCertAndKey.certificate.subject.toString().contains(MEGA_CORP.name.commonName) } // Load back server certificate val sslKeyStore = KeyStoreUtilities.loadKeyStore(tmpSSLKeyStore, "serverstorepass") val sslCertAndKey = sslKeyStore.getCertificateAndKeyPair(X509Utilities.CORDA_CLIENT_TLS, "serverkeypass") - sslCertAndKey.certificate.checkValidity(Date()) - sslCertAndKey.certificate.verify(serverCertAndKey.certificate.publicKey) + sslCertAndKey.certificate.isValidOn(Date()) + sslCertAndKey.certificate.isSignatureValid(JcaContentVerifierProviderBuilder().build(serverCertAndKey.certificate.subjectPublicKeyInfo)) - assertTrue { sslCertAndKey.certificate.subjectDN.name.contains(MEGA_CORP.name.commonName) } + assertTrue { sslCertAndKey.certificate.subject.toString().contains(MEGA_CORP.name.commonName) } // Now sign something with private key and verify against certificate public key val testData = "123456".toByteArray() val signature = Crypto.doSign(DEFAULT_TLS_SIGNATURE_SCHEME, serverCertAndKey.keyPair.private, testData) - assertTrue { Crypto.isValid(DEFAULT_TLS_SIGNATURE_SCHEME, serverCertAndKey.certificate.publicKey, signature, testData) } + val publicKey = Crypto.toSupportedPublicKey(serverCertAndKey.certificate.subjectPublicKeyInfo) + assertTrue { Crypto.isValid(DEFAULT_TLS_SIGNATURE_SCHEME, publicKey, signature, testData) } } @Test @@ -330,6 +345,7 @@ class X509UtilitiesTest { trustStoreFilePath: Path, trustStorePassword: String ): KeyStore { + val converter = JcaX509CertificateConverter() val rootCAKey = generateKeyPair(DEFAULT_TLS_SIGNATURE_SCHEME) val rootCACert = createSelfSignedCACertificate(X509Utilities.getDevX509Name("Corda Node Root CA"), rootCAKey) @@ -339,19 +355,19 @@ class X509UtilitiesTest { val keyPass = keyPassword.toCharArray() val keyStore = KeyStoreUtilities.loadOrCreateKeyStore(keyStoreFilePath, storePassword) - keyStore.addOrReplaceKey(X509Utilities.CORDA_ROOT_CA, rootCAKey.private, keyPass, arrayOf(rootCACert)) + keyStore.addOrReplaceKey(X509Utilities.CORDA_ROOT_CA, rootCAKey.private, keyPass, arrayOf(converter.getCertificate(rootCACert) as Certificate)) keyStore.addOrReplaceKey(X509Utilities.CORDA_INTERMEDIATE_CA, intermediateCAKeyPair.private, keyPass, - arrayOf(intermediateCACert, rootCACert)) + listOf(intermediateCACert, rootCACert).mapToArray(converter::getCertificate)) keyStore.save(keyStoreFilePath, storePassword) val trustStore = KeyStoreUtilities.loadOrCreateKeyStore(trustStoreFilePath, trustStorePassword) - trustStore.addOrReplaceCertificate(X509Utilities.CORDA_ROOT_CA, rootCACert) - trustStore.addOrReplaceCertificate(X509Utilities.CORDA_INTERMEDIATE_CA, intermediateCACert) + trustStore.addOrReplaceCertificate(X509Utilities.CORDA_ROOT_CA, converter.getCertificate(rootCACert)) + trustStore.addOrReplaceCertificate(X509Utilities.CORDA_INTERMEDIATE_CA, converter.getCertificate(intermediateCACert)) trustStore.save(trustStoreFilePath, trustStorePassword) @@ -360,10 +376,11 @@ class X509UtilitiesTest { @Test fun `Get correct private key type from Keystore`() { + val converter = JcaX509CertificateConverter() val keyPair = generateKeyPair(Crypto.ECDSA_SECP256R1_SHA256) val selfSignCert = createSelfSignedCACertificate(X500Name("CN=Test"), keyPair) val keyStore = KeyStoreUtilities.loadOrCreateKeyStore(tempFile("testKeystore.jks"), "keystorepassword") - keyStore.setKeyEntry("Key", keyPair.private, "keypassword".toCharArray(), arrayOf(selfSignCert)) + keyStore.setKeyEntry("Key", keyPair.private, "keypassword".toCharArray(), arrayOf(converter.getCertificate(selfSignCert))) val keyFromKeystore = keyStore.getKey("Key", "keypassword".toCharArray()) val keyFromKeystoreCasted = keyStore.getSupportedKey("Key", "keypassword") diff --git a/core/src/test/kotlin/net/corda/core/serialization/KryoTests.kt b/core/src/test/kotlin/net/corda/core/serialization/KryoTests.kt index 521e0f2b20..6250b85108 100644 --- a/core/src/test/kotlin/net/corda/core/serialization/KryoTests.kt +++ b/core/src/test/kotlin/net/corda/core/serialization/KryoTests.kt @@ -10,6 +10,7 @@ import net.corda.node.services.persistence.NodeAttachmentService import net.corda.testing.BOB_PUBKEY import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThatThrownBy +import org.bouncycastle.cert.X509CertificateHolder import org.junit.Before import org.junit.Test import org.slf4j.LoggerFactory @@ -142,10 +143,10 @@ class KryoTests { } @Test - fun `serialize - deserialize X509Certififcate`() { - val expected = X509Utilities.createSelfSignedCACertificate(ALICE.name, Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)) + fun `serialize - deserialize X509CertififcateHolder`() { + val expected: X509CertificateHolder = X509Utilities.createSelfSignedCACertificate(ALICE.name, Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)) val serialized = expected.serialize(kryo).bytes - val actual: X509Certificate = serialized.deserialize(kryo) + val actual: X509CertificateHolder = serialized.deserialize(kryo) assertEquals(expected, actual) } diff --git a/node/src/integration-test/kotlin/net/corda/services/messaging/MQSecurityAsNodeTest.kt b/node/src/integration-test/kotlin/net/corda/services/messaging/MQSecurityAsNodeTest.kt index f32f267a82..d4bb517abf 100644 --- a/node/src/integration-test/kotlin/net/corda/services/messaging/MQSecurityAsNodeTest.kt +++ b/node/src/integration-test/kotlin/net/corda/services/messaging/MQSecurityAsNodeTest.kt @@ -19,6 +19,7 @@ import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.bouncycastle.asn1.x509.GeneralName import org.bouncycastle.asn1.x509.GeneralSubtree import org.bouncycastle.asn1.x509.NameConstraints +import org.bouncycastle.cert.path.CertPath import org.junit.Test import java.nio.file.Files @@ -111,7 +112,7 @@ class MQSecurityAsNodeTest : MQSecurityTest() { X509Utilities.CORDA_CLIENT_CA, clientKey.private, keyPass, - arrayOf(clientCACert, intermediateCA.certificate, rootCACert)) + CertPath(arrayOf(clientCACert, intermediateCA.certificate, rootCACert))) clientCAKeystore.save(nodeKeystore, keyStorePassword) val tlsKeystore = KeyStoreUtilities.loadOrCreateKeyStore(sslKeystore, keyStorePassword) @@ -119,7 +120,7 @@ class MQSecurityAsNodeTest : MQSecurityTest() { X509Utilities.CORDA_CLIENT_TLS, tlsKey.private, keyPass, - arrayOf(clientTLSCert, clientCACert, intermediateCA.certificate, rootCACert)) + CertPath(arrayOf(clientTLSCert, clientCACert, intermediateCA.certificate, rootCACert))) tlsKeystore.save(sslKeystore, keyStorePassword) } } diff --git a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt index dbe68f221c..60cd48af1b 100644 --- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt @@ -57,6 +57,7 @@ import net.corda.node.utilities.transaction import org.apache.activemq.artemis.utils.ReusableLatch import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.cert.X509CertificateHolder +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter import org.jetbrains.exposed.sql.Database import org.slf4j.Logger import java.io.IOException @@ -671,8 +672,10 @@ private class KeyStoreWrapper(private val storePath: Path, private val storePass fun save(serviceName: X500Name, privateKeyAlias: String, keyPair: KeyPair) { val clientCA = keyStore.getCertificateAndKeyPair(X509Utilities.CORDA_CLIENT_CA, storePassword) + val converter = JcaX509CertificateConverter() val cert = X509Utilities.createCertificate(CertificateType.IDENTITY, clientCA.certificate, clientCA.keyPair, serviceName, keyPair.public) - keyStore.addOrReplaceKey(privateKeyAlias, keyPair.private, storePassword.toCharArray(), arrayOf(cert, *keyStore.getCertificateChain(X509Utilities.CORDA_CLIENT_CA))) + keyStore.addOrReplaceKey(privateKeyAlias, keyPair.private, storePassword.toCharArray(), + arrayOf(converter.getCertificate(cert), *keyStore.getCertificateChain(X509Utilities.CORDA_CLIENT_CA))) keyStore.save(storePath, storePassword) } } diff --git a/node/src/main/kotlin/net/corda/node/services/identity/InMemoryIdentityService.kt b/node/src/main/kotlin/net/corda/node/services/identity/InMemoryIdentityService.kt index a1f16b0b7d..5e60a04cfd 100644 --- a/node/src/main/kotlin/net/corda/node/services/identity/InMemoryIdentityService.kt +++ b/node/src/main/kotlin/net/corda/node/services/identity/InMemoryIdentityService.kt @@ -11,6 +11,8 @@ import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.core.utilities.loggerFor import net.corda.core.utilities.trace import org.bouncycastle.asn1.x500.X500Name +import org.bouncycastle.cert.X509CertificateHolder +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter import java.security.InvalidAlgorithmParameterException import java.security.PublicKey import java.security.cert.* @@ -82,8 +84,9 @@ class InMemoryIdentityService(identities: Iterable = emptySet(), override fun pathForAnonymous(anonymousParty: AnonymousParty): CertPath? = partyToPath[anonymousParty] @Throws(CertificateExpiredException::class, CertificateNotYetValidException::class, InvalidAlgorithmParameterException::class) - override fun registerPath(trustedRoot: X509Certificate, anonymousParty: AnonymousParty, path: CertPath) { - val expectedTrustAnchor = TrustAnchor(trustedRoot, null) + override fun registerPath(trustedRoot: X509CertificateHolder, anonymousParty: AnonymousParty, path: CertPath) { + val converter = JcaX509CertificateConverter() + val expectedTrustAnchor = TrustAnchor(converter.getCertificate(trustedRoot), null) require(path.certificates.isNotEmpty()) { "Certificate path must contain at least one certificate" } val target = path.certificates.last() as X509Certificate require(target.publicKey == anonymousParty.owningKey) { "Certificate path must end with anonymous party's public key" } diff --git a/node/src/main/kotlin/net/corda/node/services/keys/E2ETestKeyManagementService.kt b/node/src/main/kotlin/net/corda/node/services/keys/E2ETestKeyManagementService.kt index cb4d6ca321..85d90980bc 100644 --- a/node/src/main/kotlin/net/corda/node/services/keys/E2ETestKeyManagementService.kt +++ b/node/src/main/kotlin/net/corda/node/services/keys/E2ETestKeyManagementService.kt @@ -9,11 +9,12 @@ import net.corda.core.identity.Party import net.corda.core.node.services.IdentityService import net.corda.core.node.services.KeyManagementService import net.corda.core.serialization.SingletonSerializeAsToken +import org.bouncycastle.cert.X509CertificateHolder +import org.bouncycastle.operator.ContentSigner import java.security.KeyPair import java.security.PrivateKey import java.security.PublicKey import java.security.cert.CertPath -import java.security.cert.X509Certificate import java.util.* import javax.annotation.concurrent.ThreadSafe @@ -56,7 +57,7 @@ class E2ETestKeyManagementService(val identityService: IdentityService, return keyPair.public } - override fun freshKeyAndCert(identity: Party, revocationEnabled: Boolean): Pair = freshKeyAndCert(this, identityService, identity, revocationEnabled) + override fun freshKeyAndCert(identity: Party, revocationEnabled: Boolean): Pair = freshKeyAndCert(this, identityService, identity, revocationEnabled) private fun getSigningKeyPair(publicKey: PublicKey): KeyPair { return mutex.locked { diff --git a/node/src/main/kotlin/net/corda/node/services/keys/KMSUtils.kt b/node/src/main/kotlin/net/corda/node/services/keys/KMSUtils.kt index 24d7fd51bc..03f1dae235 100644 --- a/node/src/main/kotlin/net/corda/node/services/keys/KMSUtils.kt +++ b/node/src/main/kotlin/net/corda/node/services/keys/KMSUtils.kt @@ -1,12 +1,17 @@ package net.corda.node.services.keys import net.corda.core.crypto.CertificateType +import net.corda.core.crypto.ContentSignerBuilder import net.corda.core.crypto.Crypto import net.corda.core.crypto.X509Utilities import net.corda.core.identity.AnonymousParty import net.corda.core.identity.Party import net.corda.core.node.services.IdentityService import net.corda.core.node.services.KeyManagementService +import org.bouncycastle.cert.X509CertificateHolder +import org.bouncycastle.operator.ContentSigner +import java.security.KeyPair +import java.security.Security import java.security.cert.CertPath import java.security.cert.X509Certificate @@ -23,7 +28,7 @@ import java.security.cert.X509Certificate fun freshKeyAndCert(keyManagementService: KeyManagementService, identityService: IdentityService, identity: Party, - revocationEnabled: Boolean = false): Pair { + revocationEnabled: Boolean = false): Pair { val ourPublicKey = keyManagementService.freshKey() // FIXME: Use the actual certificate for the identity the flow is presenting themselves as val issuerKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_IDENTITY_SIGNATURE_SCHEME) diff --git a/node/src/main/kotlin/net/corda/node/services/keys/PersistentKeyManagementService.kt b/node/src/main/kotlin/net/corda/node/services/keys/PersistentKeyManagementService.kt index 532e05605b..53233a6002 100644 --- a/node/src/main/kotlin/net/corda/node/services/keys/PersistentKeyManagementService.kt +++ b/node/src/main/kotlin/net/corda/node/services/keys/PersistentKeyManagementService.kt @@ -10,13 +10,14 @@ import net.corda.core.node.services.IdentityService import net.corda.core.node.services.KeyManagementService import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.node.utilities.* +import org.bouncycastle.cert.X509CertificateHolder +import org.bouncycastle.operator.ContentSigner import org.jetbrains.exposed.sql.ResultRow import org.jetbrains.exposed.sql.statements.InsertStatement import java.security.KeyPair import java.security.PrivateKey import java.security.PublicKey import java.security.cert.CertPath -import java.security.cert.X509Certificate /** * A persistent re-implementation of [E2ETestKeyManagementService] to support node re-start. @@ -66,8 +67,7 @@ class PersistentKeyManagementService(val identityService: IdentityService, } return keyPair.public } - - override fun freshKeyAndCert(identity: Party, revocationEnabled: Boolean): Pair = freshKeyAndCert(this, identityService, identity, revocationEnabled) + override fun freshKeyAndCert(identity: Party, revocationEnabled: Boolean): Pair = freshKeyAndCert(this, identityService, identity, revocationEnabled) private fun getSigningKeyPair(publicKey: PublicKey): KeyPair { return mutex.locked { diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingServer.kt b/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingServer.kt index 23c6e1a33a..8d019f95a5 100644 --- a/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingServer.kt +++ b/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingServer.kt @@ -263,10 +263,9 @@ class ArtemisMessagingServer(override val config: NodeConfiguration, val trustStore = KeyStoreUtilities.loadKeyStore(config.trustStoreFile, config.trustStorePassword) val ourCertificate = keyStore.getX509Certificate(CORDA_CLIENT_TLS) - val ourSubjectDN = X500Name(ourCertificate.subjectDN.name) // This is a sanity check and should not fail unless things have been misconfigured - require(ourSubjectDN == config.myLegalName) { - "Legal name does not match with our subject CN: $ourSubjectDN" + require(ourCertificate.subject == config.myLegalName) { + "Legal name does not match with our subject CN: ${ourCertificate.subject}" } val defaultCertPolicies = mapOf( PEER_ROLE to CertificateChainCheckPolicy.RootMustMatch, @@ -510,7 +509,7 @@ private class VerifyingNettyConnector(configuration: MutableMap, "Peer has wrong subject name in the certificate - expected $expectedLegalName but got ${peerCertificate.subject}. This is either a fatal " + "misconfiguration by the remote peer or an SSL man-in-the-middle attack!" } - X509Utilities.validateCertificateChain(X509CertImpl(session.localCertificates.last().encoded), *session.peerCertificates) + X509Utilities.validateCertificateChain(X509CertificateHolder(session.localCertificates.last().encoded), *session.peerCertificates) server.onTcpConnection(peerLegalName) } catch (e: IllegalArgumentException) { connection.close() diff --git a/node/src/main/kotlin/net/corda/node/services/network/NetworkMapService.kt b/node/src/main/kotlin/net/corda/node/services/network/NetworkMapService.kt index 144223d4ca..7c65f3d02c 100644 --- a/node/src/main/kotlin/net/corda/node/services/network/NetworkMapService.kt +++ b/node/src/main/kotlin/net/corda/node/services/network/NetworkMapService.kt @@ -2,7 +2,9 @@ package net.corda.node.services.network import com.google.common.annotations.VisibleForTesting import net.corda.core.ThreadBox -import net.corda.core.crypto.* +import net.corda.core.crypto.DigitalSignature +import net.corda.core.crypto.SignedData +import net.corda.core.crypto.isFulfilledBy import net.corda.core.identity.Party import net.corda.core.messaging.MessageRecipients import net.corda.core.messaging.SingleMessageRecipient diff --git a/node/src/main/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelper.kt b/node/src/main/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelper.kt index 54343b58a3..79a7f8e69f 100644 --- a/node/src/main/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelper.kt +++ b/node/src/main/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelper.kt @@ -6,6 +6,8 @@ import net.corda.core.crypto.X509Utilities.CORDA_CLIENT_CA import net.corda.core.crypto.X509Utilities.CORDA_CLIENT_TLS import net.corda.core.crypto.X509Utilities.CORDA_ROOT_CA import net.corda.node.services.config.NodeConfiguration +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter +import org.bouncycastle.cert.path.CertPath import org.bouncycastle.openssl.jcajce.JcaPEMWriter import org.bouncycastle.util.io.pem.PemObject import java.io.StringWriter @@ -40,7 +42,8 @@ class NetworkRegistrationHelper(val config: NodeConfiguration, val certService: val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) val selfSignCert = X509Utilities.createSelfSignedCACertificate(config.myLegalName, keyPair) // Save to the key store. - caKeyStore.addOrReplaceKey(SELF_SIGNED_PRIVATE_KEY, keyPair.private, privateKeyPassword.toCharArray(), arrayOf(selfSignCert)) + caKeyStore.addOrReplaceKey(SELF_SIGNED_PRIVATE_KEY, keyPair.private, privateKeyPassword.toCharArray(), + CertPath(arrayOf(selfSignCert))) caKeyStore.save(config.nodeKeystore, keystorePassword) } val keyPair = caKeyStore.getKeyPair(SELF_SIGNED_PRIVATE_KEY, privateKeyPassword) @@ -69,11 +72,13 @@ class NetworkRegistrationHelper(val config: NodeConfiguration, val certService: println("Node private key and certificate stored in ${config.nodeKeystore}.") println("Generating SSL certificate for node messaging service.") + val converter = JcaX509CertificateConverter() val sslKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) val caCert = caKeyStore.getX509Certificate(CORDA_CLIENT_CA) val sslCert = X509Utilities.createCertificate(CertificateType.TLS, caCert, keyPair, caCert.subject, sslKey.public) val sslKeyStore = KeyStoreUtilities.loadOrCreateKeyStore(config.sslKeystore, keystorePassword) - sslKeyStore.addOrReplaceKey(CORDA_CLIENT_TLS, sslKey.private, privateKeyPassword.toCharArray(), arrayOf(sslCert, *certificates)) + sslKeyStore.addOrReplaceKey(CORDA_CLIENT_TLS, sslKey.private, privateKeyPassword.toCharArray(), + arrayOf(converter.getCertificate(sslCert), *certificates)) sslKeyStore.save(config.sslKeystore, config.keyStorePassword) println("SSL private key and certificate stored in ${config.sslKeystore}.") // All done, clean up temp files. diff --git a/node/src/test/kotlin/net/corda/node/utilities/registration/NetworkisRegistrationHelperTest.kt b/node/src/test/kotlin/net/corda/node/utilities/registration/NetworkisRegistrationHelperTest.kt index c1d47292f8..0ada571887 100644 --- a/node/src/test/kotlin/net/corda/node/utilities/registration/NetworkisRegistrationHelperTest.kt +++ b/node/src/test/kotlin/net/corda/node/utilities/registration/NetworkisRegistrationHelperTest.kt @@ -5,10 +5,12 @@ import com.nhaarman.mockito_kotlin.eq import com.nhaarman.mockito_kotlin.mock import net.corda.core.crypto.* import net.corda.core.exists +import net.corda.core.mapToArray import net.corda.core.utilities.ALICE import net.corda.testing.TestNodeConfiguration import net.corda.testing.getTestX509Name import org.bouncycastle.cert.X509CertificateHolder +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder @@ -29,8 +31,9 @@ class NetworkRegistrationHelperTest { "CORDA_INTERMEDIATE_CA", "CORDA_ROOT_CA") .map { getTestX509Name(it) } + val converter = JcaX509CertificateConverter() val certs = identities.map { X509Utilities.createSelfSignedCACertificate(it, Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)) } - .toTypedArray() + .mapToArray(converter::getCertificate) val certService: NetworkRegistrationService = mock { on { submitRequest(any()) }.then { id } diff --git a/test-utils/src/main/kotlin/net/corda/testing/node/MockServices.kt b/test-utils/src/main/kotlin/net/corda/testing/node/MockServices.kt index c50f00a420..c09305def7 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/node/MockServices.kt +++ b/test-utils/src/main/kotlin/net/corda/testing/node/MockServices.kt @@ -21,6 +21,7 @@ import net.corda.node.services.vault.NodeVaultService import net.corda.testing.MEGA_CORP import net.corda.testing.MINI_CORP import net.corda.testing.MOCK_VERSION_INFO +import org.bouncycastle.cert.X509CertificateHolder import rx.Observable import rx.subjects.PublishSubject import java.io.ByteArrayInputStream @@ -32,7 +33,6 @@ import java.security.KeyPair import java.security.PrivateKey import java.security.PublicKey import java.security.cert.CertPath -import java.security.cert.X509Certificate import java.time.Clock import java.util.* import java.util.jar.JarInputStream @@ -91,7 +91,7 @@ class MockKeyManagementService(val identityService: IdentityService, return k.public } - override fun freshKeyAndCert(identity: Party, revocationEnabled: Boolean): Pair = freshKeyAndCert(this, identityService, identity, revocationEnabled) + override fun freshKeyAndCert(identity: Party, revocationEnabled: Boolean): Pair = freshKeyAndCert(this, identityService, identity, revocationEnabled) private fun getSigningKeyPair(publicKey: PublicKey): KeyPair { val pk = publicKey.keys.first { keyStore.containsKey(it) } diff --git a/test-utils/src/main/kotlin/net/corda/testing/node/SimpleNode.kt b/test-utils/src/main/kotlin/net/corda/testing/node/SimpleNode.kt index ea70e70a25..0fb681071c 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/node/SimpleNode.kt +++ b/test-utils/src/main/kotlin/net/corda/testing/node/SimpleNode.kt @@ -3,6 +3,7 @@ package net.corda.testing.node import com.codahale.metrics.MetricRegistry import com.google.common.net.HostAndPort import com.google.common.util.concurrent.SettableFuture +import net.corda.core.crypto.CertificateAndKeyPair import net.corda.core.crypto.commonName import net.corda.core.crypto.generateKeyPair import net.corda.core.messaging.RPCOps @@ -30,7 +31,9 @@ import kotlin.concurrent.thread * This is a bare-bones node which can only send and receive messages. It doesn't register with a network map service or * any other such task that would make it functional in a network and thus left to the user to do so manually. */ -class SimpleNode(val config: NodeConfiguration, val address: HostAndPort = freeLocalHostAndPort(), rpcAddress: HostAndPort = freeLocalHostAndPort()) : AutoCloseable { +class SimpleNode(val config: NodeConfiguration, val address: HostAndPort = freeLocalHostAndPort(), + rpcAddress: HostAndPort = freeLocalHostAndPort(), + networkRoot: CertificateAndKeyPair? = null) : AutoCloseable { private val databaseWithCloseable: Pair = configureDatabase(config.dataSourceProperties) val database: Database get() = databaseWithCloseable.second From b6dbd6bbb523847d27b96501505322d36e9e2348 Mon Sep 17 00:00:00 2001 From: Ross Nicoll Date: Tue, 30 May 2017 16:10:57 +0100 Subject: [PATCH 014/126] Add docs --- core/src/main/kotlin/net/corda/core/node/services/Services.kt | 1 - docs/source/changelog.rst | 4 ++++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/core/src/main/kotlin/net/corda/core/node/services/Services.kt b/core/src/main/kotlin/net/corda/core/node/services/Services.kt index a673001f05..97cc2bce84 100644 --- a/core/src/main/kotlin/net/corda/core/node/services/Services.kt +++ b/core/src/main/kotlin/net/corda/core/node/services/Services.kt @@ -20,7 +20,6 @@ import net.corda.core.transactions.LedgerTransaction import net.corda.core.transactions.TransactionBuilder import net.corda.core.transactions.WireTransaction import org.bouncycastle.cert.X509CertificateHolder -import org.bouncycastle.operator.ContentSigner import rx.Observable import java.io.InputStream import java.security.PublicKey diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index 7d7783ebc0..e210cc7428 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -50,6 +50,10 @@ UNRELEASED * Names of parties are now stored as a ``X500Name`` rather than a ``String``, to correctly enforce basic structure of the name. As a result all node legal names must now be structured as X.500 distinguished names. + * The Bouncy Castle library ``X509CertificateHolder`` class is now used in place of ``X509Certificate`` in order to + have a consistent class used internally. Conversions to/from ``X509Certificate`` are done as required, but should + be avoided where possible. + * There are major changes to transaction signing in flows: * You should use the new ``CollectSignaturesFlow`` and corresponding ``SignTransactionFlow`` which handle most From 0e1e4042dc89c2984e3af3e2a8bcf9050386eaf9 Mon Sep 17 00:00:00 2001 From: Ross Nicoll Date: Wed, 31 May 2017 09:45:40 +0100 Subject: [PATCH 015/126] Add PartyAndCertificate class Add PartyAndCertificate class for pairing proof of a party's identity with the party. --- .../net/corda/core/identity/AbstractParty.kt | 9 ++++ .../core/identity/PartyAndCertificate.kt | 16 +++++++ .../net/corda/core/utilities/TestConstants.kt | 36 ++++++++++---- .../corda/node/utilities/DatabaseSupport.kt | 48 ++++++++++++++++++- .../network/InMemoryIdentityServiceTests.kt | 4 +- .../corda/testing/node/MockNetworkMapCache.kt | 8 ++-- 6 files changed, 104 insertions(+), 17 deletions(-) create mode 100644 core/src/main/kotlin/net/corda/core/identity/PartyAndCertificate.kt diff --git a/core/src/main/kotlin/net/corda/core/identity/AbstractParty.kt b/core/src/main/kotlin/net/corda/core/identity/AbstractParty.kt index 6b285c3698..5c81e0c4b2 100644 --- a/core/src/main/kotlin/net/corda/core/identity/AbstractParty.kt +++ b/core/src/main/kotlin/net/corda/core/identity/AbstractParty.kt @@ -18,6 +18,15 @@ abstract class AbstractParty(val owningKey: PublicKey) { override fun hashCode(): Int = owningKey.hashCode() abstract fun nameOrNull(): X500Name? + /** + * Build a reference to something being stored or issued by a party e.g. in a vault or (more likely) on their normal + * ledger. + */ abstract fun ref(bytes: OpaqueBytes): PartyAndReference + + /** + * Build a reference to something being stored or issued by a party e.g. in a vault or (more likely) on their normal + * ledger. + */ fun ref(vararg bytes: Byte) = ref(OpaqueBytes.of(*bytes)) } \ No newline at end of file diff --git a/core/src/main/kotlin/net/corda/core/identity/PartyAndCertificate.kt b/core/src/main/kotlin/net/corda/core/identity/PartyAndCertificate.kt new file mode 100644 index 0000000000..b758dbfd0d --- /dev/null +++ b/core/src/main/kotlin/net/corda/core/identity/PartyAndCertificate.kt @@ -0,0 +1,16 @@ +package net.corda.core.identity + +import net.corda.core.contracts.PartyAndReference +import net.corda.core.serialization.OpaqueBytes +import org.bouncycastle.asn1.x500.X500Name +import org.bouncycastle.cert.X509CertificateHolder +import java.security.PublicKey +import java.security.cert.CertPath +import java.security.cert.X509Certificate + +/** + * A full party plus the X.509 certificate and path linking the party back to a trust root. + */ +class PartyAndCertificate(name: X500Name, owningKey: PublicKey, + val certificate: X509CertificateHolder, + val certPath: CertPath) : Party(name, owningKey) \ No newline at end of file diff --git a/core/src/main/kotlin/net/corda/core/utilities/TestConstants.kt b/core/src/main/kotlin/net/corda/core/utilities/TestConstants.kt index 1084808a4a..ad71163702 100644 --- a/core/src/main/kotlin/net/corda/core/utilities/TestConstants.kt +++ b/core/src/main/kotlin/net/corda/core/utilities/TestConstants.kt @@ -3,7 +3,7 @@ package net.corda.core.utilities import net.corda.core.crypto.* -import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import org.bouncycastle.asn1.x500.X500Name import java.math.BigInteger import java.security.KeyPair @@ -21,36 +21,52 @@ val DUMMY_KEY_2: KeyPair by lazy { generateKeyPair() } val DUMMY_NOTARY_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(20)) } /** Dummy notary identity for tests and simulations */ -val DUMMY_NOTARY: Party get() = Party(X500Name("CN=Notary Service,O=R3,OU=corda,L=Zurich,C=CH"), DUMMY_NOTARY_KEY.public) +val DUMMY_NOTARY: PartyAndCertificate get() = getTestPartyAndCertificate(X500Name("CN=Notary Service,O=R3,OU=corda,L=Zurich,C=CH"), DUMMY_NOTARY_KEY.public) val DUMMY_MAP_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(30)) } /** Dummy network map service identity for tests and simulations */ -val DUMMY_MAP: Party get() = Party(X500Name("CN=Network Map Service,O=R3,OU=corda,L=Amsterdam,C=NL"), DUMMY_MAP_KEY.public) +val DUMMY_MAP: PartyAndCertificate get() = getTestPartyAndCertificate(X500Name("CN=Network Map Service,O=R3,OU=corda,L=Amsterdam,C=NL"), DUMMY_MAP_KEY.public) val DUMMY_BANK_A_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(40)) } /** Dummy bank identity for tests and simulations */ -val DUMMY_BANK_A: Party get() = Party(X500Name("CN=Bank A,O=Bank A,L=London,C=UK"), DUMMY_BANK_A_KEY.public) +val DUMMY_BANK_A: PartyAndCertificate get() = getTestPartyAndCertificate(X500Name("CN=Bank A,O=Bank A,L=London,C=UK"), DUMMY_BANK_A_KEY.public) val DUMMY_BANK_B_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(50)) } /** Dummy bank identity for tests and simulations */ -val DUMMY_BANK_B: Party get() = Party(X500Name("CN=Bank B,O=Bank B,L=New York,C=US"), DUMMY_BANK_B_KEY.public) +val DUMMY_BANK_B: PartyAndCertificate get() = getTestPartyAndCertificate(X500Name("CN=Bank B,O=Bank B,L=New York,C=US"), DUMMY_BANK_B_KEY.public) val DUMMY_BANK_C_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(60)) } /** Dummy bank identity for tests and simulations */ -val DUMMY_BANK_C: Party get() = Party(X500Name("CN=Bank C,O=Bank C,L=Tokyo,C=JP"), DUMMY_BANK_C_KEY.public) +val DUMMY_BANK_C: PartyAndCertificate get() = getTestPartyAndCertificate(X500Name("CN=Bank C,O=Bank C,L=Tokyo,C=JP"), DUMMY_BANK_C_KEY.public) val ALICE_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(70)) } /** Dummy individual identity for tests and simulations */ -val ALICE: Party get() = Party(X500Name("CN=Alice Corp,O=Alice Corp,L=London,C=UK"), ALICE_KEY.public) +val ALICE: PartyAndCertificate get() = getTestPartyAndCertificate(X500Name("CN=Alice Corp,O=Alice Corp,L=London,C=UK"), ALICE_KEY.public) val BOB_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(80)) } /** Dummy individual identity for tests and simulations */ -val BOB: Party get() = Party(X500Name("CN=Bob Plc,O=Bob Plc,L=London,C=UK"), BOB_KEY.public) +val BOB: PartyAndCertificate get() = getTestPartyAndCertificate(X500Name("CN=Bob Plc,O=Bob Plc,L=London,C=UK"), BOB_KEY.public) val CHARLIE_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(90)) } /** Dummy individual identity for tests and simulations */ -val CHARLIE: Party get() = Party(X500Name("CN=Charlie Ltd,O=Charlie Ltd,L=London,C=UK"), CHARLIE_KEY.public) +val CHARLIE: PartyAndCertificate get() = getTestPartyAndCertificate(X500Name("CN=Charlie Ltd,O=Charlie Ltd,L=London,C=UK"), CHARLIE_KEY.public) val DUMMY_REGULATOR_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(100)) } /** Dummy regulator for tests and simulations */ -val DUMMY_REGULATOR: Party get() = Party(X500Name("CN=Regulator A,OU=Corda,O=AMF,L=Paris,C=FR"), DUMMY_REGULATOR_KEY.public) +val DUMMY_REGULATOR: PartyAndCertificate get() = getTestPartyAndCertificate(X500Name("CN=Regulator A,OU=Corda,O=AMF,L=Paris,C=FR"), DUMMY_REGULATOR_KEY.public) + +val DUMMY_CA_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(110)) } +val DUMMY_CA: CertificateAndKeyPair by lazy { + // TODO: Should be identity scheme + val cert = X509Utilities.createSelfSignedCACertificate(X500Name("CN=Dummy CA,OU=Corda,O=R3 Ltd,L=London,C=UK"), DUMMY_CA_KEY) + CertificateAndKeyPair(cert, DUMMY_CA_KEY) +} + +/** + * Build a test party with a nonsense certificate authority for testing purposes. + */ +fun getTestPartyAndCertificate(name: X500Name, publicKey: PublicKey): PartyAndCertificate { + val cert = X509Utilities.createCertificate(CertificateType.IDENTITY, DUMMY_CA.certificate, DUMMY_CA.keyPair, name, publicKey) + val certPath = X509Utilities.createCertificatePath(DUMMY_CA.certificate, cert, revocationEnabled = false) + return PartyAndCertificate(name, publicKey, cert, certPath) +} \ No newline at end of file diff --git a/node/src/main/kotlin/net/corda/node/utilities/DatabaseSupport.kt b/node/src/main/kotlin/net/corda/node/utilities/DatabaseSupport.kt index eed2db06f7..4dd0222894 100644 --- a/node/src/main/kotlin/net/corda/node/utilities/DatabaseSupport.kt +++ b/node/src/main/kotlin/net/corda/node/utilities/DatabaseSupport.kt @@ -3,11 +3,12 @@ package net.corda.node.utilities import co.paralleluniverse.strands.Strand import com.zaxxer.hikari.HikariConfig import com.zaxxer.hikari.HikariDataSource -import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.SecureHash import net.corda.core.crypto.parsePublicKeyBase58 import net.corda.core.crypto.toBase58String import net.corda.node.utilities.StrandLocalTransactionManager.Boundary +import org.bouncycastle.cert.X509CertificateHolder +import org.h2.jdbc.JdbcBlob import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.transactions.TransactionInterface import org.jetbrains.exposed.sql.transactions.TransactionManager @@ -16,8 +17,12 @@ import rx.Subscriber import rx.subjects.PublishSubject import rx.subjects.Subject import rx.subjects.UnicastSubject +import java.io.ByteArrayInputStream import java.io.Closeable import java.security.PublicKey +import java.security.cert.CertPath +import java.security.cert.CertificateFactory +import java.security.cert.X509Certificate import java.sql.Connection import java.time.Instant import java.time.LocalDate @@ -264,15 +269,25 @@ fun rx.Observable.wrapWithDatabaseTransaction(db: Database? = null) // Composite columns for use with below Exposed helpers. data class PartyColumns(val name: Column, val owningKey: Column) +data class PartyAndCertificateColumns(val name: Column, val owningKey: Column, + val certificate: Column, val certPath: Column) data class StateRefColumns(val txId: Column, val index: Column) data class TxnNoteColumns(val txId: Column, val note: Column) /** * [Table] column helpers for use with Exposed, as per [varchar] etc. */ +fun Table.certificate(name: String) = this.registerColumn(name, X509CertificateColumnType) +fun Table.certificatePath(name: String) = this.registerColumn(name, CertPathColumnType) fun Table.publicKey(name: String) = this.registerColumn(name, PublicKeyColumnType) fun Table.secureHash(name: String) = this.registerColumn(name, SecureHashColumnType) -fun Table.party(nameColumnName: String, keyColumnName: String) = PartyColumns(this.varchar(nameColumnName, length = 255), this.publicKey(keyColumnName)) +fun Table.party(nameColumnName: String, + keyColumnName: String) = PartyColumns(this.varchar(nameColumnName, length = 255), this.publicKey(keyColumnName)) +fun Table.partyAndCertificate(nameColumnName: String, + keyColumnName: String, + certificateColumnName: String, + pathColumnName: String) = PartyAndCertificateColumns(this.varchar(nameColumnName, length = 255), this.publicKey(keyColumnName), + this.certificate(certificateColumnName), this.certificatePath(pathColumnName)) fun Table.uuidString(name: String) = this.registerColumn(name, UUIDStringColumnType) fun Table.localDate(name: String) = this.registerColumn(name, LocalDateColumnType) fun Table.localDateTime(name: String) = this.registerColumn(name, LocalDateTimeColumnType) @@ -280,6 +295,35 @@ fun Table.instant(name: String) = this.registerColumn(name, InstantColu fun Table.stateRef(txIdColumnName: String, indexColumnName: String) = StateRefColumns(this.secureHash(txIdColumnName), this.integer(indexColumnName)) fun Table.txnNote(txIdColumnName: String, txnNoteColumnName: String) = TxnNoteColumns(this.secureHash(txIdColumnName), this.text(txnNoteColumnName)) +/** + * [ColumnType] for marshalling to/from database on behalf of [X509CertificateHolder]. + */ +object X509CertificateColumnType : ColumnType() { + override fun sqlType(): String = "BLOB" + + override fun valueFromDB(value: Any): Any { + val blob = value as JdbcBlob + return X509CertificateHolder(blob.getBytes(0, blob.length().toInt())) + } + + override fun notNullValueToDB(value: Any): Any = (value as X509CertificateHolder).encoded +} + +/** + * [ColumnType] for marshalling to/from database on behalf of [CertPath]. + */ +object CertPathColumnType : ColumnType() { + private val factory = CertificateFactory.getInstance("X.509") + override fun sqlType(): String = "BLOB" + + override fun valueFromDB(value: Any): Any { + val blob = value as JdbcBlob + return factory.generateCertPath(ByteArrayInputStream(blob.getBytes(0, blob.length().toInt()))) + } + + override fun notNullValueToDB(value: Any): Any = (value as CertPath).encoded +} + /** * [ColumnType] for marshalling to/from database on behalf of [PublicKey]. */ diff --git a/node/src/test/kotlin/net/corda/node/services/network/InMemoryIdentityServiceTests.kt b/node/src/test/kotlin/net/corda/node/services/network/InMemoryIdentityServiceTests.kt index 03672b3833..0bd8c3cd56 100644 --- a/node/src/test/kotlin/net/corda/node/services/network/InMemoryIdentityServiceTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/network/InMemoryIdentityServiceTests.kt @@ -24,13 +24,13 @@ class InMemoryIdentityServiceTests { val service = InMemoryIdentityService() assertNull(service.getAllIdentities().firstOrNull()) service.registerIdentity(ALICE) - var expected = setOf(ALICE) + var expected = setOf(ALICE) var actual = service.getAllIdentities().toHashSet() assertEquals(expected, actual) // Add a second party and check we get both back service.registerIdentity(BOB) - expected = setOf(ALICE, BOB) + expected = setOf(ALICE, BOB) actual = service.getAllIdentities().toHashSet() assertEquals(expected, actual) } diff --git a/test-utils/src/main/kotlin/net/corda/testing/node/MockNetworkMapCache.kt b/test-utils/src/main/kotlin/net/corda/testing/node/MockNetworkMapCache.kt index 76790b851b..47bd3bf6e2 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/node/MockNetworkMapCache.kt +++ b/test-utils/src/main/kotlin/net/corda/testing/node/MockNetworkMapCache.kt @@ -1,24 +1,26 @@ package net.corda.testing.node import co.paralleluniverse.common.util.VisibleForTesting -import net.corda.core.crypto.DummyPublicKey +import net.corda.core.crypto.entropyToKeyPair import net.corda.core.identity.Party import net.corda.core.messaging.SingleMessageRecipient import net.corda.core.node.NodeInfo import net.corda.core.node.services.NetworkMapCache +import net.corda.core.utilities.getTestPartyAndCertificate import net.corda.node.services.network.InMemoryNetworkMapCache import net.corda.testing.MOCK_VERSION_INFO import net.corda.testing.getTestX509Name import rx.Observable import rx.subjects.PublishSubject +import java.math.BigInteger /** * Network map cache with no backing map service. */ class MockNetworkMapCache : InMemoryNetworkMapCache() { private companion object { - val BANK_C = Party(getTestX509Name("Bank C"), DummyPublicKey("Bank C")) - val BANK_D = Party(getTestX509Name("Bank D"), DummyPublicKey("Bank D")) + val BANK_C = getTestPartyAndCertificate(getTestX509Name("Bank C"), entropyToKeyPair(BigInteger.valueOf(1000)).public) + val BANK_D = getTestPartyAndCertificate(getTestX509Name("Bank D"), entropyToKeyPair(BigInteger.valueOf(2000)).public) } override val changed: Observable = PublishSubject.create() From e117ab77032056add2444e8fb9dedb94eec5dd50 Mon Sep 17 00:00:00 2001 From: Chris Rankin Date: Wed, 31 May 2017 10:31:10 +0100 Subject: [PATCH 016/126] Allow DemoBench to install Explorer's CorDapps multiple times. (#761) --- .../main/kotlin/net/corda/demobench/explorer/Explorer.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/explorer/Explorer.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/explorer/Explorer.kt index 8d4318e47f..52f76905be 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/explorer/Explorer.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/explorer/Explorer.kt @@ -11,6 +11,7 @@ import net.corda.demobench.readErrorLines import tornadofx.* import java.io.IOException import java.nio.file.Files +import java.nio.file.StandardCopyOption.* import java.util.concurrent.Executors class Explorer internal constructor(private val explorerController: ExplorerController) : AutoCloseable { @@ -89,13 +90,13 @@ class Explorer internal constructor(private val explorerController: ExplorerCont Files.createSymbolicLink(destPath, path) } catch(e: UnsupportedOperationException) { // OS doesn't support symbolic links? - Files.copy(path, destPath) - } catch(e: FileAlreadyExistsException) { + Files.copy(path, destPath, REPLACE_EXISTING) + } catch (e: java.nio.file.FileAlreadyExistsException) { // OK, don't care ... } catch (e: IOException) { // Windows 10 might not allow this user to create a symlink log.warn("Failed to create symlink '{}' for '{}': {}", destPath, path, e.message) - Files.copy(path, destPath) + Files.copy(path, destPath, REPLACE_EXISTING) } } } From 329e5ff17ba369d68a011cb4b9682130b2546ed1 Mon Sep 17 00:00:00 2001 From: Shams Asari Date: Fri, 19 May 2017 16:14:48 +0100 Subject: [PATCH 017/126] Introducing InitiatedBy annotation to be used on initiated flows to simplify flow registration. This removes the need to do manual registration using the PluginServiceHub. As a result CordaPluginRegistry.servicePlugins is no longer needed. For oracles and services there is a CorDappService annotation. I've also fixed the InitiatingFlow annotation such that client flows can be customised (sub-typed) without it breaking the flow sessions. --- core/src/main/kotlin/net/corda/core/Utils.kt | 6 + .../net/corda/core/flows/InitiatedBy.kt | 16 + .../net/corda/core/flows/InitiatingFlow.kt | 8 +- .../net/corda/core/flows/StartableByRPC.kt | 2 - .../kotlin/net/corda/core/flows/TxKeyFlow.kt | 36 +-- .../corda/core/node/CordaPluginRegistry.kt | 3 + .../net/corda/core/node/PluginServiceHub.kt | 21 +- .../kotlin/net/corda/core/node/ServiceHub.kt | 8 + .../corda/core/node/services/CordaService.kt | 20 ++ .../corda/core/utilities/ProcessUtilities.kt | 8 +- .../net/corda/core/flows/FlowsInJavaTest.java | 24 +- .../core/flows/CollectSignaturesFlowTests.kt | 26 +- .../net/corda/core/flows/TxKeyFlowTests.kt | 2 +- .../AttachmentSerializationTest.kt | 8 +- docs/source/changelog.rst | 115 ++++--- docs/source/corda-plugins.rst | 35 +-- docs/source/creating-a-cordapp.rst | 27 +- .../corda/docs/FxTransactionBuildTutorial.kt | 10 +- .../docs/WorkflowTransactionBuildTutorial.kt | 22 +- .../docs/FxTransactionBuildTutorialTest.kt | 7 +- .../WorkflowTransactionBuildTutorialTest.kt | 8 +- docs/source/flow-state-machines.rst | 54 ++-- docs/source/oracles.rst | 42 ++- docs/source/release-notes.rst | 8 +- .../main/kotlin/net/corda/flows/IssuerFlow.kt | 13 +- .../kotlin/net/corda/flows/IssuerFlowTest.kt | 17 +- node/build.gradle | 10 +- .../net/corda/node/CordappScanningTest.kt | 82 +++++ .../services/messaging/MQSecurityTest.kt | 4 +- .../kotlin/net/corda/node/driver/Driver.kt | 15 +- .../net/corda/node/internal/AbstractNode.kt | 286 ++++++++++++------ .../node/internal/InitiatedFlowFactory.kt | 27 ++ .../node/services/api/ServiceHubInternal.kt | 7 +- .../statemachine/FlowStateMachineImpl.kt | 36 ++- .../services/statemachine/SessionMessage.kt | 2 +- .../statemachine/StateMachineManager.kt | 39 +-- .../net/corda/node/internal/NodeTest.kt | 20 -- .../node/messaging/TwoPartyTradeFlowTests.kt | 75 +++-- .../node/services/MockServiceHubInternal.kt | 10 +- .../events/NodeSchedulerServiceTest.kt | 4 +- .../persistence/DataVendingServiceTests.kt | 11 +- .../statemachine/FlowFrameworkTests.kt | 101 ++++--- .../corda/bank/plugin/BankOfCordaPlugin.kt | 3 - .../kotlin/net/corda/irs/IRSDemoTest.kt | 14 +- .../net/corda/irs/api/NodeInterestRates.kt | 121 +++----- .../net/corda/irs/flows/AutoOfferFlow.kt | 21 +- .../kotlin/net/corda/irs/flows/FixingFlow.kt | 14 +- .../corda/irs/flows/UpdateBusinessDayFlow.kt | 15 +- .../kotlin/net/corda/irs/plugin/IRSPlugin.kt | 2 - .../net/corda/irs/simulation/IRSSimulation.kt | 23 +- .../net/corda/irs/simulation/Simulation.kt | 4 +- .../net.corda.core.node.CordaPluginRegistry | 3 - .../irs/testing/NodeInterestRatesTest.kt | 10 +- .../net/corda/vega/SimmValuationTest.kt | 7 +- .../net/corda/vega/flows/IRSTradeFlow.kt | 9 +- .../kotlin/net/corda/vega/flows/SimmFlow.kt | 11 +- .../net/corda/vega/services/SimmService.kt | 3 - .../net/corda/traderdemo/TraderDemoTest.kt | 11 +- .../net/corda/traderdemo/flow/BuyerFlow.kt | 33 +- .../traderdemo/plugin/TraderDemoPlugin.kt | 10 - .../net.corda.core.node.CordaPluginRegistry | 2 - .../kotlin/net/corda/testing/CoreTestUtils.kt | 25 +- .../kotlin/net/corda/testing/node/MockNode.kt | 14 - .../net/corda/testing/node/MockServices.kt | 10 +- .../corda/explorer/plugin/ExplorerPlugin.kt | 10 - .../net.corda.core.node.CordaPluginRegistry | 2 - 66 files changed, 892 insertions(+), 760 deletions(-) create mode 100644 core/src/main/kotlin/net/corda/core/flows/InitiatedBy.kt create mode 100644 core/src/main/kotlin/net/corda/core/node/services/CordaService.kt create mode 100644 node/src/integration-test/kotlin/net/corda/node/CordappScanningTest.kt create mode 100644 node/src/main/kotlin/net/corda/node/internal/InitiatedFlowFactory.kt delete mode 100644 node/src/test/kotlin/net/corda/node/internal/NodeTest.kt delete mode 100644 samples/trader-demo/src/main/kotlin/net/corda/traderdemo/plugin/TraderDemoPlugin.kt delete mode 100644 samples/trader-demo/src/main/resources/META-INF/services/net.corda.core.node.CordaPluginRegistry delete mode 100644 tools/explorer/src/main/kotlin/net/corda/explorer/plugin/ExplorerPlugin.kt delete mode 100644 tools/explorer/src/main/resources/META-INF/services/net.corda.core.node.CordaPluginRegistry diff --git a/core/src/main/kotlin/net/corda/core/Utils.kt b/core/src/main/kotlin/net/corda/core/Utils.kt index 0e92a0614c..7922150905 100644 --- a/core/src/main/kotlin/net/corda/core/Utils.kt +++ b/core/src/main/kotlin/net/corda/core/Utils.kt @@ -147,6 +147,12 @@ operator fun String.div(other: String) = Paths.get(this) / other fun Path.createDirectory(vararg attrs: FileAttribute<*>): Path = Files.createDirectory(this, *attrs) fun Path.createDirectories(vararg attrs: FileAttribute<*>): Path = Files.createDirectories(this, *attrs) fun Path.exists(vararg options: LinkOption): Boolean = Files.exists(this, *options) +fun Path.copyToDirectory(targetDir: Path, vararg options: CopyOption): Path { + require(targetDir.isDirectory()) { "$targetDir is not a directory" } + val targetFile = targetDir.resolve(fileName) + Files.copy(this, targetFile, *options) + return targetFile +} fun Path.moveTo(target: Path, vararg options: CopyOption): Path = Files.move(this, target, *options) fun Path.isRegularFile(vararg options: LinkOption): Boolean = Files.isRegularFile(this, *options) fun Path.isDirectory(vararg options: LinkOption): Boolean = Files.isDirectory(this, *options) diff --git a/core/src/main/kotlin/net/corda/core/flows/InitiatedBy.kt b/core/src/main/kotlin/net/corda/core/flows/InitiatedBy.kt new file mode 100644 index 0000000000..25f2433ea0 --- /dev/null +++ b/core/src/main/kotlin/net/corda/core/flows/InitiatedBy.kt @@ -0,0 +1,16 @@ +package net.corda.core.flows + +import kotlin.annotation.AnnotationTarget.CLASS +import kotlin.reflect.KClass + +/** + * This annotation is required by any [FlowLogic] that is designed to be initiated by a counterparty flow. The flow that + * does the initiating is specified by the [value] property and itself must be annotated with [InitiatingFlow]. + * + * The node on startup scans for [FlowLogic]s which are annotated with this and automatically registers the initiating + * to initiated flow mapping. + * + * @see InitiatingFlow + */ +@Target(CLASS) +annotation class InitiatedBy(val value: KClass>) \ No newline at end of file diff --git a/core/src/main/kotlin/net/corda/core/flows/InitiatingFlow.kt b/core/src/main/kotlin/net/corda/core/flows/InitiatingFlow.kt index 75ead4b8e1..e27cd5a23b 100644 --- a/core/src/main/kotlin/net/corda/core/flows/InitiatingFlow.kt +++ b/core/src/main/kotlin/net/corda/core/flows/InitiatingFlow.kt @@ -5,8 +5,7 @@ import kotlin.annotation.AnnotationTarget.CLASS /** * This annotation is required by any [FlowLogic] which has been designated to initiate communication with a counterparty - * and request they start their side of the flow communication. To ensure that this is correctly applied - * [net.corda.core.node.PluginServiceHub.registerServiceFlow] checks the initiating flow class has this annotation. + * and request they start their side of the flow communication. * * There is also an optional [version] property, which defaults to 1, to specify the version of the flow protocol. This * integer value should be incremented whenever there is a release of this flow which has changes that are not backwards @@ -19,6 +18,11 @@ import kotlin.annotation.AnnotationTarget.CLASS * * The flow version number is similar in concept to Corda's platform version but they are not the same. A flow's version * number can change independently of the platform version. + * + * If you are customising an existing initiating flow by sub-classing it then there's no need to specify this annotation + * again. In fact doing so is an error and checks are made to make sure this doesn't occur. + * + * @see InitiatedBy */ // TODO Add support for multiple versions once CorDapps are loaded in separate class loaders @Target(CLASS) diff --git a/core/src/main/kotlin/net/corda/core/flows/StartableByRPC.kt b/core/src/main/kotlin/net/corda/core/flows/StartableByRPC.kt index 6eafd3d699..c1724d615d 100644 --- a/core/src/main/kotlin/net/corda/core/flows/StartableByRPC.kt +++ b/core/src/main/kotlin/net/corda/core/flows/StartableByRPC.kt @@ -1,6 +1,5 @@ package net.corda.core.flows -import java.lang.annotation.Inherited import kotlin.annotation.AnnotationTarget.CLASS /** @@ -9,7 +8,6 @@ import kotlin.annotation.AnnotationTarget.CLASS * flow will not be allowed to start and an exception will be thrown. */ @Target(CLASS) -@Inherited @MustBeDocumented // TODO Consider a different name, something along the lines of SchedulableFlow annotation class StartableByRPC \ No newline at end of file diff --git a/core/src/main/kotlin/net/corda/core/flows/TxKeyFlow.kt b/core/src/main/kotlin/net/corda/core/flows/TxKeyFlow.kt index 05a48c6895..417ea63d2e 100644 --- a/core/src/main/kotlin/net/corda/core/flows/TxKeyFlow.kt +++ b/core/src/main/kotlin/net/corda/core/flows/TxKeyFlow.kt @@ -15,7 +15,7 @@ import java.security.cert.X509Certificate * This is intended for use as a subflow of another flow. */ object TxKeyFlow { - abstract class AbstractIdentityFlow(val otherSide: Party, val revocationEnabled: Boolean): FlowLogic>() { + abstract class AbstractIdentityFlow(val otherSide: Party): FlowLogic() { fun validateIdentity(untrustedIdentity: Pair): AnonymousIdentity { val (wellKnownCert, certPath) = untrustedIdentity val theirCert = certPath.certificates.last() @@ -26,20 +26,21 @@ object TxKeyFlow { val anonymousParty = AnonymousParty(theirCert.publicKey) serviceHub.identityService.registerPath(wellKnownCert, anonymousParty, certPath) AnonymousIdentity(certPath, X509CertificateHolder(theirCert.encoded), anonymousParty) - } else - throw IllegalStateException("Expected certificate subject to be ${otherSide.name} but found ${certName}") - } else + } else { + throw IllegalStateException("Expected certificate subject to be ${otherSide.name} but found $certName") + } + } else { throw IllegalStateException("Expected an X.509 certificate but received ${theirCert.javaClass.name}") + } } } @StartableByRPC @InitiatingFlow class Requester(otherSide: Party, - revocationEnabled: Boolean, - override val progressTracker: ProgressTracker) : AbstractIdentityFlow(otherSide, revocationEnabled) { - constructor(otherSide: Party, - revocationEnabled: Boolean) : this(otherSide, revocationEnabled, tracker()) + val revocationEnabled: Boolean, + override val progressTracker: ProgressTracker) : AbstractIdentityFlow>(otherSide) { + constructor(otherSide: Party, revocationEnabled: Boolean) : this(otherSide, revocationEnabled, tracker()) companion object { object AWAITING_KEY : ProgressTracker.Step("Awaiting key") @@ -62,26 +63,21 @@ object TxKeyFlow { * Flow which waits for a key request from a counterparty, generates a new key and then returns it to the * counterparty and as the result from the flow. */ - class Provider(otherSide: Party, - revocationEnabled: Boolean, - override val progressTracker: ProgressTracker) : AbstractIdentityFlow(otherSide,revocationEnabled) { - constructor(otherSide: Party, - revocationEnabled: Boolean = false) : this(otherSide, revocationEnabled, tracker()) - + @InitiatedBy(Requester::class) + class Provider(otherSide: Party) : AbstractIdentityFlow(otherSide) { companion object { object SENDING_KEY : ProgressTracker.Step("Sending key") - - fun tracker() = ProgressTracker(SENDING_KEY) } + override val progressTracker: ProgressTracker = ProgressTracker(SENDING_KEY) + @Suspendable - override fun call(): Map { + override fun call() { + val revocationEnabled = false progressTracker.currentStep = SENDING_KEY val myIdentityFragment = serviceHub.keyManagementService.freshKeyAndCert(serviceHub.myInfo.legalIdentity, revocationEnabled) send(otherSide, myIdentityFragment) - val theirIdentity = receive>(otherSide).unwrap { validateIdentity(it) } - return mapOf(Pair(otherSide, AnonymousIdentity(myIdentityFragment)), - Pair(serviceHub.myInfo.legalIdentity, theirIdentity)) + receive>(otherSide).unwrap { validateIdentity(it) } } } diff --git a/core/src/main/kotlin/net/corda/core/node/CordaPluginRegistry.kt b/core/src/main/kotlin/net/corda/core/node/CordaPluginRegistry.kt index 6d73439665..d8d2b75834 100644 --- a/core/src/main/kotlin/net/corda/core/node/CordaPluginRegistry.kt +++ b/core/src/main/kotlin/net/corda/core/node/CordaPluginRegistry.kt @@ -33,6 +33,9 @@ abstract class CordaPluginRegistry { * The [PluginServiceHub] will be fully constructed before the plugin service is created and will * allow access to the Flow factory and Flow initiation entry points there. */ + @Suppress("unused") + @Deprecated("This is no longer used. If you need to create your own service, such as an oracle, then use the " + + "@CordaService annotation. For flow registrations use @InitiatedBy.", level = DeprecationLevel.ERROR) open val servicePlugins: List> get() = emptyList() /** diff --git a/core/src/main/kotlin/net/corda/core/node/PluginServiceHub.kt b/core/src/main/kotlin/net/corda/core/node/PluginServiceHub.kt index b6ead1d051..be193d2dfe 100644 --- a/core/src/main/kotlin/net/corda/core/node/PluginServiceHub.kt +++ b/core/src/main/kotlin/net/corda/core/node/PluginServiceHub.kt @@ -7,22 +7,7 @@ import net.corda.core.identity.Party * A service hub to be used by the [CordaPluginRegistry] */ interface PluginServiceHub : ServiceHub { - /** - * Register the service flow factory to use when an initiating party attempts to communicate with us. The registration - * is done against the [Class] object of the client flow to the service flow. What this means is if a counterparty - * starts a [FlowLogic] represented by [initiatingFlowClass] and starts communication with us, we will execute the service - * flow produced by [serviceFlowFactory]. This service flow has respond correctly to the sends and receives the client - * does. - * @param initiatingFlowClass [Class] of the client flow involved in this client-server communication. - * @param serviceFlowFactory Lambda which produces a new service flow for each new client flow communication. The - * [Party] parameter of the factory is the client's identity. - * @throws IllegalArgumentException If [initiatingFlowClass] is not annotated with [net.corda.core.flows.InitiatingFlow]. - */ - fun registerServiceFlow(initiatingFlowClass: Class>, serviceFlowFactory: (Party) -> FlowLogic<*>) - - @Suppress("UNCHECKED_CAST") - @Deprecated("This is scheduled to be removed in a future release", ReplaceWith("registerServiceFlow")) - fun registerFlowInitiator(markerClass: Class<*>, flowFactory: (Party) -> FlowLogic<*>) { - registerServiceFlow(markerClass as Class>, flowFactory) - } + @Deprecated("This is no longer used. Instead annotate the flows produced by your factory with @InitiatedBy and have " + + "them point to the initiating flow class.", level = DeprecationLevel.ERROR) + fun registerFlowInitiator(initiatingFlowClass: Class>, serviceFlowFactory: (Party) -> FlowLogic<*>) = Unit } diff --git a/core/src/main/kotlin/net/corda/core/node/ServiceHub.kt b/core/src/main/kotlin/net/corda/core/node/ServiceHub.kt index 5e589834dd..42733ab4b3 100644 --- a/core/src/main/kotlin/net/corda/core/node/ServiceHub.kt +++ b/core/src/main/kotlin/net/corda/core/node/ServiceHub.kt @@ -3,6 +3,7 @@ package net.corda.core.node import net.corda.core.contracts.* import net.corda.core.crypto.DigitalSignature import net.corda.core.node.services.* +import net.corda.core.serialization.SerializeAsToken import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.TransactionBuilder import java.security.PublicKey @@ -44,6 +45,13 @@ interface ServiceHub : ServicesForResolution { val clock: Clock val myInfo: NodeInfo + /** + * Return the singleton instance of the given Corda service type. This is a class that is annotated with + * [CordaService] and will have automatically been registered by the node. + * @throws IllegalArgumentException If [type] is not annotated with [CordaService] or if the instance is not found. + */ + fun cordaService(type: Class): T + /** * Given a [SignedTransaction], writes it to the local storage for validated transactions and then * sends them to the vault for further processing. Expects to be run within a database transaction. diff --git a/core/src/main/kotlin/net/corda/core/node/services/CordaService.kt b/core/src/main/kotlin/net/corda/core/node/services/CordaService.kt new file mode 100644 index 0000000000..a6b6a36b03 --- /dev/null +++ b/core/src/main/kotlin/net/corda/core/node/services/CordaService.kt @@ -0,0 +1,20 @@ +package net.corda.core.node.services + +import kotlin.annotation.AnnotationTarget.CLASS + +/** + * Annotate any class that needs to be a long-lived service within the node, such as an oracle, with this annotation. + * Such a class needs to have a constructor with a single parameter of type [net.corda.core.node.PluginServiceHub]. This + * construtor will be invoked during node start to initialise the service. The service hub provided can be used to get + * information about the node that may be necessary for the service. Corda services are created as singletons within + * the node and are available to flows via [net.corda.core.node.ServiceHub.cordaService]. + * + * The service class has to implement [net.corda.core.serialization.SerializeAsToken] to ensure correct usage within flows. + * (If possible extend [net.corda.core.serialization.SingletonSerializeAsToken] instead as it removes the boilerplate.) + */ +// TODO Handle the singleton serialisation of Corda services automatically, removing the need to implement SerializeAsToken +// TODO Currently all nodes which load the plugin will attempt to load the service even if it's not revelant to them. The +// underlying problem is that the entire CorDapp jar is used as a dependency, when in fact it's just the client-facing +// bit of the CorDapp that should be depended on (e.g. the initiating flows). +@Target(CLASS) +annotation class CordaService \ No newline at end of file diff --git a/core/src/main/kotlin/net/corda/core/utilities/ProcessUtilities.kt b/core/src/main/kotlin/net/corda/core/utilities/ProcessUtilities.kt index 308824def6..d69ab38367 100644 --- a/core/src/main/kotlin/net/corda/core/utilities/ProcessUtilities.kt +++ b/core/src/main/kotlin/net/corda/core/utilities/ProcessUtilities.kt @@ -2,21 +2,24 @@ package net.corda.core.utilities import java.nio.file.Path +// TODO This doesn't belong in core and can be moved into node object ProcessUtilities { inline fun startJavaProcess( arguments: List, + classpath: String = defaultClassPath, jdwpPort: Int? = null, extraJvmArguments: List = emptyList(), inheritIO: Boolean = true, errorLogPath: Path? = null, workingDirectory: Path? = null ): Process { - return startJavaProcess(C::class.java.name, arguments, jdwpPort, extraJvmArguments, inheritIO, errorLogPath, workingDirectory) + return startJavaProcess(C::class.java.name, arguments, classpath, jdwpPort, extraJvmArguments, inheritIO, errorLogPath, workingDirectory) } fun startJavaProcess( className: String, arguments: List, + classpath: String = defaultClassPath, jdwpPort: Int? = null, extraJvmArguments: List = emptyList(), inheritIO: Boolean = true, @@ -24,7 +27,6 @@ object ProcessUtilities { workingDirectory: Path? = null ): Process { val separator = System.getProperty("file.separator") - val classpath = System.getProperty("java.class.path") val javaPath = System.getProperty("java.home") + separator + "bin" + separator + "java" val debugPortArgument = if (jdwpPort != null) { listOf("-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=$jdwpPort") @@ -44,4 +46,6 @@ object ProcessUtilities { if (workingDirectory != null) directory(workingDirectory.toFile()) }.start() } + + val defaultClassPath: String get() = System.getProperty("java.class.path") } diff --git a/core/src/test/java/net/corda/core/flows/FlowsInJavaTest.java b/core/src/test/java/net/corda/core/flows/FlowsInJavaTest.java index 7f2d31ccaa..ea99e84cc6 100644 --- a/core/src/test/java/net/corda/core/flows/FlowsInJavaTest.java +++ b/core/src/test/java/net/corda/core/flows/FlowsInJavaTest.java @@ -1,13 +1,15 @@ package net.corda.core.flows; -import co.paralleluniverse.fibers.*; +import co.paralleluniverse.fibers.Suspendable; import net.corda.core.identity.Party; -import net.corda.testing.node.*; -import org.junit.*; +import net.corda.testing.node.MockNetwork; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; -import java.util.concurrent.*; +import java.util.concurrent.Future; -import static org.assertj.core.api.AssertionsForClassTypes.*; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; public class FlowsInJavaTest { @@ -30,13 +32,12 @@ public class FlowsInJavaTest { @Test public void suspendableActionInsideUnwrap() throws Exception { - node2.getServices().registerServiceFlow(SendInUnwrapFlow.class, (otherParty) -> new OtherFlow(otherParty, "Hello")); + node2.registerInitiatedFlow(SendHelloAndThenReceive.class); Future result = node1.getServices().startFlow(new SendInUnwrapFlow(node2.getInfo().getLegalIdentity())).getResultFuture(); net.runNetwork(); assertThat(result.get()).isEqualTo("Hello"); } - @SuppressWarnings("unused") @InitiatingFlow private static class SendInUnwrapFlow extends FlowLogic { private final Party otherParty; @@ -55,19 +56,18 @@ public class FlowsInJavaTest { } } - private static class OtherFlow extends FlowLogic { + @InitiatedBy(SendInUnwrapFlow.class) + private static class SendHelloAndThenReceive extends FlowLogic { private final Party otherParty; - private final String payload; - private OtherFlow(Party otherParty, String payload) { + private SendHelloAndThenReceive(Party otherParty) { this.otherParty = otherParty; - this.payload = payload; } @Suspendable @Override public String call() throws FlowException { - return sendAndReceive(String.class, otherParty, payload).unwrap(data -> data); + return sendAndReceive(String.class, otherParty, "Hello").unwrap(data -> data); } } diff --git a/core/src/test/kotlin/net/corda/core/flows/CollectSignaturesFlowTests.kt b/core/src/test/kotlin/net/corda/core/flows/CollectSignaturesFlowTests.kt index 7e30609ca7..1396799b8c 100644 --- a/core/src/test/kotlin/net/corda/core/flows/CollectSignaturesFlowTests.kt +++ b/core/src/test/kotlin/net/corda/core/flows/CollectSignaturesFlowTests.kt @@ -7,7 +7,6 @@ import net.corda.core.contracts.TransactionType import net.corda.core.contracts.requireThat import net.corda.core.getOrThrow import net.corda.core.identity.Party -import net.corda.core.node.PluginServiceHub import net.corda.core.transactions.SignedTransaction import net.corda.core.utilities.unwrap import net.corda.flows.CollectSignaturesFlow @@ -18,7 +17,7 @@ import net.corda.testing.node.MockNetwork import org.junit.After import org.junit.Before import org.junit.Test -import java.util.concurrent.ExecutionException +import kotlin.reflect.KClass import kotlin.test.assertFailsWith class CollectSignaturesFlowTests { @@ -37,9 +36,6 @@ class CollectSignaturesFlowTests { c = nodes.partyNodes[2] notary = nodes.notaryNode.info.notaryIdentity mockNet.runNetwork() - CollectSigsTestCorDapp.registerFlows(a.services) - CollectSigsTestCorDapp.registerFlows(b.services) - CollectSigsTestCorDapp.registerFlows(c.services) } @After @@ -47,11 +43,9 @@ class CollectSignaturesFlowTests { mockNet.stopNodes() } - object CollectSigsTestCorDapp { - // Would normally be called by custom service init in a CorDapp. - fun registerFlows(pluginHub: PluginServiceHub) { - pluginHub.registerFlowInitiator(TestFlow.Initiator::class.java) { TestFlow.Responder(it) } - pluginHub.registerFlowInitiator(TestFlowTwo.Initiator::class.java) { TestFlowTwo.Responder(it) } + private fun registerFlowOnAllNodes(flowClass: KClass>) { + listOf(a, b, c).forEach { + it.registerInitiatedFlow(flowClass.java) } } @@ -82,6 +76,7 @@ class CollectSignaturesFlowTests { } } + @InitiatedBy(TestFlow.Initiator::class) class Responder(val otherParty: Party) : FlowLogic() { @Suspendable override fun call(): SignedTransaction { @@ -104,7 +99,7 @@ class CollectSignaturesFlowTests { // receiving off the wire. object TestFlowTwo { @InitiatingFlow - class Initiator(val state: DummyContract.MultiOwnerState, val otherParty: Party) : FlowLogic() { + class Initiator(val state: DummyContract.MultiOwnerState) : FlowLogic() { @Suspendable override fun call(): SignedTransaction { val notary = serviceHub.networkMapCache.notaryNodes.single().notaryIdentity @@ -118,6 +113,7 @@ class CollectSignaturesFlowTests { } } + @InitiatedBy(TestFlowTwo.Initiator::class) class Responder(val otherParty: Party) : FlowLogic() { @Suspendable override fun call(): SignedTransaction { val flow = object : SignTransactionFlow(otherParty) { @@ -137,13 +133,13 @@ class CollectSignaturesFlowTests { } } - @Test fun `successfully collects two signatures`() { + registerFlowOnAllNodes(TestFlowTwo.Responder::class) val magicNumber = 1337 val parties = listOf(a.info.legalIdentity, b.info.legalIdentity, c.info.legalIdentity) val state = DummyContract.MultiOwnerState(magicNumber, parties) - val flow = a.services.startFlow(TestFlowTwo.Initiator(state, b.info.legalIdentity)) + val flow = a.services.startFlow(TestFlowTwo.Initiator(state)) mockNet.runNetwork() val result = flow.resultFuture.getOrThrow() result.verifySignatures() @@ -169,8 +165,8 @@ class CollectSignaturesFlowTests { val ptx = onePartyDummyContract.signWith(MINI_CORP_KEY).toSignedTransaction(false) val flow = a.services.startFlow(CollectSignaturesFlow(ptx)) mockNet.runNetwork() - assertFailsWith("The Initiator of CollectSignaturesFlow must have signed the transaction.") { - flow.resultFuture.get() + assertFailsWith("The Initiator of CollectSignaturesFlow must have signed the transaction.") { + flow.resultFuture.getOrThrow() } } diff --git a/core/src/test/kotlin/net/corda/core/flows/TxKeyFlowTests.kt b/core/src/test/kotlin/net/corda/core/flows/TxKeyFlowTests.kt index 44c1f86731..ee69808222 100644 --- a/core/src/test/kotlin/net/corda/core/flows/TxKeyFlowTests.kt +++ b/core/src/test/kotlin/net/corda/core/flows/TxKeyFlowTests.kt @@ -38,7 +38,7 @@ class TxKeyFlowTests { bobNode.services.identityService.registerIdentity(notaryNode.info.legalIdentity) // Run the flows - bobNode.registerServiceFlow(TxKeyFlow.Requester::class) { TxKeyFlow.Provider(it) } + bobNode.registerInitiatedFlow(TxKeyFlow.Provider::class.java) val requesterFlow = aliceNode.services.startFlow(TxKeyFlow.Requester(bob, revocationEnabled)) // Get the results diff --git a/core/src/test/kotlin/net/corda/core/serialization/AttachmentSerializationTest.kt b/core/src/test/kotlin/net/corda/core/serialization/AttachmentSerializationTest.kt index dba3d63d17..2e300844c9 100644 --- a/core/src/test/kotlin/net/corda/core/serialization/AttachmentSerializationTest.kt +++ b/core/src/test/kotlin/net/corda/core/serialization/AttachmentSerializationTest.kt @@ -12,10 +12,12 @@ import net.corda.core.messaging.SingleMessageRecipient import net.corda.core.node.services.ServiceInfo import net.corda.core.utilities.unwrap import net.corda.flows.FetchAttachmentsFlow +import net.corda.node.internal.InitiatedFlowFactory import net.corda.node.services.config.NodeConfiguration import net.corda.node.services.network.NetworkMapService import net.corda.node.services.persistence.NodeAttachmentService import net.corda.node.services.persistence.schemas.AttachmentEntity +import net.corda.node.services.statemachine.SessionInit import net.corda.node.utilities.transaction import net.corda.testing.node.MockNetwork import org.junit.After @@ -136,7 +138,11 @@ class AttachmentSerializationTest { } private fun launchFlow(clientLogic: ClientLogic, rounds: Int) { - server.services.registerServiceFlow(clientLogic.javaClass, ::ServerLogic) + server.registerFlowFactory(ClientLogic::class.java, object : InitiatedFlowFactory { + override fun createFlow(platformVersion: Int, otherParty: Party, sessionInit: SessionInit): ServerLogic { + return ServerLogic(otherParty) + } + }, ServerLogic::class.java, track = false) client.services.startFlow(clientLogic) network.runNetwork(rounds) } diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index e210cc7428..38c6fb8e15 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -7,82 +7,79 @@ from the previous milestone release. UNRELEASED ---------- -* API changes: - * ``Timestamp`` used for validation/notarization time-range has been renamed to ``TimeWindow``. - There are now 4 factory methods ``TimeWindow.fromOnly(fromTime: Instant)``, - ``TimeWindow.untilOnly(untilTime: Instant)``, ``TimeWindow.between(fromTime: Instant, untilTime: Instant)`` and - ``TimeWindow.withTolerance(time: Instant, tolerance: Duration)``. - Previous constructors ``TimeWindow(fromTime: Instant, untilTime: Instant)`` and - ``TimeWindow(time: Instant, tolerance: Duration)`` have been removed. +* Quite a few changes have been made to the flow API which should make things simpler when writing CorDapps: * ``CordaPluginRegistry.requiredFlows`` is no longer needed. Instead annotate any flows you wish to start via RPC with - ``@StartableByRPC`` and any scheduled flows with ``@SchedulableFlow``. + ``@StartableByRPC`` and any scheduled flows with ``@SchedulableFlow``. - * Flows which initiate flows in their counterparties (an example of which is the ``NotaryFlow.Client``) are now - required to be annotated with ``@InitiatingFlow``. + * ``CordaPluginRegistry.servicePlugins`` is also no longer used, along with ``PluginServiceHub.registerFlowInitiator``. + Instead annotate your initiated flows with ``@InitiatedBy``. This annotation takes a single parameter which is the + initiating flow. This initiating flow further has to be annotated with ``@InitiatingFlow``. For any services you + may have, such as oracles, annotate them with ``@CordaService``. - * ``PluginServiceHub.registerFlowInitiator`` has been deprecated and replaced by ``registerServiceFlow`` with the - marker Class restricted to ``FlowLogic``. In line with the introduction of ``InitiatingFlow``, it throws an - ``IllegalArgumentException`` if the initiating flow class is not annotated with it. + * Related to ``InitiatingFlow``, the ``shareParentSessions`` boolean parameter of ``FlowLogic.subFlow`` has been + removed. This was an unfortunate parameter that unnecessarily exposed the inner workings of flow sessions. Now, if + your sub-flow can be started outside the context of the parent flow then annotate it with ``@InitiatingFlow``. If + it's meant to be used as a continuation of the existing parent flow, such as ``CollectSignaturesFlow``, then it + doesn't need any annotation. - * Also related to ``InitiatingFlow``, the ``shareParentSessions`` boolean parameter of ``FlowLogic.subFlow`` has been - removed. Its purpose was to allow subflows to be inlined with the parent flow - i.e. the subflow does not initiate - new sessions with parties the parent flow has already started. This allowed flows to be used as building blocks. To - achieve the same effect now simply requires the subflow to be *not* annotated wth ``InitiatingFlow`` (i.e. we've made - this the default behaviour). If the subflow is not meant to be inlined, and is supposed to initiate flows on the - other side, the annotation is required. + * The ``InitiatingFlow`` annotation also has an integer ``version`` property which assigns the initiating flow a version + number, defaulting to 1 if it's not specified. This enables versioning of flows with nodes only accepting communication + if the version number matches. At some point we will support the ability for a node to have multiple versions of the + same flow registered, enabling backwards compatibility of flows. - * ``ContractUpgradeFlow.Instigator`` has been renamed to just ``ContractUpgradeFlow``. + * ``ContractUpgradeFlow.Instigator`` has been renamed to just ``ContractUpgradeFlow``. - * ``NotaryChangeFlow.Instigator`` has been renamed to just ``NotaryChangeFlow``. + * ``NotaryChangeFlow.Instigator`` has been renamed to just ``NotaryChangeFlow``. - * ``FlowLogic.getCounterpartyMarker`` is no longer used and been deprecated for removal. If you were using this to - manage multiple independent message streams with the same party in the same flow then use sub-flows instead. + * ``FlowLogic.getCounterpartyMarker`` is no longer used and been deprecated for removal. If you were using this to + manage multiple independent message streams with the same party in the same flow then use sub-flows instead. - * There are major changes to the ``Party`` class as part of confidential identities: +* There are major changes to the ``Party`` class as part of confidential identities: - * ``Party`` has moved to the ``net.corda.core.identity`` package; there is a deprecated class in its place for - backwards compatibility, but it will be removed in a future release and developers should move to the new class as soon - as possible. - * There is a new ``AbstractParty`` superclass to ``Party``, which contains just the public key. This now replaces - use of ``Party`` and ``PublicKey`` in state objects, and allows use of full or anonymised parties depending on - use-case. - * Names of parties are now stored as a ``X500Name`` rather than a ``String``, to correctly enforce basic structure of the - name. As a result all node legal names must now be structured as X.500 distinguished names. + * ``Party`` has moved to the ``net.corda.core.identity`` package; there is a deprecated class in its place for + backwards compatibility, but it will be removed in a future release and developers should move to the new class as soon + as possible. + * There is a new ``AbstractParty`` superclass to ``Party``, which contains just the public key. This now replaces + use of ``Party`` and ``PublicKey`` in state objects, and allows use of full or anonymised parties depending on + use-case. + * Names of parties are now stored as a ``X500Name`` rather than a ``String``, to correctly enforce basic structure of the + name. As a result all node legal names must now be structured as X.500 distinguished names. - * The Bouncy Castle library ``X509CertificateHolder`` class is now used in place of ``X509Certificate`` in order to - have a consistent class used internally. Conversions to/from ``X509Certificate`` are done as required, but should - be avoided where possible. +* There are major changes to transaction signing in flows: - * There are major changes to transaction signing in flows: - - * You should use the new ``CollectSignaturesFlow`` and corresponding ``SignTransactionFlow`` which handle most + * You should use the new ``CollectSignaturesFlow`` and corresponding ``SignTransactionFlow`` which handle most of the details of this for you. They may get more complex in future as signing becomes a more featureful operation. * ``ServiceHub.legalIdentityKey`` no longer returns a ``KeyPair``, it instead returns just the ``PublicKey`` portion of this pair. - The ``ServiceHub.notaryIdentityKey`` has changed similarly. The goal of this change is to keep private keys + The ``ServiceHub.notaryIdentityKey`` has changed similarly. The goal of this change is to keep private keys encapsulated and away from most flow code/Java code, so that the private key material can be stored in HSMs and other key management devices. - * The ``KeyManagementService`` now provides no mechanism to request the node's ``PrivateKey`` objects directly. - Instead signature creation occurs in the ``KeyManagementService.sign``, with the ``PublicKey`` used to indicate - which of the node's multiple keys to use. This lookup also works for ``CompositeKey`` scenarios - and the service will search for a leaf key hosted on the node. - * The ``KeyManagementService.freshKey`` method now returns only the ``PublicKey`` portion of the newly generated ``KeyPair`` - with the ``PrivateKey`` kept internally to the service. - * Flows which used to acquire a node's ``KeyPair``, typically via ``ServiceHub.legalIdentityKey``, - should instead use the helper methods on ``ServiceHub``. In particular to freeze a ``TransactionBuilder`` and - generate an initial partially signed ``SignedTransaction`` the flow should use ``ServiceHub.signInitialTransaction``. - Flows generating additional party signatures should use ``ServiceHub.createSignature``. Each of these methods is - provided with two signatures. One version that signs with the default node key, the other which allows key selection - by passing in the ``PublicKey`` partner of the desired signing key. - * The original ``KeyPair`` signing methods have been left on the ``TransactionBuilder`` and ``SignedTransaction``, but - should only be used as part of unit testing. - -* The ``InitiatingFlow`` annotation also has an integer ``version`` property which assigns the initiating flow a version - number, defaulting to 1 if it's specified. The flow version is included in the flow session request and the counterparty - will only respond and start their own flow if the version number matches to the one they've registered with. At some - point we will support the ability for a node to have multiple versions of the same flow registered, enabling backwards - compatibility of CorDapp flows. + * The ``KeyManagementService`` now provides no mechanism to request the node's ``PrivateKey`` objects directly. + Instead signature creation occurs in the ``KeyManagementService.sign``, with the ``PublicKey`` used to indicate + which of the node's multiple keys to use. This lookup also works for ``CompositeKey`` scenarios + and the service will search for a leaf key hosted on the node. + * The ``KeyManagementService.freshKey`` method now returns only the ``PublicKey`` portion of the newly generated ``KeyPair`` + with the ``PrivateKey`` kept internally to the service. + * Flows which used to acquire a node's ``KeyPair``, typically via ``ServiceHub.legalIdentityKey``, + should instead use the helper methods on ``ServiceHub``. In particular to freeze a ``TransactionBuilder`` and + generate an initial partially signed ``SignedTransaction`` the flow should use ``ServiceHub.signInitialTransaction``. + Flows generating additional party signatures should use ``ServiceHub.createSignature``. Each of these methods is + provided with two signatures. One version that signs with the default node key, the other which allows key selection + by passing in the ``PublicKey`` partner of the desired signing key. + * The original ``KeyPair`` signing methods have been left on the ``TransactionBuilder`` and ``SignedTransaction``, but + should only be used as part of unit testing. + +* ``Timestamp`` used for validation/notarization time-range has been renamed to ``TimeWindow``. + There are now 4 factory methods ``TimeWindow.fromOnly(fromTime: Instant)``, + ``TimeWindow.untilOnly(untilTime: Instant)``, ``TimeWindow.between(fromTime: Instant, untilTime: Instant)`` and + ``TimeWindow.withTolerance(time: Instant, tolerance: Duration)``. + Previous constructors ``TimeWindow(fromTime: Instant, untilTime: Instant)`` and + ``TimeWindow(time: Instant, tolerance: Duration)`` have been removed. + +* The Bouncy Castle library ``X509CertificateHolder`` class is now used in place of ``X509Certificate`` in order to + have a consistent class used internally. Conversions to/from ``X509Certificate`` are done as required, but should + be avoided where possible. * The certificate hierarchy has been changed in order to allow corda node to sign keys with proper certificate chain. * The corda node will now be issued a restricted client CA for identity/transaction key signing. diff --git a/docs/source/corda-plugins.rst b/docs/source/corda-plugins.rst index 75a893449a..281c6874ec 100644 --- a/docs/source/corda-plugins.rst +++ b/docs/source/corda-plugins.rst @@ -45,40 +45,7 @@ extensions to be created, or registered at startup. In particular: jars. These static serving directories will not be available if the bundled web server is not started. - c. The ``servicePlugins`` property returns a list of classes which will - be instantiated once during the ``AbstractNode.start`` call. These - classes must provide a single argument constructor which will receive a - ``PluginServiceHub`` reference. They must also extend the abstract class - ``SingletonSerializeAsToken`` which ensures that if any reference to your - service is captured in a flow checkpoint (i.e. serialized by Kryo as - part of Quasar checkpoints, either on the stack or by reference within - your flows) it is stored as a simple token representing your service. - When checkpoints are restored, after a node restart for example, - the latest instance of the service will be substituted back in place of - the token stored in the checkpoint. - - i. Firstly, they can call ``PluginServiceHub.registerServiceFlow`` and - register flows that will be initiated locally in response to remote flow - requests. - - ii. Second, the service can hold a long lived reference to the - PluginServiceHub and to other private data, so the service can be used - to provide Oracle functionality. This Oracle functionality would - typically be exposed to other nodes by flows which are given a reference - to the service plugin when initiated (as defined by the - ``registerServiceFlow`` call). The flow can then call into functions - on the plugin service singleton. Note, care should be taken to not allow - flows to hold references to fields which are not - also ``SingletonSerializeAsToken``, otherwise Quasar suspension in the - ``StateMachineManager`` will fail with exceptions. An example oracle can - be seen in ``NodeInterestRates.kt`` in the irs-demo sample. - - iii. The final use case for service plugins is that they can spawn threads, or register - to monitor vault updates. This allows them to provide long lived active - functions inside the node, for instance to initiate workflows when - certain conditions are met. - - d. The ``customizeSerialization`` function allows classes to be whitelisted + c. The ``customizeSerialization`` function allows classes to be whitelisted for object serialisation, over and above those tagged with the ``@CordaSerializable`` annotation. In general the annotation should be preferred. For instance new state types will need to be explicitly registered. This will be called at diff --git a/docs/source/creating-a-cordapp.rst b/docs/source/creating-a-cordapp.rst index c4c808aeb5..5a31c228a0 100644 --- a/docs/source/creating-a-cordapp.rst +++ b/docs/source/creating-a-cordapp.rst @@ -12,20 +12,33 @@ App plugins To create an app plugin you must extend from `CordaPluginRegistry`_. The JavaDoc contains specific details of the implementation, but you can extend the server in the following ways: -1. Service plugins: Register your services (see below). +1. Register your flows and services (see below). 2. Web APIs: You may register your own endpoints under /api/ of the bundled web server. 3. Static web endpoints: You may register your own static serving directories for serving web content from the web server. 4. Whitelisting your additional contract, state and other classes for object serialization. Any class that forms part of a persisted state, that is used in messaging between flows or in RPC needs to be whitelisted. -Services --------- +Flows and services +------------------ -Services are classes which are constructed after the node has started. It is provided a `PluginServiceHub`_ which -allows a richer API than the `ServiceHub`_ exposed to contracts. It enables adding flows, registering -message handlers and more. The service does not run in a separate thread, so the only entry point to the service is during -construction, where message handlers should be registered and threads started. +Flows are of two types: initiating and initiated. Initiating flows need to be annotated with ``@InitiatingFlow`` and can +be started in one of three ways: +1. By a user of your CorDapp via RPC in which the flow also needs to be annotated with ``@StartableByRPC``. +2. By another CorDapp executing it as a sub-flow in their own flow. +3. By a ``SchedulableState`` activity event, in which the flow also needs to be annotated with ``@SchedulableFlow`` + +``InitiatingFlow`` also has a ``version`` property to enable you to version your flows. A node will only accept communication +from an initiating party if the version numbers match up. + +Initiated flows are typically private to your CorDapp and need to be annotated with ``@InitiatedBy`` which point to +initiating flow Class. The node scans your CorDapps for these annotations and automatically registers the initiating to +initiated mapping for you. + +If your CorDapp also needs to have additional services running in the node, such as oracles, then annotate your service +class with ``@CordaService``. As with the flows, the node will automatically register it and make it available for use by +your flows. The service class has to implement ``SerializeAsToken`` to ensure they work correctly within flows. If possible +extend ``SingletonSerializeAsToken`` instead to avoid the boilerplate. Starting nodes -------------- diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/FxTransactionBuildTutorial.kt b/docs/source/example-code/src/main/kotlin/net/corda/docs/FxTransactionBuildTutorial.kt index 4a7def4e87..33d75ce6ee 100644 --- a/docs/source/example-code/src/main/kotlin/net/corda/docs/FxTransactionBuildTutorial.kt +++ b/docs/source/example-code/src/main/kotlin/net/corda/docs/FxTransactionBuildTutorial.kt @@ -9,9 +9,9 @@ import net.corda.core.contracts.TransactionType import net.corda.core.crypto.DigitalSignature import net.corda.core.crypto.SecureHash import net.corda.core.flows.FlowLogic +import net.corda.core.flows.InitiatedBy import net.corda.core.flows.InitiatingFlow import net.corda.core.identity.Party -import net.corda.core.node.PluginServiceHub import net.corda.core.node.ServiceHub import net.corda.core.node.services.unconsumedStates import net.corda.core.serialization.CordaSerializable @@ -21,13 +21,6 @@ import net.corda.flows.FinalityFlow import net.corda.flows.ResolveTransactionsFlow import java.util.* -object FxTransactionDemoTutorial { - // Would normally be called by custom service init in a CorDapp - fun registerFxProtocols(pluginHub: PluginServiceHub) { - pluginHub.registerServiceFlow(ForeignExchangeFlow::class.java, ::ForeignExchangeRemoteFlow) - } -} - @CordaSerializable private data class FxRequest(val tradeId: String, val amount: Amount>, @@ -212,6 +205,7 @@ class ForeignExchangeFlow(val tradeId: String, // DOCEND 3 } +@InitiatedBy(ForeignExchangeFlow::class) class ForeignExchangeRemoteFlow(val source: Party) : FlowLogic() { @Suspendable override fun call() { diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/WorkflowTransactionBuildTutorial.kt b/docs/source/example-code/src/main/kotlin/net/corda/docs/WorkflowTransactionBuildTutorial.kt index aaba15267e..43c7b5b245 100644 --- a/docs/source/example-code/src/main/kotlin/net/corda/docs/WorkflowTransactionBuildTutorial.kt +++ b/docs/source/example-code/src/main/kotlin/net/corda/docs/WorkflowTransactionBuildTutorial.kt @@ -6,10 +6,10 @@ import net.corda.core.crypto.DigitalSignature import net.corda.core.crypto.SecureHash import net.corda.core.crypto.containsAny import net.corda.core.flows.FlowLogic +import net.corda.core.flows.InitiatedBy import net.corda.core.flows.InitiatingFlow import net.corda.core.identity.AbstractParty import net.corda.core.identity.Party -import net.corda.core.node.PluginServiceHub import net.corda.core.node.ServiceHub import net.corda.core.node.services.linearHeadsOfType import net.corda.core.serialization.CordaSerializable @@ -19,22 +19,13 @@ import net.corda.flows.FinalityFlow import java.security.PublicKey import java.time.Duration -object WorkflowTransactionBuildTutorial { - // Would normally be called by custom service init in a CorDapp - fun registerWorkflowProtocols(pluginHub: PluginServiceHub) { - pluginHub.registerServiceFlow(SubmitCompletionFlow::class.java, ::RecordCompletionFlow) - } -} - // DOCSTART 1 - // Helper method to locate the latest Vault version of a LinearState from a possibly out of date StateRef inline fun ServiceHub.latest(ref: StateRef): StateAndRef { val linearHeads = vaultService.linearHeadsOfType() val original = toStateAndRef(ref) - return linearHeads.get(original.state.data.linearId)!! + return linearHeads[original.state.data.linearId]!! } - // DOCEND 1 // Minimal state model of a manual approval process @@ -87,7 +78,7 @@ data class TradeApprovalContract(override val legalContractReference: SecureHash "Issue of new WorkflowContract must not include any inputs" using (tx.inputs.isEmpty()) "Issue of new WorkflowContract must be in a unique transaction" using (tx.outputs.size == 1) } - val issued = tx.outputs.get(0) as TradeApprovalContract.State + val issued = tx.outputs[0] as TradeApprovalContract.State requireThat { "Issue requires the source Party as signer" using (command.signers.contains(issued.source.owningKey)) "Initial Issue state must be NEW" using (issued.state == WorkflowState.NEW) @@ -96,9 +87,9 @@ data class TradeApprovalContract(override val legalContractReference: SecureHash is Commands.Completed -> { val stateGroups = tx.groupStates(TradeApprovalContract.State::class.java) { it.linearId } require(stateGroups.size == 1) { "Must be only a single proposal in transaction" } - for (group in stateGroups) { - val before = group.inputs.single() - val after = group.outputs.single() + for ((inputs, outputs) in stateGroups) { + val before = inputs.single() + val after = outputs.single() requireThat { "Only a non-final trade can be modified" using (before.state == WorkflowState.NEW) "Output must be a final state" using (after.state in setOf(WorkflowState.APPROVED, WorkflowState.REJECTED)) @@ -227,6 +218,7 @@ class SubmitCompletionFlow(val ref: StateRef, val verdict: WorkflowState) : Flow * Then after checking to sign it and eventually store the fully notarised * transaction to the ledger. */ +@InitiatedBy(SubmitCompletionFlow::class) class RecordCompletionFlow(val source: Party) : FlowLogic() { @Suspendable override fun call(): Unit { diff --git a/docs/source/example-code/src/test/kotlin/net/corda/docs/FxTransactionBuildTutorialTest.kt b/docs/source/example-code/src/test/kotlin/net/corda/docs/FxTransactionBuildTutorialTest.kt index 5713a3041a..59cd0dbfbc 100644 --- a/docs/source/example-code/src/test/kotlin/net/corda/docs/FxTransactionBuildTutorialTest.kt +++ b/docs/source/example-code/src/test/kotlin/net/corda/docs/FxTransactionBuildTutorialTest.kt @@ -29,14 +29,11 @@ class FxTransactionBuildTutorialTest { val notaryService = ServiceInfo(ValidatingNotaryService.type) notaryNode = net.createNode( legalName = DUMMY_NOTARY.name, - overrideServices = mapOf(Pair(notaryService, DUMMY_NOTARY_KEY)), + overrideServices = mapOf(notaryService to DUMMY_NOTARY_KEY), advertisedServices = *arrayOf(ServiceInfo(NetworkMapService.type), notaryService)) nodeA = net.createPartyNode(notaryNode.info.address) nodeB = net.createPartyNode(notaryNode.info.address) - FxTransactionDemoTutorial.registerFxProtocols(nodeA.services) - FxTransactionDemoTutorial.registerFxProtocols(nodeB.services) - WorkflowTransactionBuildTutorial.registerWorkflowProtocols(nodeA.services) - WorkflowTransactionBuildTutorial.registerWorkflowProtocols(nodeB.services) + nodeB.registerInitiatedFlow(ForeignExchangeRemoteFlow::class.java) } @After diff --git a/docs/source/example-code/src/test/kotlin/net/corda/docs/WorkflowTransactionBuildTutorialTest.kt b/docs/source/example-code/src/test/kotlin/net/corda/docs/WorkflowTransactionBuildTutorialTest.kt index 6815a205e2..77d389a1bb 100644 --- a/docs/source/example-code/src/test/kotlin/net/corda/docs/WorkflowTransactionBuildTutorialTest.kt +++ b/docs/source/example-code/src/test/kotlin/net/corda/docs/WorkflowTransactionBuildTutorialTest.kt @@ -4,7 +4,6 @@ import net.corda.core.contracts.LinearState import net.corda.core.contracts.StateAndRef import net.corda.core.contracts.StateRef import net.corda.core.getOrThrow -import net.corda.core.node.ServiceEntry import net.corda.core.node.ServiceHub import net.corda.core.node.services.ServiceInfo import net.corda.core.node.services.linearHeadsOfType @@ -30,7 +29,7 @@ class WorkflowTransactionBuildTutorialTest { private inline fun ServiceHub.latest(ref: StateRef): StateAndRef { val linearHeads = vaultService.linearHeadsOfType() val original = storageService.validatedTransactions.getTransaction(ref.txhash)!!.tx.outRef(ref.index) - return linearHeads.get(original.state.data.linearId)!! + return linearHeads[original.state.data.linearId]!! } @Before @@ -43,10 +42,7 @@ class WorkflowTransactionBuildTutorialTest { advertisedServices = *arrayOf(ServiceInfo(NetworkMapService.type), notaryService)) nodeA = net.createPartyNode(notaryNode.info.address) nodeB = net.createPartyNode(notaryNode.info.address) - FxTransactionDemoTutorial.registerFxProtocols(nodeA.services) - FxTransactionDemoTutorial.registerFxProtocols(nodeB.services) - WorkflowTransactionBuildTutorial.registerWorkflowProtocols(nodeA.services) - WorkflowTransactionBuildTutorial.registerWorkflowProtocols(nodeB.services) + nodeA.registerInitiatedFlow(RecordCompletionFlow::class.java) } @After diff --git a/docs/source/flow-state-machines.rst b/docs/source/flow-state-machines.rst index 9e90f045cd..fa75f50f8c 100644 --- a/docs/source/flow-state-machines.rst +++ b/docs/source/flow-state-machines.rst @@ -419,49 +419,57 @@ sequence of message transfers. Flows end pre-maturely due to exceptions, and as Taking a step back, we mentioned that the other side has to accept the session request for there to be a communication channel. A node accepts a session request if it has registered the flow type (the fully-qualified class name) that is -making the request - each session initiation includes the initiating flow type. The registration is done by a CorDapp -which has made available the particular flow communication, using ``PluginServiceHub.registerServiceFlow``. This method -specifies a flow factory for generating the counter-flow to any given initiating flow. If this registration doesn't exist -then no further communication takes place and the initiating flow ends with an exception. The initiating flow has to be -annotated with ``InitiatingFlow``. +making the request - each session initiation includes the initiating flow type. This registration is done automatically +by the node at startup by searching for flows which are annotated with ``@InitiatedBy``. This annotation points to the +flow that is doing the initiating, and this flow must be annotated with ``@InitiatingFlow``. The ``InitiatedBy`` flow +must have a constructor which takes in a single parameter of type ``Party`` - this is the initiating party. Going back to our buyer and seller flows, we need a way to initiate communication between the two. This is typically done -with one side started manually using the ``startFlowDynamic`` RPC and this initiates the counter-flow on the other side. -In this case it doesn't matter which flow is the initiator and which is the initiated, which is why neither ``Buyer`` nor -``Seller`` are annotated with ``InitiatingFlow``. For example, if we choose the seller side as the initiator then we need -to create a simple seller starter flow that has the annotation we need: +with one side started manually using the ``startFlowDynamic`` RPC and this initiates the flow on the other side. In our +case it doesn't matter which flow is the initiator and which is the initiated, which is why neither ``Buyer`` nor ``Seller`` +are annotated with ``InitiatedBy`` or ``InitiatingFlow``. If we, for example, choose the seller side as the initiator then +we need to create a simple seller starter flow that has the annotation we need: .. container:: codeset .. sourcecode:: kotlin @InitiatingFlow - class SellerStarter(val otherParty: Party, val assetToSell: StateAndRef, val price: Amount) : FlowLogic() { + class SellerInitiator(val buyer: Party, + val notary: NodeInfo, + val assetToSell: StateAndRef, + val price: Amount) : FlowLogic() { @Suspendable override fun call(): SignedTransaction { - val notary: NodeInfo = serviceHub.networkMapCache.notaryNodes[0] - val cpOwnerKey: PublicKey = serviceHub.legalIdentityKey - return subFlow(TwoPartyTradeFlow.Seller(otherParty, notary, assetToSell, price, cpOwnerKey)) + send(buyer, Pair(notary.notaryIdentity, price)) + return subFlow(Seller( + buyer, + notary, + assetToSell, + price, + serviceHub.legalIdentityKey)) } } -The buyer side would then need to register their flow, perhaps with something like: +The buyer side would look something like this. Notice the constructor takes in a single ``Party`` object which represents +the seller. .. container:: codeset .. sourcecode:: kotlin - val services: PluginServiceHub = TODO() - services.registerServiceFlow(SellerStarter::class.java) { otherParty -> - val notary = services.networkMapCache.notaryNodes[0] - val acceptablePrice = TODO() - val typeToBuy = TODO() - Buyer(otherParty, notary, acceptablePrice, typeToBuy) + @InitiatedBy(SellerInitiator::class) + class BuyerAcceptor(val seller: Party) : FlowLogic() { + @Suspendable + override fun call() { + val (notary, price) = receive>>(seller).unwrap { + require(serviceHub.networkMapCache.isNotary(it.first)) { "${it.first} is not a notary" } + it + } + subFlow(Buyer(seller, notary, price, CommercialPaper.State::class.java)) + } } -This is telling the buyer node to fire up an instance of ``Buyer`` (the code in the lambda) when the initiating flow -is a seller (``SellerStarter::class.java``). - .. _progress-tracking: Progress tracking diff --git a/docs/source/oracles.rst b/docs/source/oracles.rst index 63afdf510f..e3e74473ca 100644 --- a/docs/source/oracles.rst +++ b/docs/source/oracles.rst @@ -195,41 +195,37 @@ Here we can see that there are several steps: exactly our data source. The final step, assuming we have got this far, is to generate a signature for the transaction and return it. -Binding to the network via a CorDapp plugin -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Binding to the network +~~~~~~~~~~~~~~~~~~~~~~ .. note:: Before reading any further, we advise that you understand the concept of flows and how to write them and use them. See :doc:`flow-state-machines`. Likewise some understanding of Cordapps, plugins and services will be helpful. See :doc:`creating-a-cordapp`. -The first step is to create a service to host the oracle on the network. Let's see how that's implemented: +The first step is to create the oracle as a service by annotating its class with ``@CordaService``. Let's see how that's +done: + +.. literalinclude:: ../../samples/irs-demo/src/main/kotlin/net/corda/irs/api/NodeInterestRates.kt + :language: kotlin + :start-after: DOCSTART 3 + :end-before: DOCEND 3 + +The Corda node scans for any class with this annotation and initialises them. The only requirement is that the class provide +a constructor with a single parameter of type ``PluginServiceHub```. In our example the oracle class has two constructors. +The second is used for testing. .. literalinclude:: ../../samples/irs-demo/src/main/kotlin/net/corda/irs/api/NodeInterestRates.kt :language: kotlin :start-after: DOCSTART 2 :end-before: DOCEND 2 -This may look complicated, but really it's made up of some relatively simple elements (in the order they appear in the code): +These two flows leverage the oracle to provide the querying and signing operations. They get reference to the oracle, +which will have already been initialised by the node, using ``ServiceHub.cordappService``. Both flows are annotated with +``@InitiatedBy``. This tells the node which initiating flow (which are discussed in the next section) they are meant to +be executed with. -1. Accept a ``PluginServiceHub`` in the constructor. This is your interface to the Corda node. -2. Ensure you extend the abstract class ``SingletonSerializeAsToken`` (see :doc:`corda-plugins`). -3. Create an instance of your core oracle class that has the ``query`` and ``sign`` methods as discussed above. -4. Register your client sub-flows (in this case both in ``RatesFixFlow``. See the next section) for querying and - signing as initiating your service flows that actually do the querying and signing using your core oracle class instance. -5. Implement your service flows that call your core oracle class instance. - -The final step is to register your service with the node via the plugin mechanism. Do this by -implementing a plugin. Don't forget the resources file to register it with the ``ServiceLoader`` framework -(see :doc:`corda-plugins`). - -.. sourcecode:: kotlin - - class Plugin : CordaPluginRegistry() { - override val servicePlugins: List> = listOf(Service::class.java) - } - -Providing client sub-flows for querying and signing -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Providing sub-flows for querying and signing +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ We mentioned the client sub-flow briefly above. They are the mechanism that clients, in the form of other flows, will interact with your oracle. Typically there will be one for querying and one for signing. Let's take a look at diff --git a/docs/source/release-notes.rst b/docs/source/release-notes.rst index 02a2ab14cf..e39fab42b8 100644 --- a/docs/source/release-notes.rst +++ b/docs/source/release-notes.rst @@ -6,13 +6,15 @@ Here are release notes for each snapshot release from M9 onwards. Unreleased ---------- -We've added the ability for flows to be versioned by their CorDapp developers. This enables a node to support a particular -version of a flow and allows it to reject flow communication with a node which isn't using the same fact. In a future -release we allow a node to have multiple versions of the same flow running to enable backwards compatibility. +Writing CorDapps has been made simpler by removing boiler-plate code that was previously required when registering flows. +Instead we now make use of classpath scanning to automatically wire-up flows. There are major changes to the ``Party`` class as part of confidential identities, and how parties and keys are stored in transaction state objects. See :doc:`changelog` for full details. +We've added the ability for flows to be versioned by their CorDapp developers. This enables a node to support a particular +version of a flow and allows it to reject flow communication with a node which isn't using the same fact. In a future +release we allow a node to have multiple versions of the same flow running to enable backwards compatibility. Milestone 11 ------------ diff --git a/finance/src/main/kotlin/net/corda/flows/IssuerFlow.kt b/finance/src/main/kotlin/net/corda/flows/IssuerFlow.kt index ab6b4a8883..50bfe72327 100644 --- a/finance/src/main/kotlin/net/corda/flows/IssuerFlow.kt +++ b/finance/src/main/kotlin/net/corda/flows/IssuerFlow.kt @@ -2,12 +2,8 @@ package net.corda.flows import co.paralleluniverse.fibers.Suspendable import net.corda.core.contracts.* -import net.corda.core.flows.FlowException -import net.corda.core.flows.FlowLogic -import net.corda.core.flows.InitiatingFlow +import net.corda.core.flows.* import net.corda.core.identity.Party -import net.corda.core.flows.StartableByRPC -import net.corda.core.node.PluginServiceHub import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.OpaqueBytes import net.corda.core.transactions.SignedTransaction @@ -46,6 +42,7 @@ object IssuerFlow { * Issuer refers to a Node acting as a Bank Issuer of [FungibleAsset], and processes requests from a [IssuanceRequester] client. * Returns the generated transaction representing the transfer of the [Issued] [FungibleAsset] to the issue requester. */ + @InitiatedBy(IssuanceRequester::class) class Issuer(val otherParty: Party) : FlowLogic() { companion object { object AWAITING_REQUEST : ProgressTracker.Step("Awaiting issuance request") @@ -97,11 +94,5 @@ object IssuerFlow { // NOTE: CashFlow PayCash calls FinalityFlow which performs a Broadcast (which stores a local copy of the txn to the ledger) return moveTx } - - class Service(services: PluginServiceHub) { - init { - services.registerServiceFlow(IssuanceRequester::class.java, ::Issuer) - } - } } } \ No newline at end of file diff --git a/finance/src/test/kotlin/net/corda/flows/IssuerFlowTest.kt b/finance/src/test/kotlin/net/corda/flows/IssuerFlowTest.kt index 4721ca8aeb..4e23555c56 100644 --- a/finance/src/test/kotlin/net/corda/flows/IssuerFlowTest.kt +++ b/finance/src/test/kotlin/net/corda/flows/IssuerFlowTest.kt @@ -11,16 +11,17 @@ import net.corda.core.getOrThrow import net.corda.core.identity.Party import net.corda.core.map import net.corda.core.serialization.OpaqueBytes +import net.corda.core.toFuture import net.corda.core.transactions.SignedTransaction import net.corda.core.utilities.DUMMY_NOTARY import net.corda.flows.IssuerFlow.IssuanceRequester import net.corda.testing.BOC import net.corda.testing.MEGA_CORP -import net.corda.testing.initiateSingleShotFlow import net.corda.testing.ledger import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork.MockNode import org.junit.Test +import rx.Observable import java.util.* import kotlin.test.assertEquals import kotlin.test.assertFailsWith @@ -73,7 +74,6 @@ class IssuerFlowTest { @Test fun `test concurrent issuer flow`() { - net = MockNetwork(false, true) ledger { notaryNode = net.createNotaryNode(null, DUMMY_NOTARY.name) @@ -96,18 +96,19 @@ class IssuerFlowTest { } } - private fun runIssuerAndIssueRequester(issuerNode: MockNode, issueToNode: MockNode, + private fun runIssuerAndIssueRequester(issuerNode: MockNode, + issueToNode: MockNode, amount: Amount, - party: Party, ref: OpaqueBytes): RunResult { + party: Party, + ref: OpaqueBytes): RunResult { val issueToPartyAndRef = party.ref(ref) - val issuerFuture = issuerNode.initiateSingleShotFlow(IssuerFlow.IssuanceRequester::class) { _ -> - IssuerFlow.Issuer(party) - }.map { it.stateMachine } + val issuerFlows: Observable = issuerNode.registerInitiatedFlow(IssuerFlow.Issuer::class.java) + val firstIssuerFiber = issuerFlows.toFuture().map { it.stateMachine } val issueRequest = IssuanceRequester(amount, party, issueToPartyAndRef.reference, issuerNode.info.legalIdentity) val issueRequestResultFuture = issueToNode.services.startFlow(issueRequest).resultFuture - return IssuerFlowTest.RunResult(issuerFuture, issueRequestResultFuture) + return IssuerFlowTest.RunResult(firstIssuerFiber, issueRequestResultFuture) } private data class RunResult( diff --git a/node/build.gradle b/node/build.gradle index 4dc0c02b44..5676649bce 100644 --- a/node/build.gradle +++ b/node/build.gradle @@ -46,6 +46,14 @@ processResources { from file("$rootDir/config/dev/log4j2.xml") } +processIntegrationTestResources { + // Build one of the demos so that we can test CorDapp scanning in CordappScanningTest. It doesn't matter which demo + // we use, just make sure the test is updated accordingly. + from(project(':samples:trader-demo').tasks.jar) { + rename 'trader-demo-(.*)', 'trader-demo.jar' + } +} + // To find potential version conflicts, run "gradle htmlDependencyReport" and then look in // build/reports/project/dependencies/index.html for green highlighted parts of the tree. @@ -153,7 +161,7 @@ dependencies { compile "io.requery:requery-kotlin:$requery_version" // FastClasspathScanner: classpath scanning - compile 'io.github.lukehutch:fast-classpath-scanner:2.0.20' + compile 'io.github.lukehutch:fast-classpath-scanner:2.0.21' // Integration test helpers integrationTestCompile "junit:junit:$junit_version" diff --git a/node/src/integration-test/kotlin/net/corda/node/CordappScanningTest.kt b/node/src/integration-test/kotlin/net/corda/node/CordappScanningTest.kt new file mode 100644 index 0000000000..ba98a0adbc --- /dev/null +++ b/node/src/integration-test/kotlin/net/corda/node/CordappScanningTest.kt @@ -0,0 +1,82 @@ +package net.corda.node + +import co.paralleluniverse.fibers.Suspendable +import com.google.common.util.concurrent.Futures +import net.corda.core.copyToDirectory +import net.corda.core.createDirectories +import net.corda.core.div +import net.corda.core.flows.FlowLogic +import net.corda.core.flows.InitiatedBy +import net.corda.core.flows.InitiatingFlow +import net.corda.core.flows.StartableByRPC +import net.corda.core.getOrThrow +import net.corda.core.identity.Party +import net.corda.core.messaging.startFlow +import net.corda.core.utilities.ALICE +import net.corda.core.utilities.BOB +import net.corda.core.utilities.unwrap +import net.corda.node.driver.driver +import net.corda.node.services.startFlowPermission +import net.corda.nodeapi.User +import org.assertj.core.api.Assertions.assertThat +import org.junit.Test +import java.nio.file.Paths + +class CordappScanningTest { + @Test + fun `CorDapp jar in plugins directory is scanned`() { + // If the CorDapp jar does't exist then run the integrationTestClasses gradle task + val cordappJar = Paths.get(javaClass.getResource("/trader-demo.jar").toURI()) + driver { + val pluginsDir = (baseDirectory(ALICE.name) / "plugins").createDirectories() + cordappJar.copyToDirectory(pluginsDir) + + val user = User("u", "p", emptySet()) + val alice = startNode(ALICE.name, rpcUsers = listOf(user)).getOrThrow() + val rpc = alice.rpcClientToNode().start(user.username, user.password) + // If the CorDapp wasn't scanned then SellerFlow won't have been picked up as an RPC flow + assertThat(rpc.proxy.registeredFlows()).contains("net.corda.traderdemo.flow.SellerFlow") + } + } + + @Test + fun `empty plugins directory`() { + driver { + val baseDirectory = baseDirectory(ALICE.name) + (baseDirectory / "plugins").createDirectories() + startNode(ALICE.name).getOrThrow() + } + } + + @Test + fun `sub-classed initiated flow pointing to the same initiating flow as its super-class`() { + val user = User("u", "p", setOf(startFlowPermission())) + driver(systemProperties = mapOf("net.corda.node.cordapp.scan.package" to "net.corda.node")) { + val (alice, bob) = Futures.allAsList( + startNode(ALICE.name, rpcUsers = listOf(user)), + startNode(BOB.name)).getOrThrow() + val initiatedFlowClass = alice.rpcClientToNode() + .start(user.username, user.password) + .proxy + .startFlow(::ReceiveFlow, bob.nodeInfo.legalIdentity) + .returnValue + assertThat(initiatedFlowClass.getOrThrow()).isEqualTo(SendSubClassFlow::class.java.name) + } + } + + @StartableByRPC + @InitiatingFlow + class ReceiveFlow(val otherParty: Party) : FlowLogic() { + @Suspendable + override fun call(): String = receive(otherParty).unwrap { it } + } + + @InitiatedBy(ReceiveFlow::class) + open class SendClassFlow(val otherParty: Party) : FlowLogic() { + @Suspendable + override fun call() = send(otherParty, javaClass.name) + } + + @InitiatedBy(ReceiveFlow::class) + class SendSubClassFlow(otherParty: Party) : SendClassFlow(otherParty) +} diff --git a/node/src/integration-test/kotlin/net/corda/services/messaging/MQSecurityTest.kt b/node/src/integration-test/kotlin/net/corda/services/messaging/MQSecurityTest.kt index caf54da6da..7086d1a3db 100644 --- a/node/src/integration-test/kotlin/net/corda/services/messaging/MQSecurityTest.kt +++ b/node/src/integration-test/kotlin/net/corda/services/messaging/MQSecurityTest.kt @@ -6,6 +6,7 @@ import net.corda.client.rpc.CordaRPCClient import net.corda.core.crypto.generateKeyPair import net.corda.core.crypto.toBase58String import net.corda.core.flows.FlowLogic +import net.corda.core.flows.InitiatedBy import net.corda.core.flows.InitiatingFlow import net.corda.core.getOrThrow import net.corda.core.identity.Party @@ -216,7 +217,7 @@ abstract class MQSecurityTest : NodeBasedTest() { private fun startBobAndCommunicateWithAlice(): Party { val bob = startNode(BOB.name).getOrThrow() - bob.services.registerServiceFlow(SendFlow::class.java, ::ReceiveFlow) + bob.registerInitiatedFlow(ReceiveFlow::class.java) val bobParty = bob.info.legalIdentity // Perform a protocol exchange to force the peer queue to be created alice.services.startFlow(SendFlow(bobParty, 0)).resultFuture.getOrThrow() @@ -229,6 +230,7 @@ abstract class MQSecurityTest : NodeBasedTest() { override fun call() = send(otherParty, payload) } + @InitiatedBy(SendFlow::class) private class ReceiveFlow(val otherParty: Party) : FlowLogic() { @Suspendable override fun call() = receive(otherParty).unwrap { it } diff --git a/node/src/main/kotlin/net/corda/node/driver/Driver.kt b/node/src/main/kotlin/net/corda/node/driver/Driver.kt index 65ae64bd26..0d9bfe3273 100644 --- a/node/src/main/kotlin/net/corda/node/driver/Driver.kt +++ b/node/src/main/kotlin/net/corda/node/driver/Driver.kt @@ -7,6 +7,8 @@ import com.google.common.util.concurrent.* import com.typesafe.config.Config import com.typesafe.config.ConfigRenderOptions import net.corda.client.rpc.CordaRPCClient +import net.corda.cordform.CordformContext +import net.corda.cordform.CordformNode import net.corda.core.* import net.corda.core.crypto.X509Utilities import net.corda.core.crypto.appendToCommonName @@ -19,10 +21,6 @@ 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 @@ -30,8 +28,6 @@ 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 net.corda.core.internal.ShutdownHook import net.corda.core.internal.addShutdownHook import okhttp3.OkHttpClient @@ -39,6 +35,7 @@ import okhttp3.Request import org.bouncycastle.asn1.x500.X500Name import org.slf4j.Logger import java.io.File +import java.io.File.pathSeparator import java.net.* import java.nio.file.Path import java.nio.file.Paths @@ -614,7 +611,7 @@ class DriverDSL( } } - override fun baseDirectory(nodeName: X500Name) = driverDirectory / nodeName.commonName.replace(WHITESPACE, "") + override fun baseDirectory(nodeName: X500Name): Path = driverDirectory / nodeName.commonName.replace(WHITESPACE, "") override fun startDedicatedNetworkMapService(): ListenableFuture { val debugPort = if (isDebug) debugPortAllocation.nextPort() else null @@ -679,6 +676,8 @@ class DriverDSL( "-javaagent:$quasarJarPath" val loggingLevel = if (debugPort == null) "INFO" else "DEBUG" + val pluginsDirectory = nodeConf.baseDirectory / "plugins" + ProcessUtilities.startJavaProcess( className = "net.corda.node.Corda", // cannot directly get class for this, so just use string arguments = listOf( @@ -686,6 +685,8 @@ class DriverDSL( "--logging-level=$loggingLevel", "--no-local-shell" ), + // Like the capsule, include the node's plugin directory + classpath = "${ProcessUtilities.defaultClassPath}$pathSeparator$pluginsDirectory/*", jdwpPort = debugPort, extraJvmArguments = extraJvmArguments, errorLogPath = nodeConf.baseDirectory / LOGS_DIRECTORY_NAME / "error.log", diff --git a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt index 60cd48af1b..c87b0361b0 100644 --- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt @@ -2,16 +2,15 @@ package net.corda.node.internal import com.codahale.metrics.MetricRegistry import com.google.common.annotations.VisibleForTesting +import com.google.common.collect.MutableClassToInstanceMap import com.google.common.util.concurrent.ListenableFuture import com.google.common.util.concurrent.MoreExecutors import com.google.common.util.concurrent.SettableFuture import io.github.lukehutch.fastclasspathscanner.FastClasspathScanner +import io.github.lukehutch.fastclasspathscanner.scanner.ScanResult import net.corda.core.* import net.corda.core.crypto.* -import net.corda.core.flows.FlowInitiator -import net.corda.core.flows.FlowLogic -import net.corda.core.flows.InitiatingFlow -import net.corda.core.flows.StartableByRPC +import net.corda.core.flows.* import net.corda.core.identity.Party import net.corda.core.messaging.CordaRPCOps import net.corda.core.messaging.RPCOps @@ -19,6 +18,7 @@ import net.corda.core.messaging.SingleMessageRecipient import net.corda.core.node.* import net.corda.core.node.services.* import net.corda.core.node.services.NetworkMapCache.MapChange +import net.corda.core.serialization.SerializeAsToken import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.core.serialization.deserialize import net.corda.core.transactions.SignedTransaction @@ -45,7 +45,7 @@ import net.corda.node.services.schema.HibernateObserver import net.corda.node.services.schema.NodeSchemaService import net.corda.node.services.statemachine.FlowStateMachineImpl import net.corda.node.services.statemachine.StateMachineManager -import net.corda.node.services.statemachine.flowVersion +import net.corda.node.services.statemachine.flowVersionAndInitiatingClass import net.corda.node.services.transactions.* import net.corda.node.services.vault.CashBalanceAsMetricsObserver import net.corda.node.services.vault.NodeVaultService @@ -60,9 +60,11 @@ import org.bouncycastle.cert.X509CertificateHolder import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter import org.jetbrains.exposed.sql.Database import org.slf4j.Logger +import rx.Observable import java.io.IOException import java.lang.reflect.Modifier.* -import java.net.URL +import java.net.JarURLConnection +import java.net.URI import java.nio.file.FileAlreadyExistsException import java.nio.file.Path import java.nio.file.Paths @@ -73,6 +75,7 @@ import java.util.* import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ExecutorService import java.util.concurrent.TimeUnit.SECONDS +import java.util.stream.Collectors.toList import kotlin.collections.ArrayList import kotlin.reflect.KClass import net.corda.core.crypto.generateKeyPair as cryptoGenerateKeyPair @@ -106,7 +109,8 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, // low-performance prototyping period. protected abstract val serverThread: AffinityExecutor - protected val serviceFlowFactories = ConcurrentHashMap, ServiceFlowInfo>() + private val cordappServices = MutableClassToInstanceMap.create() + private val flowFactories = ConcurrentHashMap>, InitiatedFlowFactory<*>>() protected val partyKeys = mutableSetOf() val services = object : ServiceHubInternal() { @@ -122,6 +126,12 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, override val schemaService: SchemaService get() = schemas override val transactionVerifierService: TransactionVerifierService get() = txVerifierService override val auditService: AuditService get() = auditService + + override fun cordaService(type: Class): T { + require(type.isAnnotationPresent(CordaService::class.java)) { "${type.name} is not a Corda service" } + return cordappServices.getInstance(type) ?: throw IllegalArgumentException("Corda service ${type.name} does not exist") + } + override val rpcFlows: List>> get() = this@AbstractNode.rpcFlows // Internal only @@ -131,17 +141,8 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, return serverThread.fetchFrom { smm.add(logic, flowInitiator) } } - override fun registerServiceFlow(initiatingFlowClass: Class>, serviceFlowFactory: (Party) -> FlowLogic<*>) { - require(initiatingFlowClass !in serviceFlowFactories) { - "${initiatingFlowClass.name} has already been used to register a service flow" - } - val info = ServiceFlowInfo.CorDapp(initiatingFlowClass.flowVersion, serviceFlowFactory) - log.info("Registering service flow for ${initiatingFlowClass.name}: $info") - serviceFlowFactories[initiatingFlowClass] = info - } - - override fun getServiceFlowFactory(clientFlowClass: Class>): ServiceFlowInfo? { - return serviceFlowFactories[clientFlowClass] + override fun getFlowFactory(initiatingFlowClass: Class>): InitiatedFlowFactory<*>? { + return flowFactories[initiatingFlowClass] } override fun recordTransactions(txs: Iterable) { @@ -167,15 +168,11 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, lateinit var scheduler: NodeSchedulerService lateinit var schemas: SchemaService lateinit var auditService: AuditService - val customServices: ArrayList = ArrayList() protected val runOnStop: ArrayList = ArrayList() lateinit var database: Database protected var dbCloser: Runnable? = null private lateinit var rpcFlows: List>> - /** Locates and returns a service of the given type if loaded, or throws an exception if not found. */ - inline fun findService() = customServices.filterIsInstance().single() - var isPreviousCheckpointsPresent = false private set @@ -217,7 +214,6 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, val tokenizableServices = makeServices() smm = StateMachineManager(services, - listOf(tokenizableServices), checkpointStorage, serverThread, database, @@ -240,22 +236,24 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, startMessagingService(rpcOps) installCoreFlows() - fun Class>.isUserInvokable(): Boolean { - return isPublic(modifiers) && !isLocalClass && !isAnonymousClass && (!isMemberClass || isStatic(modifiers)) + val scanResult = scanCorDapps() + if (scanResult != null) { + val cordappServices = installCordaServices(scanResult) + tokenizableServices.addAll(cordappServices) + registerInitiatedFlows(scanResult) + rpcFlows = findRPCFlows(scanResult) + } else { + rpcFlows = emptyList() } - val flows = scanForFlows() - rpcFlows = flows.filter { it.isUserInvokable() && it.isAnnotationPresent(StartableByRPC::class.java) } + - // Add any core flows here - listOf(ContractUpgradeFlow::class.java, - // TODO Remove all Cash flows from default list once they are split into separate CorDapp. - CashIssueFlow::class.java, - CashExitFlow::class.java, - CashPaymentFlow::class.java) + // TODO Remove this once the cash stuff is in its own CorDapp + registerInitiatedFlow(IssuerFlow.Issuer::class.java) + + initUploaders() runOnStop += Runnable { net.stop() } _networkMapRegistrationFuture.setFuture(registerWithNetworkMapIfConfigured()) - smm.start() + smm.start(tokenizableServices) // Shut down the SMM so no Fibers are scheduled. runOnStop += Runnable { smm.stop(acceptableLiveFiberCountOnStop()) } scheduler.start() @@ -264,18 +262,142 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, return this } + private fun installCordaServices(scanResult: ScanResult): List { + return scanResult.getClassesWithAnnotation(SerializeAsToken::class, CordaService::class).mapNotNull { + try { + installCordaService(it) + } catch (e: NoSuchMethodException) { + log.error("${it.name}, as a Corda service, must have a constructor with a single parameter " + + "of type ${PluginServiceHub::class.java.name}") + null + } catch (e: Exception) { + log.error("Unable to install Corda service ${it.name}", e) + null + } + } + } + + /** + * Use this method to install your Corda services in your tests. This is automatically done by the node when it + * starts up for all classes it finds which are annotated with [CordaService]. + */ + fun installCordaService(clazz: Class): T { + clazz.requireAnnotation() + val ctor = clazz.getDeclaredConstructor(PluginServiceHub::class.java).apply { isAccessible = true } + val service = ctor.newInstance(services) + cordappServices.putInstance(clazz, service) + log.info("Installed ${clazz.name} Corda service") + return service + } + + private inline fun Class<*>.requireAnnotation(): A { + return requireNotNull(getDeclaredAnnotation(A::class.java)) { "$name needs to be annotated with ${A::class.java.name}" } + } + + private fun registerInitiatedFlows(scanResult: ScanResult) { + scanResult + .getClassesWithAnnotation(FlowLogic::class, InitiatedBy::class) + // First group by the initiating flow class in case there are multiple mappings + .groupBy { it.requireAnnotation().value.java } + .map { (initiatingFlow, initiatedFlows) -> + val sorted = initiatedFlows.sortedWith(FlowTypeHierarchyComparator(initiatingFlow)) + if (sorted.size > 1) { + log.warn("${initiatingFlow.name} has been specified as the inititating flow by multiple flows " + + "in the same type hierarchy: ${sorted.joinToString { it.name }}. Choosing the most " + + "specific sub-type for registration: ${sorted[0].name}.") + } + sorted[0] + } + .forEach { + try { + registerInitiatedFlowInternal(it, track = false) + } catch (e: NoSuchMethodException) { + log.error("${it.name}, as an initiated flow, must have a constructor with a single parameter " + + "of type ${Party::class.java.name}") + } catch (e: Exception) { + log.error("Unable to register initiated flow ${it.name}", e) + } + } + } + + private class FlowTypeHierarchyComparator(val initiatingFlow: Class>) : Comparator>> { + override fun compare(o1: Class>, o2: Class>): Int { + return if (o1 == o2) { + 0 + } else if (o1.isAssignableFrom(o2)) { + 1 + } else if (o2.isAssignableFrom(o1)) { + -1 + } else { + throw IllegalArgumentException("${initiatingFlow.name} has been specified as the initiating flow by " + + "both ${o1.name} and ${o2.name}") + } + } + } + + /** + * Use this method to register your initiated flows in your tests. This is automatically done by the node when it + * starts up for all [FlowLogic] classes it finds which are annotated with [InitiatedBy]. + * @return An [Observable] of the initiated flows started by counter-parties. + */ + fun > registerInitiatedFlow(initiatedFlowClass: Class): Observable { + return registerInitiatedFlowInternal(initiatedFlowClass, track = true) + } + + private fun > registerInitiatedFlowInternal(initiatedFlow: Class, track: Boolean): Observable { + val ctor = initiatedFlow.getDeclaredConstructor(Party::class.java).apply { isAccessible = true } + val initiatingFlow = initiatedFlow.requireAnnotation().value.java + val (version, classWithAnnotation) = initiatingFlow.flowVersionAndInitiatingClass + require(classWithAnnotation == initiatingFlow) { + "${InitiatingFlow::class.java.name} must be annotated on ${initiatingFlow.name} and not on a super-type" + } + val flowFactory = InitiatedFlowFactory.CorDapp(version, { ctor.newInstance(it) }) + val observable = registerFlowFactory(initiatingFlow, flowFactory, initiatedFlow, track) + log.info("Registered ${initiatingFlow.name} to initiate ${initiatedFlow.name} (version $version)") + return observable + } + + @VisibleForTesting + fun > registerFlowFactory(initiatingFlowClass: Class>, + flowFactory: InitiatedFlowFactory, + initiatedFlowClass: Class, + track: Boolean): Observable { + val observable = if (track) { + smm.changes.filter { it is StateMachineManager.Change.Add }.map { it.logic }.ofType(initiatedFlowClass) + } else { + Observable.empty() + } + flowFactories[initiatingFlowClass] = flowFactory + return observable + } + + private fun findRPCFlows(scanResult: ScanResult): List>> { + fun Class>.isUserInvokable(): Boolean { + return isPublic(modifiers) && !isLocalClass && !isAnonymousClass && (!isMemberClass || isStatic(modifiers)) + } + + return scanResult.getClassesWithAnnotation(FlowLogic::class, StartableByRPC::class).filter { it.isUserInvokable() } + + // Add any core flows here + listOf( + ContractUpgradeFlow::class.java, + // TODO Remove all Cash flows from default list once they are split into separate CorDapp. + CashIssueFlow::class.java, + CashExitFlow::class.java, + CashPaymentFlow::class.java) + } + /** * Installs a flow that's core to the Corda platform. Unlike CorDapp flows which are versioned individually using * [InitiatingFlow.version], core flows have the same version as the node's platform version. To cater for backwards - * compatibility [serviceFlowFactory] provides a second parameter which is the platform version of the initiating party. + * compatibility [flowFactory] provides a second parameter which is the platform version of the initiating party. * @suppress */ @VisibleForTesting - fun installCoreFlow(clientFlowClass: KClass>, serviceFlowFactory: (Party, Int) -> FlowLogic<*>) { - require(clientFlowClass.java.flowVersion == 1) { + fun installCoreFlow(clientFlowClass: KClass>, flowFactory: (Party, Int) -> FlowLogic<*>) { + require(clientFlowClass.java.flowVersionAndInitiatingClass.first == 1) { "${InitiatingFlow::class.java.name}.version not applicable for core flows; their version is the node's platform version" } - serviceFlowFactories[clientFlowClass.java] = ServiceFlowInfo.Core(serviceFlowFactory) + flowFactories[clientFlowClass.java] = InitiatedFlowFactory.Core(flowFactory) log.debug { "Installed core flow ${clientFlowClass.java.name}" } } @@ -313,61 +435,62 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, val tokenizableServices = mutableListOf(storage, net, vault, keyManagement, identity, platformClock, scheduler) makeAdvertisedServices(tokenizableServices) - customServices.clear() - customServices.addAll(makePluginServices(tokenizableServices)) - - initUploaders(storageServices) return tokenizableServices } - private fun scanForFlows(): List>> { - val pluginsDir = configuration.baseDirectory / "plugins" - log.info("Scanning plugins in $pluginsDir ...") - if (!pluginsDir.exists()) return emptyList() - - val pluginJars = pluginsDir.list { - it.filter { it.isRegularFile() && it.toString().endsWith(".jar") }.toArray() + private fun scanCorDapps(): ScanResult? { + val scanPackage = System.getProperty("net.corda.node.cordapp.scan.package") + val paths = if (scanPackage != null) { + // This is purely for integration tests so that classes defined in the test can automatically be picked up + check(configuration.devMode) { "Package scanning can only occur in dev mode" } + val resource = scanPackage.replace('.', '/') + javaClass.classLoader.getResources(resource) + .asSequence() + .map { + val uri = if (it.protocol == "jar") { + (it.openConnection() as JarURLConnection).jarFileURL.toURI() + } else { + URI(it.toExternalForm().removeSuffix(resource)) + } + Paths.get(uri) + } + .toList() + } else { + val pluginsDir = configuration.baseDirectory / "plugins" + if (!pluginsDir.exists()) return null + pluginsDir.list { + it.filter { it.isRegularFile() && it.toString().endsWith(".jar") }.collect(toList()) + } } - if (pluginJars.isEmpty()) return emptyList() + log.info("Scanning CorDapps in $paths") - val scanResult = FastClasspathScanner().overrideClasspath(*pluginJars).scan() // This will only scan the plugin jars and nothing else + // This will only scan the plugin jars and nothing else + return if (paths.isNotEmpty()) FastClasspathScanner().overrideClasspath(paths).scan() else null + } - fun loadFlowClass(className: String): Class>? { + private fun ScanResult.getClassesWithAnnotation(type: KClass, annotation: KClass): List> { + fun loadClass(className: String): Class? { return try { // TODO Make sure this is loaded by the correct class loader - @Suppress("UNCHECKED_CAST") - Class.forName(className, false, javaClass.classLoader) as Class> + Class.forName(className, false, javaClass.classLoader).asSubclass(type.java) + } catch (e: ClassCastException) { + log.warn("As $className is annotated with ${annotation.qualifiedName} it must be a sub-type of ${type.java.name}") + null } catch (e: Exception) { - log.warn("Unable to load flow class $className", e) + log.warn("Unable to load class $className", e) null } } - val flowClasses = scanResult.getNamesOfSubclassesOf(FlowLogic::class.java) - .mapNotNull { loadFlowClass(it) } + return getNamesOfClassesWithAnnotation(annotation.java) + .mapNotNull { loadClass(it) } .filterNot { isAbstract(it.modifiers) } - - fun URL.pluginName(): String { - return try { - Paths.get(toURI()).fileName.toString() - } catch (e: Exception) { - toString() - } - } - - flowClasses.groupBy { - scanResult.classNameToClassInfo[it.name]!!.classpathElementURLs.first() - }.forEach { url, classes -> - log.info("Found flows in plugin ${url.pluginName()}: ${classes.joinToString { it.name }}") - } - - return flowClasses } - private fun initUploaders(storageServices: Pair) { - val uploaders: List = listOf(storageServices.first.attachments as NodeAttachmentService) + - customServices.filterIsInstance(AcceptsFileUpload::class.java) + private fun initUploaders() { + val uploaders: List = listOf(storage.attachments as NodeAttachmentService) + + cordappServices.values.filterIsInstance(AcceptsFileUpload::class.java) (storage as StorageServiceImpl).initUploaders(uploaders) } @@ -433,12 +556,6 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, } } - private fun makePluginServices(tokenizableServices: MutableList): List { - val pluginServices = pluginRegistries.flatMap { it.servicePlugins }.map { it.apply(services) } - tokenizableServices.addAll(pluginServices) - return pluginServices - } - /** * Run any tasks that are needed to ensure the node is in a correct state before running start(). */ @@ -658,11 +775,6 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, } } -sealed class ServiceFlowInfo { - data class Core(val factory: (Party, Int) -> FlowLogic<*>) : ServiceFlowInfo() - data class CorDapp(val version: Int, val factory: (Party) -> FlowLogic<*>) : ServiceFlowInfo() -} - private class KeyStoreWrapper(private val storePath: Path, private val storePassword: String) { private val keyStore = KeyStoreUtilities.loadKeyStore(storePath, storePassword) diff --git a/node/src/main/kotlin/net/corda/node/internal/InitiatedFlowFactory.kt b/node/src/main/kotlin/net/corda/node/internal/InitiatedFlowFactory.kt new file mode 100644 index 0000000000..06a0a7cc61 --- /dev/null +++ b/node/src/main/kotlin/net/corda/node/internal/InitiatedFlowFactory.kt @@ -0,0 +1,27 @@ +package net.corda.node.internal + +import net.corda.core.flows.FlowLogic +import net.corda.core.identity.Party +import net.corda.node.services.statemachine.SessionInit + +interface InitiatedFlowFactory> { + fun createFlow(platformVersion: Int, otherParty: Party, sessionInit: SessionInit): F + + data class Core>(val factory: (Party, Int) -> F) : InitiatedFlowFactory { + override fun createFlow(platformVersion: Int, otherParty: Party, sessionInit: SessionInit): F { + return factory(otherParty, platformVersion) + } + } + + data class CorDapp>(val version: Int, val factory: (Party) -> F) : InitiatedFlowFactory { + override fun createFlow(platformVersion: Int, otherParty: Party, sessionInit: SessionInit): F { + // TODO Add support for multiple versions of the same flow when CorDapps are loaded in separate class loaders + if (sessionInit.flowVerison == version) return factory(otherParty) + throw SessionRejectException( + "Version not supported", + "Version mismatch - ${sessionInit.initiatingFlowClass} is only registered for version $version") + } + } +} + +class SessionRejectException(val rejectMessage: String, val logMessage: String) : Exception() diff --git a/node/src/main/kotlin/net/corda/node/services/api/ServiceHubInternal.kt b/node/src/main/kotlin/net/corda/node/services/api/ServiceHubInternal.kt index e1af4b173a..805e23c3a8 100644 --- a/node/src/main/kotlin/net/corda/node/services/api/ServiceHubInternal.kt +++ b/node/src/main/kotlin/net/corda/node/services/api/ServiceHubInternal.kt @@ -13,7 +13,7 @@ import net.corda.core.node.services.TxWritableStorageService import net.corda.core.serialization.CordaSerializable import net.corda.core.transactions.SignedTransaction import net.corda.core.utilities.loggerFor -import net.corda.node.internal.ServiceFlowInfo +import net.corda.node.internal.InitiatedFlowFactory import net.corda.node.services.messaging.MessagingService import net.corda.node.services.statemachine.FlowLogicRefFactoryImpl import net.corda.node.services.statemachine.FlowStateMachineImpl @@ -47,7 +47,6 @@ interface NetworkMapCacheInternal : NetworkMapCache { /** For testing where the network map cache is manipulated marks the service as immediately ready. */ @VisibleForTesting fun runWithoutMapService() - } @CordaSerializable @@ -93,7 +92,6 @@ abstract class ServiceHubInternal : PluginServiceHub { * Starts an already constructed flow. Note that you must be on the server thread to call this method. [FlowInitiator] * defaults to [FlowInitiator.RPC] with username "Only For Testing". */ - // TODO Move it to test utils. @VisibleForTesting fun startFlow(logic: FlowLogic): FlowStateMachine = startFlow(logic, FlowInitiator.RPC("Only For Testing")) @@ -103,7 +101,6 @@ abstract class ServiceHubInternal : PluginServiceHub { */ abstract fun startFlow(logic: FlowLogic, flowInitiator: FlowInitiator): FlowStateMachineImpl - /** * Will check [logicType] and [args] against a whitelist and if acceptable then construct and initiate the flow. * Note that you must be on the server thread to call this method. [flowInitiator] points how flow was started, @@ -122,5 +119,5 @@ abstract class ServiceHubInternal : PluginServiceHub { return startFlow(logic, flowInitiator) } - abstract fun getServiceFlowFactory(clientFlowClass: Class>): ServiceFlowInfo? + abstract fun getFlowFactory(initiatingFlowClass: Class>): InitiatedFlowFactory<*>? } \ No newline at end of file diff --git a/node/src/main/kotlin/net/corda/node/services/statemachine/FlowStateMachineImpl.kt b/node/src/main/kotlin/net/corda/node/services/statemachine/FlowStateMachineImpl.kt index 309530bb32..a43c0849d3 100644 --- a/node/src/main/kotlin/net/corda/node/services/statemachine/FlowStateMachineImpl.kt +++ b/node/src/main/kotlin/net/corda/node/services/statemachine/FlowStateMachineImpl.kt @@ -8,9 +8,9 @@ import com.google.common.util.concurrent.ListenableFuture import com.google.common.util.concurrent.SettableFuture import net.corda.core.ErrorOr import net.corda.core.abbreviate -import net.corda.core.identity.Party import net.corda.core.crypto.SecureHash import net.corda.core.flows.* +import net.corda.core.identity.Party import net.corda.core.random63BitValue import net.corda.core.transactions.SignedTransaction import net.corda.core.utilities.ProgressTracker @@ -27,7 +27,6 @@ import org.jetbrains.exposed.sql.Transaction import org.jetbrains.exposed.sql.transactions.TransactionManager import org.slf4j.Logger import org.slf4j.LoggerFactory -import java.lang.reflect.Modifier import java.sql.Connection import java.sql.SQLException import java.util.* @@ -322,9 +321,8 @@ class FlowStateMachineImpl(override val id: StateMachineRunId, logger.trace { "Initiating a new session with $otherParty" } val session = FlowSession(sessionFlow, random63BitValue(), null, FlowSessionState.Initiating(otherParty), retryable) openSessions[Pair(sessionFlow, otherParty)] = session - // We get the top-most concrete class object to cater for the case where the client flow is customised via a sub-class - val clientFlowClass = sessionFlow.topConcreteFlowClass - val sessionInit = SessionInit(session.ourSessionId, clientFlowClass, clientFlowClass.flowVersion, firstPayload) + val (version, initiatingFlowClass) = sessionFlow.javaClass.flowVersionAndInitiatingClass + val sessionInit = SessionInit(session.ourSessionId, initiatingFlowClass, version, firstPayload) sendInternal(session, sessionInit) if (waitForConfirmation) { session.waitForConfirmation() @@ -332,15 +330,6 @@ class FlowStateMachineImpl(override val id: StateMachineRunId, return session } - @Suppress("UNCHECKED_CAST") - private val FlowLogic<*>.topConcreteFlowClass: Class> get() { - var current: Class> = javaClass - while (!Modifier.isAbstract(current.superclass.modifiers)) { - current = current.superclass as Class> - } - return current - } - @Suspendable private fun waitForMessage(receiveRequest: ReceiveRequest): ReceivedSessionMessage { return receiveRequest.suspendAndExpectReceive().confirmReceiveType(receiveRequest) @@ -460,10 +449,19 @@ class FlowStateMachineImpl(override val id: StateMachineRunId, } } -val Class>.flowVersion: Int get() { - val annotation = requireNotNull(getAnnotation(InitiatingFlow::class.java)) { - "$name as the initiating flow must be annotated with ${InitiatingFlow::class.java.name}" +@Suppress("UNCHECKED_CAST") +val Class>.flowVersionAndInitiatingClass: Pair>> get() { + var current: Class<*> = this + var found: Pair>>? = null + while (true) { + val annotation = current.getDeclaredAnnotation(InitiatingFlow::class.java) + if (annotation != null) { + if (found != null) throw IllegalArgumentException("${InitiatingFlow::class.java.name} can only be annotated once") + require(annotation.version > 0) { "Flow versions have to be greater or equal to 1" } + found = annotation.version to (current as Class>) + } + current = current.superclass + ?: return found + ?: throw IllegalArgumentException("$name as an initiating flow must be annotated with ${InitiatingFlow::class.java.name}") } - require(annotation.version > 0) { "Flow versions have to be greater or equal to 1" } - return annotation.version } diff --git a/node/src/main/kotlin/net/corda/node/services/statemachine/SessionMessage.kt b/node/src/main/kotlin/net/corda/node/services/statemachine/SessionMessage.kt index dcfb5621b4..9f35c9eace 100644 --- a/node/src/main/kotlin/net/corda/node/services/statemachine/SessionMessage.kt +++ b/node/src/main/kotlin/net/corda/node/services/statemachine/SessionMessage.kt @@ -15,7 +15,7 @@ import net.corda.core.utilities.UntrustworthyData interface SessionMessage data class SessionInit(val initiatorSessionId: Long, - val clientFlowClass: Class>, + val initiatingFlowClass: Class>, val flowVerison: Int, val firstPayload: Any?) : SessionMessage diff --git a/node/src/main/kotlin/net/corda/node/services/statemachine/StateMachineManager.kt b/node/src/main/kotlin/net/corda/node/services/statemachine/StateMachineManager.kt index c20c5d84c2..db7d34b490 100644 --- a/node/src/main/kotlin/net/corda/node/services/statemachine/StateMachineManager.kt +++ b/node/src/main/kotlin/net/corda/node/services/statemachine/StateMachineManager.kt @@ -15,14 +15,14 @@ import com.google.common.collect.HashMultimap import com.google.common.util.concurrent.ListenableFuture import io.requery.util.CloseableIterator import net.corda.core.* -import net.corda.core.identity.Party import net.corda.core.crypto.SecureHash import net.corda.core.flows.* +import net.corda.core.identity.Party import net.corda.core.serialization.* import net.corda.core.utilities.debug import net.corda.core.utilities.loggerFor import net.corda.core.utilities.trace -import net.corda.node.internal.ServiceFlowInfo +import net.corda.node.internal.SessionRejectException import net.corda.node.services.api.Checkpoint import net.corda.node.services.api.CheckpointStorage import net.corda.node.services.api.ServiceHubInternal @@ -61,7 +61,6 @@ import javax.annotation.concurrent.ThreadSafe */ @ThreadSafe class StateMachineManager(val serviceHub: ServiceHubInternal, - tokenizableServices: List, val checkpointStorage: CheckpointStorage, val executor: AffinityExecutor, val database: Database, @@ -147,7 +146,7 @@ class StateMachineManager(val serviceHub: ServiceHubInternal, private val recentlyClosedSessions = ConcurrentHashMap() // Context for tokenized services in checkpoints - private val serializationContext = SerializeAsTokenContext(tokenizableServices, quasarKryoPool, serviceHub) + private lateinit var serializationContext: SerializeAsTokenContext /** Returns a list of all state machines executing the given flow logic at the top level (subflows do not count) */ fun

, T> findStateMachines(flowClass: Class

): List>> { @@ -171,7 +170,8 @@ class StateMachineManager(val serviceHub: ServiceHubInternal, */ val changes: Observable = mutex.content.changesPublisher.wrapWithDatabaseTransaction() - fun start() { + fun start(tokenizableServices: List) { + serializationContext = SerializeAsTokenContext(tokenizableServices, quasarKryoPool, serviceHub) restoreFibersFromCheckpoints() listenToLedgerTransactions() serviceHub.networkMapCache.mapServiceRegistered.then(executor) { resumeRestoredFibers() } @@ -345,28 +345,15 @@ class StateMachineManager(val serviceHub: ServiceHubInternal, fun sendSessionReject(message: String) = sendSessionMessage(sender, SessionReject(otherPartySessionId, message)) - val serviceFlowInfo = serviceHub.getServiceFlowFactory(sessionInit.clientFlowClass) - if (serviceFlowInfo == null) { - logger.warn("${sessionInit.clientFlowClass} has not been registered with a service flow: $sessionInit") - sendSessionReject("${sessionInit.clientFlowClass.name} has not been registered with a service flow") + val initiatedFlowFactory = serviceHub.getFlowFactory(sessionInit.initiatingFlowClass) + if (initiatedFlowFactory == null) { + logger.warn("${sessionInit.initiatingFlowClass} has not been registered: $sessionInit") + sendSessionReject("${sessionInit.initiatingFlowClass.name} has not been registered with a service flow") return } val session = try { - val flow = when (serviceFlowInfo) { - is ServiceFlowInfo.CorDapp -> { - // TODO Add support for multiple versions of the same flow when CorDapps are loaded in separate class loaders - if (sessionInit.flowVerison != serviceFlowInfo.version) { - logger.warn("Version mismatch - ${sessionInit.clientFlowClass} is only registered for version " + - "${serviceFlowInfo.version}: $sessionInit") - sendSessionReject("Version not supported") - return - } - serviceFlowInfo.factory(sender) - } - is ServiceFlowInfo.Core -> serviceFlowInfo.factory(sender, receivedMessage.platformVersion) - } - + val flow = initiatedFlowFactory.createFlow(receivedMessage.platformVersion, sender, sessionInit) val fiber = createFiber(flow, FlowInitiator.Peer(sender)) val session = FlowSession(flow, random63BitValue(), sender, FlowSessionState.Initiated(sender, otherPartySessionId)) if (sessionInit.firstPayload != null) { @@ -376,6 +363,10 @@ class StateMachineManager(val serviceHub: ServiceHubInternal, fiber.openSessions[Pair(flow, sender)] = session updateCheckpoint(fiber) session + } catch (e: SessionRejectException) { + logger.warn("${e.logMessage}: $sessionInit") + sendSessionReject(e.rejectMessage) + return } catch (e: Exception) { logger.warn("Couldn't start flow session from $sessionInit", e) sendSessionReject("Unable to establish session") @@ -383,7 +374,7 @@ class StateMachineManager(val serviceHub: ServiceHubInternal, } sendSessionMessage(sender, SessionConfirm(otherPartySessionId, session.ourSessionId), session.fiber) - session.fiber.logger.debug { "Initiated by $sender using ${sessionInit.clientFlowClass.name}" } + session.fiber.logger.debug { "Initiated by $sender using ${sessionInit.initiatingFlowClass.name}" } session.fiber.logger.trace { "Initiated from $sessionInit on $session" } resumeFiber(session.fiber) } diff --git a/node/src/test/kotlin/net/corda/node/internal/NodeTest.kt b/node/src/test/kotlin/net/corda/node/internal/NodeTest.kt deleted file mode 100644 index 38a239f949..0000000000 --- a/node/src/test/kotlin/net/corda/node/internal/NodeTest.kt +++ /dev/null @@ -1,20 +0,0 @@ -package net.corda.node.internal - -import net.corda.core.createDirectories -import net.corda.core.crypto.commonName -import net.corda.core.div -import net.corda.core.getOrThrow -import net.corda.core.utilities.ALICE -import net.corda.core.utilities.WHITESPACE -import net.corda.testing.node.NodeBasedTest -import org.assertj.core.api.Assertions.assertThat -import org.junit.Test - -class NodeTest : NodeBasedTest() { - @Test - fun `empty plugins directory`() { - val baseDirectory = baseDirectory(ALICE.name) - (baseDirectory / "plugins").createDirectories() - startNode(ALICE.name).getOrThrow() - } -} diff --git a/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt b/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt index 0a59f2d54d..ed89f2e424 100644 --- a/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt +++ b/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt @@ -4,24 +4,18 @@ import co.paralleluniverse.fibers.Suspendable import net.corda.contracts.CommercialPaper import net.corda.contracts.asset.* import net.corda.contracts.testing.fillWithSomeTestCash +import net.corda.core.* import net.corda.core.contracts.* import net.corda.core.crypto.DigitalSignature import net.corda.core.crypto.SecureHash import net.corda.core.crypto.sign -import net.corda.core.days -import net.corda.core.flows.FlowLogic -import net.corda.core.flows.FlowStateMachine -import net.corda.core.flows.InitiatingFlow -import net.corda.core.flows.StateMachineRunId -import net.corda.core.getOrThrow +import net.corda.core.flows.* +import net.corda.core.identity.AbstractParty import net.corda.core.identity.AnonymousParty import net.corda.core.identity.Party -import net.corda.core.identity.AbstractParty -import net.corda.core.map import net.corda.core.messaging.SingleMessageRecipient import net.corda.core.node.NodeInfo import net.corda.core.node.services.* -import net.corda.core.rootCause import net.corda.core.serialization.serialize import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.TransactionBuilder @@ -86,9 +80,10 @@ class TwoPartyTradeFlowTests { net = MockNetwork(false, true) ledger { - val notaryNode = net.createNotaryNode(null, DUMMY_NOTARY.name) - val aliceNode = net.createPartyNode(notaryNode.info.address, ALICE.name) - val bobNode = net.createPartyNode(notaryNode.info.address, BOB.name) + val basketOfNodes = net.createSomeNodes(2) + val notaryNode = basketOfNodes.notaryNode + val aliceNode = basketOfNodes.partyNodes[0] + val bobNode = basketOfNodes.partyNodes[1] aliceNode.disableDBCloseOnStop() bobNode.disableDBCloseOnStop() @@ -137,8 +132,7 @@ class TwoPartyTradeFlowTests { aliceNode.disableDBCloseOnStop() bobNode.disableDBCloseOnStop() - val cashStates = - bobNode.database.transaction { + val cashStates = bobNode.database.transaction { bobNode.services.fillWithSomeTestCash(2000.DOLLARS, notaryNode.info.notaryIdentity, 3, 3) } @@ -239,7 +233,7 @@ class TwoPartyTradeFlowTests { }, true, BOB.name) // Find the future representing the result of this state machine again. - val bobFuture = bobNode.smm.findStateMachines(Buyer::class.java).single().second + val bobFuture = bobNode.smm.findStateMachines(BuyerAcceptor::class.java).single().second // And off we go again. net.runNetwork() @@ -489,25 +483,42 @@ class TwoPartyTradeFlowTests { sellerNode: MockNetwork.MockNode, buyerNode: MockNetwork.MockNode, assetToSell: StateAndRef): RunResult { - @InitiatingFlow - class SellerRunnerFlow(val buyer: Party, val notary: NodeInfo) : FlowLogic() { - @Suspendable - override fun call(): SignedTransaction = subFlow(Seller( - buyer, - notary, - assetToSell, - 1000.DOLLARS, - serviceHub.legalIdentityKey)) - } - sellerNode.services.identityService.registerIdentity(buyerNode.info.legalIdentity) buyerNode.services.identityService.registerIdentity(sellerNode.info.legalIdentity) - val buyerFuture = buyerNode.initiateSingleShotFlow(SellerRunnerFlow::class) { otherParty -> - Buyer(otherParty, notaryNode.info.notaryIdentity, 1000.DOLLARS, CommercialPaper.State::class.java) - }.map { it.stateMachine } - val seller = SellerRunnerFlow(buyerNode.info.legalIdentity, notaryNode.info) - val sellerResultFuture = sellerNode.services.startFlow(seller).resultFuture - return RunResult(buyerFuture, sellerResultFuture, seller.stateMachine.id) + val buyerFlows: Observable = buyerNode.registerInitiatedFlow(BuyerAcceptor::class.java) + val firstBuyerFiber = buyerFlows.toFuture().map { it.stateMachine } + val seller = SellerInitiator(buyerNode.info.legalIdentity, notaryNode.info, assetToSell, 1000.DOLLARS) + val sellerResult = sellerNode.services.startFlow(seller).resultFuture + return RunResult(firstBuyerFiber, sellerResult, seller.stateMachine.id) + } + + @InitiatingFlow + class SellerInitiator(val buyer: Party, + val notary: NodeInfo, + val assetToSell: StateAndRef, + val price: Amount) : FlowLogic() { + @Suspendable + override fun call(): SignedTransaction { + send(buyer, Pair(notary.notaryIdentity, price)) + return subFlow(Seller( + buyer, + notary, + assetToSell, + price, + serviceHub.legalIdentityKey)) + } + } + + @InitiatedBy(SellerInitiator::class) + class BuyerAcceptor(val seller: Party) : FlowLogic() { + @Suspendable + override fun call(): SignedTransaction { + val (notary, price) = receive>>(seller).unwrap { + require(serviceHub.networkMapCache.isNotary(it.first)) { "${it.first} is not a notary" } + it + } + return subFlow(Buyer(seller, notary, price, CommercialPaper.State::class.java)) + } } private fun LedgerDSL.runWithError( diff --git a/node/src/test/kotlin/net/corda/node/services/MockServiceHubInternal.kt b/node/src/test/kotlin/net/corda/node/services/MockServiceHubInternal.kt index e79a83b653..4b21b7fbd9 100644 --- a/node/src/test/kotlin/net/corda/node/services/MockServiceHubInternal.kt +++ b/node/src/test/kotlin/net/corda/node/services/MockServiceHubInternal.kt @@ -3,11 +3,11 @@ package net.corda.node.services import com.codahale.metrics.MetricRegistry import net.corda.core.flows.FlowInitiator import net.corda.core.flows.FlowLogic -import net.corda.core.identity.Party import net.corda.core.node.NodeInfo import net.corda.core.node.services.* +import net.corda.core.serialization.SerializeAsToken import net.corda.core.transactions.SignedTransaction -import net.corda.node.internal.ServiceFlowInfo +import net.corda.node.internal.InitiatedFlowFactory import net.corda.node.serialization.NodeClock import net.corda.node.services.api.* import net.corda.node.services.messaging.MessagingService @@ -67,11 +67,11 @@ open class MockServiceHubInternal( override fun recordTransactions(txs: Iterable) = recordTransactionsInternal(txStorageService, txs) + override fun cordaService(type: Class): T = throw UnsupportedOperationException() + override fun startFlow(logic: FlowLogic, flowInitiator: FlowInitiator): FlowStateMachineImpl { return smm.executor.fetchFrom { smm.add(logic, flowInitiator) } } - override fun registerServiceFlow(initiatingFlowClass: Class>, serviceFlowFactory: (Party) -> FlowLogic<*>) = Unit - - override fun getServiceFlowFactory(clientFlowClass: Class>): ServiceFlowInfo? = null + override fun getFlowFactory(initiatingFlowClass: Class>): InitiatedFlowFactory<*>? = null } diff --git a/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt b/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt index 28366cb7dd..caafeeda0c 100644 --- a/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt @@ -92,13 +92,13 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() { } scheduler = NodeSchedulerService(services, database, schedulerGatedExecutor) smmExecutor = AffinityExecutor.ServiceAffinityExecutor("test", 1) - val mockSMM = StateMachineManager(services, listOf(services, scheduler), DBCheckpointStorage(), smmExecutor, database) + val mockSMM = StateMachineManager(services, DBCheckpointStorage(), smmExecutor, database) mockSMM.changes.subscribe { change -> if (change is StateMachineManager.Change.Removed && mockSMM.allStateMachines.isEmpty()) { smmHasRemovedAllFlows.countDown() } } - mockSMM.start() + mockSMM.start(listOf(services, scheduler)) services.smm = mockSMM scheduler.start() } diff --git a/node/src/test/kotlin/net/corda/node/services/persistence/DataVendingServiceTests.kt b/node/src/test/kotlin/net/corda/node/services/persistence/DataVendingServiceTests.kt index 8d969ce1c4..95072b0a7f 100644 --- a/node/src/test/kotlin/net/corda/node/services/persistence/DataVendingServiceTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/persistence/DataVendingServiceTests.kt @@ -6,9 +6,10 @@ import net.corda.core.contracts.Amount import net.corda.core.contracts.Issued import net.corda.core.contracts.TransactionType import net.corda.core.contracts.USD -import net.corda.core.identity.Party import net.corda.core.flows.FlowLogic +import net.corda.core.flows.InitiatedBy import net.corda.core.flows.InitiatingFlow +import net.corda.core.identity.Party import net.corda.core.node.services.unconsumedStates import net.corda.core.transactions.SignedTransaction import net.corda.core.utilities.DUMMY_NOTARY @@ -86,16 +87,20 @@ class DataVendingServiceTests { } private fun MockNode.sendNotifyTx(tx: SignedTransaction, walletServiceNode: MockNode) { - walletServiceNode.registerServiceFlow(clientFlowClass = NotifyTxFlow::class, serviceFlowFactory = ::NotifyTransactionHandler) + walletServiceNode.registerInitiatedFlow(InitiateNotifyTxFlow::class.java) services.startFlow(NotifyTxFlow(walletServiceNode.info.legalIdentity, tx)) network.runNetwork() } - @InitiatingFlow private class NotifyTxFlow(val otherParty: Party, val stx: SignedTransaction) : FlowLogic() { @Suspendable override fun call() = send(otherParty, NotifyTxRequest(stx)) } + @InitiatedBy(NotifyTxFlow::class) + private class InitiateNotifyTxFlow(val otherParty: Party) : FlowLogic() { + @Suspendable + override fun call() = subFlow(NotifyTransactionHandler(otherParty)) + } } diff --git a/node/src/test/kotlin/net/corda/node/services/statemachine/FlowFrameworkTests.kt b/node/src/test/kotlin/net/corda/node/services/statemachine/FlowFrameworkTests.kt index 7eece7a705..3248cb33c5 100644 --- a/node/src/test/kotlin/net/corda/node/services/statemachine/FlowFrameworkTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/statemachine/FlowFrameworkTests.kt @@ -7,13 +7,13 @@ import net.corda.contracts.asset.Cash import net.corda.core.* import net.corda.core.contracts.DOLLARS import net.corda.core.contracts.DummyState -import net.corda.core.identity.Party import net.corda.core.crypto.SecureHash import net.corda.core.crypto.generateKeyPair import net.corda.core.flows.FlowException import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowSessionException import net.corda.core.flows.InitiatingFlow +import net.corda.core.identity.Party import net.corda.core.messaging.MessageRecipients import net.corda.core.node.services.PartyInfo import net.corda.core.node.services.ServiceInfo @@ -30,15 +30,19 @@ import net.corda.flows.CashIssueFlow import net.corda.flows.CashPaymentFlow import net.corda.flows.FinalityFlow import net.corda.flows.NotaryFlow +import net.corda.node.internal.InitiatedFlowFactory import net.corda.node.services.persistence.checkpoints import net.corda.node.services.transactions.ValidatingNotaryService import net.corda.node.utilities.transaction -import net.corda.testing.* +import net.corda.testing.expect +import net.corda.testing.expectEvents +import net.corda.testing.getTestX509Name import net.corda.testing.node.InMemoryMessagingNetwork import net.corda.testing.node.InMemoryMessagingNetwork.MessageTransfer import net.corda.testing.node.InMemoryMessagingNetwork.ServicePeerAllocationStrategy.RoundRobin import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork.MockNode +import net.corda.testing.sequence import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThatThrownBy import org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType @@ -110,7 +114,7 @@ class FlowFrameworkTests { @Test fun `exception while fiber suspended`() { - node2.registerServiceFlow(ReceiveFlow::class) { SendFlow("Hello", it) } + node2.registerFlowFactory(ReceiveFlow::class) { SendFlow("Hello", it) } val flow = ReceiveFlow(node2.info.legalIdentity) val fiber = node1.services.startFlow(flow) as FlowStateMachineImpl // Before the flow runs change the suspend action to throw an exception @@ -129,7 +133,7 @@ class FlowFrameworkTests { @Test fun `flow restarted just after receiving payload`() { - node2.registerServiceFlow(SendFlow::class) { ReceiveFlow(it).nonTerminating() } + node2.registerFlowFactory(SendFlow::class) { ReceiveFlow(it).nonTerminating() } node1.services.startFlow(SendFlow("Hello", node2.info.legalIdentity)) // We push through just enough messages to get only the payload sent @@ -179,7 +183,7 @@ class FlowFrameworkTests { @Test fun `flow loaded from checkpoint will respond to messages from before start`() { - node1.registerServiceFlow(ReceiveFlow::class) { SendFlow("Hello", it) } + node1.registerFlowFactory(ReceiveFlow::class) { SendFlow("Hello", it) } node2.services.startFlow(ReceiveFlow(node1.info.legalIdentity).nonTerminating()) // Prepare checkpointed receive flow // Make sure the add() has finished initial processing. node2.smm.executor.flush() @@ -198,7 +202,7 @@ class FlowFrameworkTests { net.messagingNetwork.sentMessages.toSessionTransfers().filter { it.isPayloadTransfer }.forEach { sentCount++ } val node3 = net.createNode(node1.info.address) - val secondFlow = node3.initiateSingleShotFlow(PingPongFlow::class) { PingPongFlow(it, payload2) } + val secondFlow = node3.registerFlowFactory(PingPongFlow::class) { PingPongFlow(it, payload2) } net.runNetwork() // Kick off first send and receive @@ -243,8 +247,8 @@ class FlowFrameworkTests { fun `sending to multiple parties`() { val node3 = net.createNode(node1.info.address) net.runNetwork() - node2.registerServiceFlow(SendFlow::class) { ReceiveFlow(it).nonTerminating() } - node3.registerServiceFlow(SendFlow::class) { ReceiveFlow(it).nonTerminating() } + node2.registerFlowFactory(SendFlow::class) { ReceiveFlow(it).nonTerminating() } + node3.registerFlowFactory(SendFlow::class) { ReceiveFlow(it).nonTerminating() } val payload = "Hello World" node1.services.startFlow(SendFlow(payload, node2.info.legalIdentity, node3.info.legalIdentity)) net.runNetwork() @@ -277,8 +281,8 @@ class FlowFrameworkTests { net.runNetwork() val node2Payload = "Test 1" val node3Payload = "Test 2" - node2.registerServiceFlow(ReceiveFlow::class) { SendFlow(node2Payload, it) } - node3.registerServiceFlow(ReceiveFlow::class) { SendFlow(node3Payload, it) } + node2.registerFlowFactory(ReceiveFlow::class) { SendFlow(node2Payload, it) } + node3.registerFlowFactory(ReceiveFlow::class) { SendFlow(node3Payload, it) } val multiReceiveFlow = ReceiveFlow(node2.info.legalIdentity, node3.info.legalIdentity).nonTerminating() node1.services.startFlow(multiReceiveFlow) node1.acceptableLiveFiberCountOnStop = 1 @@ -303,7 +307,7 @@ class FlowFrameworkTests { @Test fun `both sides do a send as their first IO request`() { - node2.registerServiceFlow(PingPongFlow::class) { PingPongFlow(it, 20L) } + node2.registerFlowFactory(PingPongFlow::class) { PingPongFlow(it, 20L) } node1.services.startFlow(PingPongFlow(node2.info.legalIdentity, 10L)) net.runNetwork() @@ -339,7 +343,7 @@ class FlowFrameworkTests { sessionTransfers.expectEvents(isStrict = false) { sequence( // First Pay - expect(match = { it.message is SessionInit && it.message.clientFlowClass == NotaryFlow.Client::class.java }) { + expect(match = { it.message is SessionInit && it.message.initiatingFlowClass == NotaryFlow.Client::class.java }) { it.message as SessionInit assertEquals(node1.id, it.from) assertEquals(notary1Address, it.to) @@ -349,7 +353,7 @@ class FlowFrameworkTests { assertEquals(notary1.id, it.from) }, // Second pay - expect(match = { it.message is SessionInit && it.message.clientFlowClass == NotaryFlow.Client::class.java }) { + expect(match = { it.message is SessionInit && it.message.initiatingFlowClass == NotaryFlow.Client::class.java }) { it.message as SessionInit assertEquals(node1.id, it.from) assertEquals(notary1Address, it.to) @@ -359,7 +363,7 @@ class FlowFrameworkTests { assertEquals(notary2.id, it.from) }, // Third pay - expect(match = { it.message is SessionInit && it.message.clientFlowClass == NotaryFlow.Client::class.java }) { + expect(match = { it.message is SessionInit && it.message.initiatingFlowClass == NotaryFlow.Client::class.java }) { it.message as SessionInit assertEquals(node1.id, it.from) assertEquals(notary1Address, it.to) @@ -374,7 +378,7 @@ class FlowFrameworkTests { @Test fun `other side ends before doing expected send`() { - node2.registerServiceFlow(ReceiveFlow::class) { NoOpFlow() } + node2.registerFlowFactory(ReceiveFlow::class) { NoOpFlow() } val resultFuture = node1.services.startFlow(ReceiveFlow(node2.info.legalIdentity)).resultFuture net.runNetwork() assertThatExceptionOfType(FlowSessionException::class.java).isThrownBy { @@ -384,7 +388,7 @@ class FlowFrameworkTests { @Test fun `non-FlowException thrown on other side`() { - val erroringFlowFuture = node2.initiateSingleShotFlow(ReceiveFlow::class) { + val erroringFlowFuture = node2.registerFlowFactory(ReceiveFlow::class) { ExceptionFlow { Exception("evil bug!") } } val erroringFlowSteps = erroringFlowFuture.flatMap { it.progressSteps } @@ -418,7 +422,7 @@ class FlowFrameworkTests { @Test fun `FlowException thrown on other side`() { - val erroringFlow = node2.initiateSingleShotFlow(ReceiveFlow::class) { + val erroringFlow = node2.registerFlowFactory(ReceiveFlow::class) { ExceptionFlow { MyFlowException("Nothing useful") } } val erroringFlowSteps = erroringFlow.flatMap { it.progressSteps } @@ -456,8 +460,8 @@ class FlowFrameworkTests { val node3 = net.createNode(node1.info.address) net.runNetwork() - node3.initiateSingleShotFlow(ReceiveFlow::class) { ExceptionFlow { MyFlowException("Chain") } } - node2.initiateSingleShotFlow(ReceiveFlow::class) { ReceiveFlow(node3.info.legalIdentity) } + node3.registerFlowFactory(ReceiveFlow::class) { ExceptionFlow { MyFlowException("Chain") } } + node2.registerFlowFactory(ReceiveFlow::class) { ReceiveFlow(node3.info.legalIdentity) } val receivingFiber = node1.services.startFlow(ReceiveFlow(node2.info.legalIdentity)) net.runNetwork() assertThatExceptionOfType(MyFlowException::class.java) @@ -473,9 +477,9 @@ class FlowFrameworkTests { // Node 2 will send its payload and then block waiting for the receive from node 1. Meanwhile node 1 will move // onto node 3 which will throw the exception val node2Fiber = node2 - .initiateSingleShotFlow(ReceiveFlow::class) { SendAndReceiveFlow(it, "Hello") } + .registerFlowFactory(ReceiveFlow::class) { SendAndReceiveFlow(it, "Hello") } .map { it.stateMachine } - node3.initiateSingleShotFlow(ReceiveFlow::class) { ExceptionFlow { MyFlowException("Nothing useful") } } + node3.registerFlowFactory(ReceiveFlow::class) { ExceptionFlow { MyFlowException("Nothing useful") } } val node1Fiber = node1.services.startFlow(ReceiveFlow(node2.info.legalIdentity, node3.info.legalIdentity)) as FlowStateMachineImpl net.runNetwork() @@ -528,7 +532,7 @@ class FlowFrameworkTests { } } - node2.registerServiceFlow(AskForExceptionFlow::class) { ConditionalExceptionFlow(it, "Hello") } + node2.registerFlowFactory(AskForExceptionFlow::class) { ConditionalExceptionFlow(it, "Hello") } val resultFuture = node1.services.startFlow(RetryOnExceptionFlow(node2.info.legalIdentity)).resultFuture net.runNetwork() assertThat(resultFuture.getOrThrow()).isEqualTo("Hello") @@ -536,7 +540,7 @@ class FlowFrameworkTests { @Test fun `serialisation issue in counterparty`() { - node2.registerServiceFlow(ReceiveFlow::class) { SendFlow(NonSerialisableData(1), it) } + node2.registerFlowFactory(ReceiveFlow::class) { SendFlow(NonSerialisableData(1), it) } val result = node1.services.startFlow(ReceiveFlow(node2.info.legalIdentity)).resultFuture net.runNetwork() assertThatExceptionOfType(FlowSessionException::class.java).isThrownBy { @@ -546,7 +550,7 @@ class FlowFrameworkTests { @Test fun `FlowException has non-serialisable object`() { - node2.initiateSingleShotFlow(ReceiveFlow::class) { + node2.registerFlowFactory(ReceiveFlow::class) { ExceptionFlow { NonSerialisableFlowException(NonSerialisableData(1)) } } val result = node1.services.startFlow(ReceiveFlow(node2.info.legalIdentity)).resultFuture @@ -562,9 +566,9 @@ class FlowFrameworkTests { ptx.addOutputState(DummyState()) val stx = node1.services.signInitialTransaction(ptx) - val committerFiber = node1 - .initiateSingleShotFlow(WaitingFlows.Waiter::class) { WaitingFlows.Committer(it) } - .map { it.stateMachine } + val committerFiber = node1.registerFlowFactory(WaitingFlows.Waiter::class) { + WaitingFlows.Committer(it) + }.map { it.stateMachine } val waiterStx = node2.services.startFlow(WaitingFlows.Waiter(stx, node1.info.legalIdentity)).resultFuture net.runNetwork() assertThat(waiterStx.getOrThrow()).isEqualTo(committerFiber.getOrThrow().resultFuture.getOrThrow()) @@ -576,7 +580,7 @@ class FlowFrameworkTests { ptx.addOutputState(DummyState()) val stx = node1.services.signInitialTransaction(ptx) - node1.registerServiceFlow(WaitingFlows.Waiter::class) { + node1.registerFlowFactory(WaitingFlows.Waiter::class) { WaitingFlows.Committer(it) { throw Exception("Error") } } val waiter = node2.services.startFlow(WaitingFlows.Waiter(stx, node1.info.legalIdentity)).resultFuture @@ -594,13 +598,22 @@ class FlowFrameworkTests { } @Test - fun `custom client flow`() { - val receiveFlowFuture = node2.initiateSingleShotFlow(SendFlow::class) { ReceiveFlow(it) } + fun `customised client flow`() { + val receiveFlowFuture = node2.registerFlowFactory(SendFlow::class) { ReceiveFlow(it) } node1.services.startFlow(CustomSendFlow("Hello", node2.info.legalIdentity)).resultFuture net.runNetwork() assertThat(receiveFlowFuture.getOrThrow().receivedPayloads).containsOnly("Hello") } + @Test + fun `customised client flow which has annotated @InitiatingFlow again`() { + val result = node1.services.startFlow(IncorrectCustomSendFlow("Hello", node2.info.legalIdentity)).resultFuture + net.runNetwork() + assertThatExceptionOfType(IllegalArgumentException::class.java).isThrownBy { + result.getOrThrow() + }.withMessageContaining(InitiatingFlow::class.java.simpleName) + } + @Test fun `upgraded flow`() { node1.services.startFlow(UpgradedFlow(node2.info.legalIdentity)) @@ -612,7 +625,11 @@ class FlowFrameworkTests { @Test fun `unsupported new flow version`() { - node2.registerServiceFlow(UpgradedFlow::class, flowVersion = 1) { SendFlow("Hello", it) } + node2.registerFlowFactory( + UpgradedFlow::class.java, + InitiatedFlowFactory.CorDapp(version = 1, factory = ::DoubleInlinedSubFlow), + DoubleInlinedSubFlow::class.java, + track = false) val result = node1.services.startFlow(UpgradedFlow(node2.info.legalIdentity)).resultFuture net.runNetwork() assertThatExceptionOfType(FlowSessionException::class.java).isThrownBy { @@ -622,7 +639,7 @@ class FlowFrameworkTests { @Test fun `single inlined sub-flow`() { - node2.registerServiceFlow(SendAndReceiveFlow::class) { SingleInlinedSubFlow(it) } + node2.registerFlowFactory(SendAndReceiveFlow::class, ::SingleInlinedSubFlow) val result = node1.services.startFlow(SendAndReceiveFlow(node2.info.legalIdentity, "Hello")).resultFuture net.runNetwork() assertThat(result.getOrThrow()).isEqualTo("HelloHello") @@ -630,7 +647,7 @@ class FlowFrameworkTests { @Test fun `double inlined sub-flow`() { - node2.registerServiceFlow(SendAndReceiveFlow::class) { DoubleInlinedSubFlow(it) } + node2.registerFlowFactory(SendAndReceiveFlow::class, ::DoubleInlinedSubFlow) val result = node1.services.startFlow(SendAndReceiveFlow(node2.info.legalIdentity, "Hello")).resultFuture net.runNetwork() assertThat(result.getOrThrow()).isEqualTo("HelloHello") @@ -654,6 +671,18 @@ class FlowFrameworkTests { return smm.findStateMachines(P::class.java).single() } + private inline fun > MockNode.registerFlowFactory( + initiatingFlowClass: KClass>, + noinline flowFactory: (Party) -> P): ListenableFuture

+ { + val observable = registerFlowFactory(initiatingFlowClass.java, object : InitiatedFlowFactory

{ + override fun createFlow(platformVersion: Int, otherParty: Party, sessionInit: SessionInit): P { + return flowFactory(otherParty) + } + }, P::class.java, track = true) + return observable.toFuture() + } + private fun sessionInit(clientFlowClass: KClass>, flowVersion: Int = 1, payload: Any? = null): SessionInit { return SessionInit(0, clientFlowClass.java, flowVersion, payload) } @@ -730,8 +759,12 @@ class FlowFrameworkTests { } private interface CustomInterface + private class CustomSendFlow(payload: String, otherParty: Party) : CustomInterface, SendFlow(payload, otherParty) + @InitiatingFlow + private class IncorrectCustomSendFlow(payload: String, otherParty: Party) : CustomInterface, SendFlow(payload, otherParty) + @InitiatingFlow private class ReceiveFlow(vararg val otherParties: Party) : FlowLogic() { object START_STEP : ProgressTracker.Step("Starting") @@ -852,7 +885,7 @@ class FlowFrameworkTests { } private data class NonSerialisableData(val a: Int) - private class NonSerialisableFlowException(val data: NonSerialisableData) : FlowException() + private class NonSerialisableFlowException(@Suppress("unused") val data: NonSerialisableData) : FlowException() //endregion Helpers } diff --git a/samples/bank-of-corda-demo/src/main/kotlin/net/corda/bank/plugin/BankOfCordaPlugin.kt b/samples/bank-of-corda-demo/src/main/kotlin/net/corda/bank/plugin/BankOfCordaPlugin.kt index 8fd4ce47bb..b003bf2da2 100644 --- a/samples/bank-of-corda-demo/src/main/kotlin/net/corda/bank/plugin/BankOfCordaPlugin.kt +++ b/samples/bank-of-corda-demo/src/main/kotlin/net/corda/bank/plugin/BankOfCordaPlugin.kt @@ -1,13 +1,10 @@ package net.corda.bank.plugin import net.corda.bank.api.BankOfCordaWebApi -import net.corda.core.identity.Party import net.corda.core.node.CordaPluginRegistry -import net.corda.flows.IssuerFlow import java.util.function.Function class BankOfCordaPlugin : CordaPluginRegistry() { // A list of classes that expose web APIs. override val webApis = listOf(Function(::BankOfCordaWebApi)) - override val servicePlugins = listOf(Function(IssuerFlow.Issuer::Service)) } diff --git a/samples/irs-demo/src/integration-test/kotlin/net/corda/irs/IRSDemoTest.kt b/samples/irs-demo/src/integration-test/kotlin/net/corda/irs/IRSDemoTest.kt index 01b0a588b0..56a45f388d 100644 --- a/samples/irs-demo/src/integration-test/kotlin/net/corda/irs/IRSDemoTest.kt +++ b/samples/irs-demo/src/integration-test/kotlin/net/corda/irs/IRSDemoTest.kt @@ -33,7 +33,11 @@ class IRSDemoTest : IntegrationTestCategory { @Test fun `runs IRS demo`() { - driver(useTestClock = true, isDebug = true) { + driver( + useTestClock = true, + isDebug = true, + systemProperties = mapOf("net.corda.node.cordapp.scan.package" to "net.corda.irs")) + { val (controller, nodeA, nodeB) = Futures.allAsList( startNode(DUMMY_NOTARY.name, setOf(ServiceInfo(SimpleNotaryService.type), ServiceInfo(NodeInterestRates.type))), startNode(DUMMY_BANK_A.name, rpcUsers = listOf(rpcUser)), @@ -83,18 +87,22 @@ class IRSDemoTest : IntegrationTestCategory { } private fun runTrade(nodeAddr: HostAndPort) { - val fileContents = IOUtils.toString(Thread.currentThread().contextClassLoader.getResourceAsStream("net/corda/irs/simulation/example-irs-trade.json"), Charsets.UTF_8.name()) + val fileContents = loadResourceFile("net/corda/irs/simulation/example-irs-trade.json") val tradeFile = fileContents.replace("tradeXXX", "trade1") val url = URL("http://$nodeAddr/api/irs/deals") assertThat(postJson(url, tradeFile)).isTrue() } private fun runUploadRates(host: HostAndPort) { - val fileContents = IOUtils.toString(Thread.currentThread().contextClassLoader.getResourceAsStream("net/corda/irs/simulation/example.rates.txt"), Charsets.UTF_8.name()) + val fileContents = loadResourceFile("net/corda/irs/simulation/example.rates.txt") val url = URL("http://$host/upload/interest-rates") assertThat(uploadFile(url, fileContents)).isTrue() } + private fun loadResourceFile(filename: String): String { + return IOUtils.toString(Thread.currentThread().contextClassLoader.getResourceAsStream(filename), Charsets.UTF_8.name()) + } + private fun getTradeCount(nodeAddr: HostAndPort): Int { val api = HttpApi.fromHostAndPort(nodeAddr, "api/irs") val deals = api.getJson>("deals") diff --git a/samples/irs-demo/src/main/kotlin/net/corda/irs/api/NodeInterestRates.kt b/samples/irs-demo/src/main/kotlin/net/corda/irs/api/NodeInterestRates.kt index b485f406a1..f4cc09ea4c 100644 --- a/samples/irs-demo/src/main/kotlin/net/corda/irs/api/NodeInterestRates.kt +++ b/samples/irs-demo/src/main/kotlin/net/corda/irs/api/NodeInterestRates.kt @@ -6,15 +6,15 @@ import net.corda.core.contracts.* import net.corda.core.crypto.DigitalSignature import net.corda.core.crypto.MerkleTreeException import net.corda.core.crypto.keys -import net.corda.core.crypto.sign import net.corda.core.flows.FlowLogic +import net.corda.core.flows.InitiatedBy import net.corda.core.identity.Party import net.corda.core.math.CubicSplineInterpolator import net.corda.core.math.Interpolator import net.corda.core.math.InterpolatorFactory -import net.corda.core.node.CordaPluginRegistry import net.corda.core.node.PluginServiceHub import net.corda.core.node.ServiceHub +import net.corda.core.node.services.CordaService import net.corda.core.node.services.ServiceType import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.core.transactions.FilteredTransaction @@ -30,14 +30,10 @@ import org.jetbrains.exposed.sql.ResultRow import org.jetbrains.exposed.sql.statements.InsertStatement import java.io.InputStream import java.math.BigDecimal -import java.security.KeyPair -import java.time.Clock import java.security.PublicKey -import java.time.Duration import java.time.Instant import java.time.LocalDate import java.util.* -import java.util.function.Function import javax.annotation.concurrent.ThreadSafe import kotlin.collections.component1 import kotlin.collections.component2 @@ -55,83 +51,50 @@ import kotlin.collections.set object NodeInterestRates { val type = ServiceType.corda.getSubType("interest_rates") - /** - * Register the flow that is used with the Fixing integration tests. - */ - class Plugin : CordaPluginRegistry() { - override val servicePlugins = listOf(Function(::Service)) - } - - /** - * The Service that wraps [Oracle] and handles messages/network interaction/request scrubbing. - */ // DOCSTART 2 - class Service(val services: PluginServiceHub) : AcceptsFileUpload, SingletonSerializeAsToken() { - val oracle: Oracle by lazy { - val myNodeInfo = services.myInfo - val myIdentity = myNodeInfo.serviceIdentities(type).first() - val mySigningKey = myIdentity.owningKey.keys.first { services.keyManagementService.keys.contains(it) } - Oracle(myIdentity, mySigningKey, services) - } - - init { - // Note: access to the singleton oracle property is via the registered SingletonSerializeAsToken Service. - // Otherwise the Kryo serialisation of the call stack in the Quasar Fiber extends to include - // the framework Oracle and the flow will crash. - services.registerServiceFlow(RatesFixFlow.FixSignFlow::class.java) { FixSignHandler(it, this) } - services.registerServiceFlow(RatesFixFlow.FixQueryFlow::class.java) { FixQueryHandler(it, this) } - } - - private class FixSignHandler(val otherParty: Party, val service: Service) : FlowLogic() { - @Suspendable - override fun call() { - val request = receive(otherParty).unwrap { it } - send(otherParty, service.oracle.sign(request.ftx)) - } - } - - private class FixQueryHandler(val otherParty: Party, val service: Service) : FlowLogic() { - companion object { - object RECEIVED : ProgressTracker.Step("Received fix request") - object SENDING : ProgressTracker.Step("Sending fix response") - } - - override val progressTracker = ProgressTracker(RECEIVED, SENDING) - - init { - progressTracker.currentStep = RECEIVED - } - - @Suspendable - override fun call(): Unit { - val request = receive(otherParty).unwrap { it } - val answers = service.oracle.query(request.queries, request.deadline) - progressTracker.currentStep = SENDING - send(otherParty, answers) - } - } - // DOCEND 2 - - // File upload support - override val dataTypePrefix = "interest-rates" - override val acceptableFileExtensions = listOf(".rates", ".txt") - - override fun upload(file: InputStream): String { - val fixes = parseFile(file.bufferedReader().readText()) - oracle.knownFixes = fixes - val msg = "Interest rates oracle accepted ${fixes.size} new interest rate fixes" - println(msg) - return msg + @InitiatedBy(RatesFixFlow.FixSignFlow::class) + class FixSignHandler(val otherParty: Party) : FlowLogic() { + @Suspendable + override fun call() { + val request = receive(otherParty).unwrap { it } + send(otherParty, serviceHub.cordaService(Oracle::class.java).sign(request.ftx)) } } + @InitiatedBy(RatesFixFlow.FixQueryFlow::class) + class FixQueryHandler(val otherParty: Party) : FlowLogic() { + object RECEIVED : ProgressTracker.Step("Received fix request") + object SENDING : ProgressTracker.Step("Sending fix response") + + override val progressTracker = ProgressTracker(RECEIVED, SENDING) + + @Suspendable + override fun call(): Unit { + val request = receive(otherParty).unwrap { it } + progressTracker.currentStep = RECEIVED + val answers = serviceHub.cordaService(Oracle::class.java).query(request.queries, request.deadline) + progressTracker.currentStep = SENDING + send(otherParty, answers) + } + } + // DOCEND 2 + /** * An implementation of an interest rate fix oracle which is given data in a simple string format. * * The oracle will try to interpolate the missing value of a tenor for the given fix name and date. */ @ThreadSafe - class Oracle(val identity: Party, private val signingKey: PublicKey, val services: ServiceHub) { + // DOCSTART 3 + @CordaService + class Oracle(val identity: Party, private val signingKey: PublicKey, val services: ServiceHub) : AcceptsFileUpload, SingletonSerializeAsToken() { + constructor(services: PluginServiceHub) : this( + services.myInfo.serviceIdentities(type).first(), + services.myInfo.serviceIdentities(type).first().owningKey.keys.first { services.keyManagementService.keys.contains(it) }, + services + ) + // DOCEND 3 + private object Table : JDBCHashedTable("demo_interest_rate_fixes") { val name = varchar("index_name", length = 255) val forDay = localDate("for_day") @@ -175,7 +138,7 @@ object NodeInterestRates { /** * This method will now wait until the given deadline if the fix for the given [FixOf] is not immediately - * available. To implement this, [readWithDeadline] will loop if the deadline is not reached and we throw + * available. To implement this, [FiberBox.readWithDeadline] will loop if the deadline is not reached and we throw * [UnknownFix] as it implements [RetryableException] which has special meaning to this function. */ @Suspendable @@ -231,6 +194,16 @@ object NodeInterestRates { return DigitalSignature.LegallyIdentifiable(identity, signature.bytes) } // DOCEND 1 + + // File upload support + override val dataTypePrefix = "interest-rates" + override val acceptableFileExtensions = listOf(".rates", ".txt") + + override fun upload(file: InputStream): String { + val fixes = parseFile(file.bufferedReader().readText()) + knownFixes = fixes + return "Interest rates oracle accepted ${fixes.size} new interest rate fixes" + } } // TODO: can we split into two? Fix not available (retryable/transient) and unknown (permanent) diff --git a/samples/irs-demo/src/main/kotlin/net/corda/irs/flows/AutoOfferFlow.kt b/samples/irs-demo/src/main/kotlin/net/corda/irs/flows/AutoOfferFlow.kt index 7e7520c65a..0c60126018 100644 --- a/samples/irs-demo/src/main/kotlin/net/corda/irs/flows/AutoOfferFlow.kt +++ b/samples/irs-demo/src/main/kotlin/net/corda/irs/flows/AutoOfferFlow.kt @@ -3,19 +3,17 @@ package net.corda.irs.flows import co.paralleluniverse.fibers.Suspendable import net.corda.core.contracts.DealState import net.corda.core.flows.FlowLogic +import net.corda.core.flows.InitiatedBy import net.corda.core.flows.InitiatingFlow import net.corda.core.flows.StartableByRPC import net.corda.core.identity.AbstractParty -import net.corda.core.node.CordaPluginRegistry -import net.corda.core.node.PluginServiceHub -import net.corda.core.serialization.SingletonSerializeAsToken +import net.corda.core.identity.Party import net.corda.core.transactions.SignedTransaction import net.corda.core.utilities.ProgressTracker import net.corda.flows.TwoPartyDealFlow import net.corda.flows.TwoPartyDealFlow.Acceptor import net.corda.flows.TwoPartyDealFlow.AutoOffer import net.corda.flows.TwoPartyDealFlow.Instigator -import java.util.function.Function /** * This whole class is really part of a demo just to initiate the agreement of a deal with a simple @@ -25,18 +23,6 @@ import java.util.function.Function * or the flow would have to reach out to external systems (or users) to verify the deals. */ object AutoOfferFlow { - - class Plugin : CordaPluginRegistry() { - override val servicePlugins = listOf(Function(::Service)) - } - - - class Service(services: PluginServiceHub) : SingletonSerializeAsToken() { - init { - services.registerServiceFlow(Requester::class.java) { Acceptor(it) } - } - } - @InitiatingFlow @StartableByRPC class Requester(val dealToBeOffered: DealState) : FlowLogic() { @@ -81,4 +67,7 @@ object AutoOfferFlow { return parties.filter { serviceHub.myInfo.legalIdentity != it } } } + + @InitiatedBy(Requester::class) + class AutoOfferAcceptor(otherParty: Party) : Acceptor(otherParty) } diff --git a/samples/irs-demo/src/main/kotlin/net/corda/irs/flows/FixingFlow.kt b/samples/irs-demo/src/main/kotlin/net/corda/irs/flows/FixingFlow.kt index 7937b05908..1350c68187 100644 --- a/samples/irs-demo/src/main/kotlin/net/corda/irs/flows/FixingFlow.kt +++ b/samples/irs-demo/src/main/kotlin/net/corda/irs/flows/FixingFlow.kt @@ -5,11 +5,11 @@ import net.corda.core.TransientProperty import net.corda.core.contracts.* import net.corda.core.crypto.toBase58String import net.corda.core.flows.FlowLogic +import net.corda.core.flows.InitiatedBy import net.corda.core.flows.InitiatingFlow import net.corda.core.flows.SchedulableFlow import net.corda.core.identity.Party import net.corda.core.node.NodeInfo -import net.corda.core.node.PluginServiceHub import net.corda.core.node.services.ServiceType import net.corda.core.seconds import net.corda.core.serialization.CordaSerializable @@ -22,13 +22,6 @@ import java.math.BigDecimal import java.security.PublicKey object FixingFlow { - - class Service(services: PluginServiceHub) { - init { - services.registerServiceFlow(FixingRoleDecider::class.java) { Fixer(it) } - } - } - /** * One side of the fixing flow for an interest rate swap, but could easily be generalised further. * @@ -36,8 +29,9 @@ object FixingFlow { * of the flow that is run by the party with the fixed leg of swap deal, which is the basis for deciding * who does what in the flow. */ - class Fixer(override val otherParty: Party, - override val progressTracker: ProgressTracker = TwoPartyDealFlow.Secondary.tracker()) : TwoPartyDealFlow.Secondary() { + @InitiatedBy(FixingRoleDecider::class) + class Fixer(override val otherParty: Party) : TwoPartyDealFlow.Secondary() { + override val progressTracker: ProgressTracker = TwoPartyDealFlow.Secondary.tracker() private lateinit var txState: TransactionState<*> private lateinit var deal: FixableDealState diff --git a/samples/irs-demo/src/main/kotlin/net/corda/irs/flows/UpdateBusinessDayFlow.kt b/samples/irs-demo/src/main/kotlin/net/corda/irs/flows/UpdateBusinessDayFlow.kt index 63f3215bd8..8c0720a073 100644 --- a/samples/irs-demo/src/main/kotlin/net/corda/irs/flows/UpdateBusinessDayFlow.kt +++ b/samples/irs-demo/src/main/kotlin/net/corda/irs/flows/UpdateBusinessDayFlow.kt @@ -2,19 +2,17 @@ package net.corda.irs.flows import co.paralleluniverse.fibers.Suspendable import net.corda.core.flows.FlowLogic +import net.corda.core.flows.InitiatedBy import net.corda.core.flows.InitiatingFlow import net.corda.core.flows.StartableByRPC import net.corda.core.identity.Party -import net.corda.core.node.CordaPluginRegistry import net.corda.core.node.NodeInfo -import net.corda.core.node.PluginServiceHub import net.corda.core.serialization.CordaSerializable import net.corda.core.utilities.ProgressTracker import net.corda.core.utilities.unwrap import net.corda.node.utilities.TestClock import net.corda.testing.node.MockNetworkMapCache import java.time.LocalDate -import java.util.function.Function /** * This is a less temporary, demo-oriented way of initiating processing of temporal events. @@ -26,16 +24,7 @@ object UpdateBusinessDayFlow { @CordaSerializable data class UpdateBusinessDayMessage(val date: LocalDate) - class Plugin : CordaPluginRegistry() { - override val servicePlugins = listOf(Function(::Service)) - } - - class Service(services: PluginServiceHub) { - init { - services.registerServiceFlow(Broadcast::class.java, ::UpdateBusinessDayHandler) - } - } - + @InitiatedBy(Broadcast::class) private class UpdateBusinessDayHandler(val otherParty: Party) : FlowLogic() { override fun call() { val message = receive(otherParty).unwrap { it } diff --git a/samples/irs-demo/src/main/kotlin/net/corda/irs/plugin/IRSPlugin.kt b/samples/irs-demo/src/main/kotlin/net/corda/irs/plugin/IRSPlugin.kt index 14519804e2..77a530d8c4 100644 --- a/samples/irs-demo/src/main/kotlin/net/corda/irs/plugin/IRSPlugin.kt +++ b/samples/irs-demo/src/main/kotlin/net/corda/irs/plugin/IRSPlugin.kt @@ -2,7 +2,6 @@ package net.corda.irs.plugin import net.corda.core.node.CordaPluginRegistry import net.corda.irs.api.InterestRateSwapAPI -import net.corda.irs.flows.FixingFlow import java.util.function.Function class IRSPlugin : CordaPluginRegistry() { @@ -10,5 +9,4 @@ class IRSPlugin : CordaPluginRegistry() { override val staticServeDirs: Map = mapOf( "irsdemo" to javaClass.classLoader.getResource("irsweb").toExternalForm() ) - override val servicePlugins = listOf(Function(FixingFlow::Service)) } diff --git a/samples/irs-demo/src/main/kotlin/net/corda/irs/simulation/IRSSimulation.kt b/samples/irs-demo/src/main/kotlin/net/corda/irs/simulation/IRSSimulation.kt index 45b2f9a4d0..369d8537ba 100644 --- a/samples/irs-demo/src/main/kotlin/net/corda/irs/simulation/IRSSimulation.kt +++ b/samples/irs-demo/src/main/kotlin/net/corda/irs/simulation/IRSSimulation.kt @@ -7,27 +7,26 @@ import com.google.common.util.concurrent.FutureCallback import com.google.common.util.concurrent.Futures import com.google.common.util.concurrent.ListenableFuture import com.google.common.util.concurrent.SettableFuture -import net.corda.core.RunOnCallerThread +import net.corda.core.* import net.corda.core.contracts.StateAndRef import net.corda.core.contracts.UniqueIdentifier -import net.corda.core.flatMap import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowStateMachine +import net.corda.core.flows.InitiatedBy import net.corda.core.flows.InitiatingFlow import net.corda.core.identity.Party -import net.corda.core.map import net.corda.core.node.services.linearHeadsOfType -import net.corda.core.success import net.corda.core.transactions.SignedTransaction import net.corda.flows.TwoPartyDealFlow.Acceptor import net.corda.flows.TwoPartyDealFlow.AutoOffer import net.corda.flows.TwoPartyDealFlow.Instigator import net.corda.irs.contract.InterestRateSwap +import net.corda.irs.flows.FixingFlow import net.corda.jackson.JacksonSupport import net.corda.node.services.identity.InMemoryIdentityService import net.corda.node.utilities.transaction -import net.corda.testing.initiateSingleShotFlow import net.corda.testing.node.InMemoryMessagingNetwork +import rx.Observable import java.security.PublicKey import java.time.LocalDate import java.util.* @@ -126,6 +125,9 @@ class IRSSimulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, laten irs.fixedLeg.fixedRatePayer = node1.info.legalIdentity irs.floatingLeg.floatingRatePayer = node2.info.legalIdentity + node1.registerInitiatedFlow(FixingFlow.Fixer::class.java) + node2.registerInitiatedFlow(FixingFlow.Fixer::class.java) + @InitiatingFlow class StartDealFlow(val otherParty: Party, val payload: AutoOffer, @@ -134,8 +136,13 @@ class IRSSimulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, laten override fun call(): SignedTransaction = subFlow(Instigator(otherParty, payload, myKey)) } + @InitiatedBy(StartDealFlow::class) + class AcceptDealFlow(otherParty: Party) : Acceptor(otherParty) + + val acceptDealFlows: Observable = node2.registerInitiatedFlow(AcceptDealFlow::class.java) + @Suppress("UNCHECKED_CAST") - val acceptorTx = node2.initiateSingleShotFlow(StartDealFlow::class) { Acceptor(it) }.flatMap { + val acceptorTxFuture = acceptDealFlows.toFuture().flatMap { (it.stateMachine as FlowStateMachine).resultFuture } @@ -146,9 +153,9 @@ class IRSSimulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, laten node2.info.legalIdentity, AutoOffer(notary.info.notaryIdentity, irs), node1.services.legalIdentityKey) - val instigatorTx = node1.services.startFlow(instigator).resultFuture + val instigatorTxFuture = node1.services.startFlow(instigator).resultFuture - return Futures.allAsList(instigatorTx, acceptorTx).flatMap { instigatorTx } + return Futures.allAsList(instigatorTxFuture, acceptorTxFuture).flatMap { instigatorTxFuture } } override fun iterate(): InMemoryMessagingNetwork.MessageTransfer? { diff --git a/samples/irs-demo/src/main/kotlin/net/corda/irs/simulation/Simulation.kt b/samples/irs-demo/src/main/kotlin/net/corda/irs/simulation/Simulation.kt index 6f770662c2..a2a89ca38f 100644 --- a/samples/irs-demo/src/main/kotlin/net/corda/irs/simulation/Simulation.kt +++ b/samples/irs-demo/src/main/kotlin/net/corda/irs/simulation/Simulation.kt @@ -126,9 +126,11 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean, return object : SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot) { override fun start(): MockNetwork.MockNode { super.start() + registerInitiatedFlow(NodeInterestRates.FixQueryHandler::class.java) + registerInitiatedFlow(NodeInterestRates.FixSignHandler::class.java) javaClass.classLoader.getResourceAsStream("net/corda/irs/simulation/example.rates.txt").use { database.transaction { - findService().upload(it) + installCordaService(NodeInterestRates.Oracle::class.java).upload(it) } } return this diff --git a/samples/irs-demo/src/main/resources/META-INF/services/net.corda.core.node.CordaPluginRegistry b/samples/irs-demo/src/main/resources/META-INF/services/net.corda.core.node.CordaPluginRegistry index b7e05a9569..f1275336a5 100644 --- a/samples/irs-demo/src/main/resources/META-INF/services/net.corda.core.node.CordaPluginRegistry +++ b/samples/irs-demo/src/main/resources/META-INF/services/net.corda.core.node.CordaPluginRegistry @@ -1,5 +1,2 @@ # Register a ServiceLoader service extending from net.corda.core.node.CordaPluginRegistry net.corda.irs.plugin.IRSPlugin -net.corda.irs.api.NodeInterestRates$Plugin -net.corda.irs.flows.AutoOfferFlow$Plugin -net.corda.irs.flows.UpdateBusinessDayFlow$Plugin diff --git a/samples/irs-demo/src/test/kotlin/net/corda/irs/testing/NodeInterestRatesTest.kt b/samples/irs-demo/src/test/kotlin/net/corda/irs/testing/NodeInterestRatesTest.kt index fee15b50d0..c1ad4256ec 100644 --- a/samples/irs-demo/src/test/kotlin/net/corda/irs/testing/NodeInterestRatesTest.kt +++ b/samples/irs-demo/src/test/kotlin/net/corda/irs/testing/NodeInterestRatesTest.kt @@ -210,8 +210,10 @@ class NodeInterestRatesTest { val net = MockNetwork() val n1 = net.createNotaryNode() val n2 = net.createNode(n1.info.address, advertisedServices = ServiceInfo(NodeInterestRates.type)) + n2.registerInitiatedFlow(NodeInterestRates.FixQueryHandler::class.java) + n2.registerInitiatedFlow(NodeInterestRates.FixSignHandler::class.java) n2.database.transaction { - n2.findService().oracle.knownFixes = TEST_DATA + n2.installCordaService(NodeInterestRates.Oracle::class.java).knownFixes = TEST_DATA } val tx = TransactionType.General.Builder(null) val fixOf = NodeInterestRates.parseFixOf("LIBOR 2016-03-16 1M") @@ -233,7 +235,8 @@ class NodeInterestRatesTest { fixOf: FixOf, expectedRate: BigDecimal, rateTolerance: BigDecimal, - progressTracker: ProgressTracker = RatesFixFlow.tracker(fixOf.name)) : RatesFixFlow(tx, oracle, fixOf, expectedRate, rateTolerance, progressTracker) { + progressTracker: ProgressTracker = RatesFixFlow.tracker(fixOf.name)) + : RatesFixFlow(tx, oracle, fixOf, expectedRate, rateTolerance, progressTracker) { override fun filtering(elem: Any): Boolean { return when (elem) { is Command -> oracle.owningKey in elem.signers && elem.value is Fix @@ -242,5 +245,6 @@ class NodeInterestRatesTest { } } - private fun makeTX() = TransactionType.General.Builder(DUMMY_NOTARY).withItems(1000.DOLLARS.CASH `issued by` DUMMY_CASH_ISSUER `owned by` ALICE `with notary` DUMMY_NOTARY) + private fun makeTX() = TransactionType.General.Builder(DUMMY_NOTARY).withItems( + 1000.DOLLARS.CASH `issued by` DUMMY_CASH_ISSUER `owned by` ALICE `with notary` DUMMY_NOTARY) } diff --git a/samples/simm-valuation-demo/src/integration-test/kotlin/net/corda/vega/SimmValuationTest.kt b/samples/simm-valuation-demo/src/integration-test/kotlin/net/corda/vega/SimmValuationTest.kt index cb62bc9bd7..69283f7ce6 100644 --- a/samples/simm-valuation-demo/src/integration-test/kotlin/net/corda/vega/SimmValuationTest.kt +++ b/samples/simm-valuation-demo/src/integration-test/kotlin/net/corda/vega/SimmValuationTest.kt @@ -32,7 +32,7 @@ class SimmValuationTest : IntegrationTestCategory { @Test fun `runs SIMM valuation demo`() { - driver(isDebug = true) { + driver(isDebug = true, systemProperties = mapOf("net.corda.node.cordapp.scan.package" to "net.corda.vega")) { startNode(DUMMY_NOTARY.name, setOf(ServiceInfo(SimpleNotaryService.type))).getOrThrow() val (nodeA, nodeB) = Futures.allAsList(startNode(nodeALegalName), startNode(nodeBLegalName)).getOrThrow() val (nodeAApi, nodeBApi) = Futures.allAsList(startWebserver(nodeA), startWebserver(nodeB)) @@ -50,8 +50,9 @@ class SimmValuationTest : IntegrationTestCategory { } } - private fun getPartyWithName(partyApi: HttpApi, counterparty: X500Name): PortfolioApi.ApiParty = - getAvailablePartiesFor(partyApi).counterparties.single { it.text == counterparty } + private fun getPartyWithName(partyApi: HttpApi, counterparty: X500Name): PortfolioApi.ApiParty { + return getAvailablePartiesFor(partyApi).counterparties.single { it.text == counterparty } + } private fun getAvailablePartiesFor(partyApi: HttpApi): PortfolioApi.AvailableParties { return partyApi.getJson("whoami") diff --git a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/IRSTradeFlow.kt b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/IRSTradeFlow.kt index 11a8363f92..ec39e261a0 100644 --- a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/IRSTradeFlow.kt +++ b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/IRSTradeFlow.kt @@ -2,10 +2,10 @@ package net.corda.vega.flows import co.paralleluniverse.fibers.Suspendable import net.corda.core.flows.FlowLogic +import net.corda.core.flows.InitiatedBy import net.corda.core.flows.InitiatingFlow import net.corda.core.flows.StartableByRPC import net.corda.core.identity.Party -import net.corda.core.node.PluginServiceHub import net.corda.core.serialization.CordaSerializable import net.corda.core.transactions.SignedTransaction import net.corda.core.utilities.unwrap @@ -15,12 +15,6 @@ import net.corda.vega.contracts.OGTrade import net.corda.vega.contracts.SwapData object IRSTradeFlow { - class Service(services: PluginServiceHub) { - init { - services.registerServiceFlow(Requester::class.java, ::Receiver) - } - } - @CordaSerializable data class OfferMessage(val notary: Party, val dealBeingOffered: IRSState) @@ -52,6 +46,7 @@ object IRSTradeFlow { } + @InitiatedBy(Requester::class) class Receiver(private val replyToParty: Party) : FlowLogic() { @Suspendable override fun call() { diff --git a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/SimmFlow.kt b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/SimmFlow.kt index 251a5436ed..7a359c0824 100644 --- a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/SimmFlow.kt +++ b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/SimmFlow.kt @@ -11,6 +11,7 @@ import com.opengamma.strata.pricer.swap.DiscountingSwapProductPricer import net.corda.core.contracts.StateAndRef import net.corda.core.contracts.StateRef import net.corda.core.flows.FlowLogic +import net.corda.core.flows.InitiatedBy import net.corda.core.flows.InitiatingFlow import net.corda.core.flows.StartableByRPC import net.corda.core.identity.Party @@ -180,18 +181,10 @@ object SimmFlow { } } - /** - * Service plugin for listening for incoming Simm flow communication - */ - class Service(services: PluginServiceHub) { - init { - services.registerServiceFlow(Requester::class.java, ::Receiver) - } - } - /** * Receives and validates a portfolio and comes to consensus over the portfolio initial margin using SIMM. */ + @InitiatedBy(Requester::class) class Receiver(val replyToParty: Party) : FlowLogic() { lateinit var ownParty: Party lateinit var offer: OfferMessage diff --git a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/services/SimmService.kt b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/services/SimmService.kt index d1f43d93b8..14f360f3db 100644 --- a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/services/SimmService.kt +++ b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/services/SimmService.kt @@ -15,8 +15,6 @@ import net.corda.core.serialization.SerializationCustomization import net.corda.vega.analytics.CordaMarketData import net.corda.vega.analytics.InitialMarginTriple import net.corda.vega.api.PortfolioApi -import net.corda.vega.flows.IRSTradeFlow -import net.corda.vega.flows.SimmFlow import java.util.function.Function /** @@ -28,7 +26,6 @@ object SimmService { class Plugin : CordaPluginRegistry() { override val webApis = listOf(Function(::PortfolioApi)) override val staticServeDirs: Map = mapOf("simmvaluationdemo" to javaClass.classLoader.getResource("simmvaluationweb").toExternalForm()) - override val servicePlugins = listOf(Function(SimmFlow::Service), Function(IRSTradeFlow::Service)) override fun customizeSerialization(custom: SerializationCustomization): Boolean { custom.apply { // OpenGamma classes. diff --git a/samples/trader-demo/src/integration-test/kotlin/net/corda/traderdemo/TraderDemoTest.kt b/samples/trader-demo/src/integration-test/kotlin/net/corda/traderdemo/TraderDemoTest.kt index fb73735ec3..348163a7bb 100644 --- a/samples/trader-demo/src/integration-test/kotlin/net/corda/traderdemo/TraderDemoTest.kt +++ b/samples/trader-demo/src/integration-test/kotlin/net/corda/traderdemo/TraderDemoTest.kt @@ -16,6 +16,7 @@ import net.corda.node.services.transactions.SimpleNotaryService import net.corda.nodeapi.User import net.corda.testing.BOC import net.corda.testing.node.NodeBasedTest +import net.corda.traderdemo.flow.BuyerFlow import net.corda.traderdemo.flow.SellerFlow import org.assertj.core.api.Assertions.assertThat import org.junit.Test @@ -36,6 +37,8 @@ class TraderDemoTest : NodeBasedTest() { startNode(DUMMY_NOTARY.name, advertisedServices = setOf(ServiceInfo(SimpleNotaryService.type))) ).getOrThrow() + nodeA.registerInitiatedFlow(BuyerFlow::class.java) + val (nodeARpc, nodeBRpc) = listOf(nodeA, nodeB).map { val client = CordaRPCClient(it.configuration.rpcAddress!!) client.start(demoUser[0].username, demoUser[0].password).proxy @@ -57,12 +60,8 @@ class TraderDemoTest : NodeBasedTest() { val executor = Executors.newScheduledThreadPool(1) poll(executor, "A to be notified of the commercial paper", pollInterval = 100.millis) { val actualPaper = listOf(clientA.commercialPaperCount, clientB.commercialPaperCount) - if (actualPaper == expectedPaper) { - Unit - } else { - null - } - }.get() + if (actualPaper == expectedPaper) Unit else null + }.getOrThrow() executor.shutdown() assertThat(clientA.dollarCashBalance).isEqualTo(95.DOLLARS) assertThat(clientB.dollarCashBalance).isEqualTo(5.DOLLARS) diff --git a/samples/trader-demo/src/main/kotlin/net/corda/traderdemo/flow/BuyerFlow.kt b/samples/trader-demo/src/main/kotlin/net/corda/traderdemo/flow/BuyerFlow.kt index 6d01fdd3a7..53024ad9a5 100644 --- a/samples/trader-demo/src/main/kotlin/net/corda/traderdemo/flow/BuyerFlow.kt +++ b/samples/trader-demo/src/main/kotlin/net/corda/traderdemo/flow/BuyerFlow.kt @@ -4,36 +4,24 @@ import co.paralleluniverse.fibers.Suspendable import net.corda.contracts.CommercialPaper import net.corda.core.contracts.Amount import net.corda.core.contracts.TransactionGraphSearch -import net.corda.core.identity.Party +import net.corda.core.div import net.corda.core.flows.FlowLogic +import net.corda.core.flows.InitiatedBy +import net.corda.core.identity.Party import net.corda.core.node.NodeInfo -import net.corda.core.node.PluginServiceHub -import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.core.transactions.SignedTransaction import net.corda.core.utilities.Emoji import net.corda.core.utilities.ProgressTracker import net.corda.core.utilities.unwrap import net.corda.flows.TwoPartyTradeFlow -import java.nio.file.Paths import java.util.* -class BuyerFlow(val otherParty: Party, - private val attachmentsDirectory: String, - override val progressTracker: ProgressTracker = ProgressTracker(STARTING_BUY)) : FlowLogic() { +@InitiatedBy(SellerFlow::class) +class BuyerFlow(val otherParty: Party) : FlowLogic() { object STARTING_BUY : ProgressTracker.Step("Seller connected, purchasing commercial paper asset") - class Service(services: PluginServiceHub) : SingletonSerializeAsToken() { - init { - // Buyer will fetch the attachment from the seller automatically when it resolves the transaction. - // For demo purposes just extract attachment jars when saved to disk, so the user can explore them. - val attachmentsPath = (services.storageService.attachments).let { - it.automaticallyExtractAttachments = true - it.storePath - } - services.registerServiceFlow(SellerFlow::class.java) { BuyerFlow(it, attachmentsPath.toString()) } - } - } + override val progressTracker: ProgressTracker = ProgressTracker(STARTING_BUY) @Suspendable override fun call() { @@ -72,8 +60,15 @@ class BuyerFlow(val otherParty: Party, followInputsOfType = CommercialPaper.State::class.java) val cpIssuance = search.call().single() + // Buyer will fetch the attachment from the seller automatically when it resolves the transaction. + // For demo purposes just extract attachment jars when saved to disk, so the user can explore them. + val attachmentsPath = (serviceHub.storageService.attachments).let { + it.automaticallyExtractAttachments = true + it.storePath + } + cpIssuance.attachments.first().let { - val p = Paths.get(attachmentsDirectory, "$it.jar") + val p = attachmentsPath / "$it.jar" println(""" The issuance of the commercial paper came with an attachment. You can find it expanded in this directory: diff --git a/samples/trader-demo/src/main/kotlin/net/corda/traderdemo/plugin/TraderDemoPlugin.kt b/samples/trader-demo/src/main/kotlin/net/corda/traderdemo/plugin/TraderDemoPlugin.kt deleted file mode 100644 index cd45ed4b95..0000000000 --- a/samples/trader-demo/src/main/kotlin/net/corda/traderdemo/plugin/TraderDemoPlugin.kt +++ /dev/null @@ -1,10 +0,0 @@ -package net.corda.traderdemo.plugin - -import net.corda.core.identity.Party -import net.corda.core.node.CordaPluginRegistry -import net.corda.traderdemo.flow.BuyerFlow -import java.util.function.Function - -class TraderDemoPlugin : CordaPluginRegistry() { - override val servicePlugins = listOf(Function(BuyerFlow::Service)) -} diff --git a/samples/trader-demo/src/main/resources/META-INF/services/net.corda.core.node.CordaPluginRegistry b/samples/trader-demo/src/main/resources/META-INF/services/net.corda.core.node.CordaPluginRegistry deleted file mode 100644 index 8ac62a0cd8..0000000000 --- a/samples/trader-demo/src/main/resources/META-INF/services/net.corda.core.node.CordaPluginRegistry +++ /dev/null @@ -1,2 +0,0 @@ -# Register a ServiceLoader service extending from net.corda.core.node.CordaPluginRegistry -net.corda.traderdemo.plugin.TraderDemoPlugin diff --git a/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt b/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt index 35ae8093b2..24d0a67eb8 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt +++ b/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt @@ -4,24 +4,21 @@ package net.corda.testing import com.google.common.net.HostAndPort -import com.google.common.util.concurrent.ListenableFuture import net.corda.core.contracts.StateRef -import net.corda.core.crypto.* -import net.corda.core.flows.FlowLogic +import net.corda.core.crypto.SecureHash +import net.corda.core.crypto.X509Utilities +import net.corda.core.crypto.commonName +import net.corda.core.crypto.generateKeyPair import net.corda.core.identity.Party import net.corda.core.node.ServiceHub import net.corda.core.node.VersionInfo import net.corda.core.node.services.IdentityService import net.corda.core.serialization.OpaqueBytes -import net.corda.core.toFuture import net.corda.core.transactions.TransactionBuilder import net.corda.core.utilities.* -import net.corda.node.internal.AbstractNode import net.corda.node.internal.NetworkMapInfo import net.corda.node.services.config.* import net.corda.node.services.identity.InMemoryIdentityService -import net.corda.node.services.statemachine.FlowStateMachineImpl -import net.corda.node.services.statemachine.StateMachineManager import net.corda.nodeapi.User import net.corda.nodeapi.config.SSLConfiguration import net.corda.testing.node.MockServices @@ -36,7 +33,6 @@ import java.security.KeyPair import java.security.PublicKey import java.util.* import java.util.concurrent.atomic.AtomicInteger -import kotlin.reflect.KClass /** * JAVA INTEROP @@ -138,19 +134,6 @@ fun getFreeLocalPorts(hostName: String, numberToAlloc: Int): List { dsl: TransactionDSL.() -> EnforceVerifyOrFail ) = ledger { this.transaction(transactionLabel, transactionBuilder, dsl) } -/** - * The given flow factory will be used to initiate just one instance of a flow of type [P] when a counterparty - * flow requests for it using [clientFlowClass]. - * @return Returns a [ListenableFuture] holding the single [FlowStateMachineImpl] created by the request. - */ -inline fun > AbstractNode.initiateSingleShotFlow( - clientFlowClass: KClass>, - noinline serviceFlowFactory: (Party) -> P): ListenableFuture

{ - val future = smm.changes.filter { it is StateMachineManager.Change.Add && it.logic is P }.map { it.logic as P }.toFuture() - services.registerServiceFlow(clientFlowClass.java, serviceFlowFactory) - return future -} - // TODO Replace this with testConfiguration data class TestNodeConfiguration( override val baseDirectory: Path, diff --git a/test-utils/src/main/kotlin/net/corda/testing/node/MockNode.kt b/test-utils/src/main/kotlin/net/corda/testing/node/MockNode.kt index b1606ec9fb..5014db0a5b 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/node/MockNode.kt +++ b/test-utils/src/main/kotlin/net/corda/testing/node/MockNode.kt @@ -1,13 +1,11 @@ package net.corda.testing.node -import com.google.common.annotations.VisibleForTesting import com.google.common.jimfs.Configuration.unix import com.google.common.jimfs.Jimfs import com.google.common.util.concurrent.Futures import com.google.common.util.concurrent.ListenableFuture import net.corda.core.* import net.corda.core.crypto.entropyToKeyPair -import net.corda.core.flows.FlowLogic import net.corda.core.identity.Party import net.corda.core.messaging.RPCOps import net.corda.core.messaging.SingleMessageRecipient @@ -18,14 +16,12 @@ import net.corda.core.node.services.* import net.corda.core.utilities.DUMMY_NOTARY_KEY import net.corda.core.utilities.loggerFor import net.corda.node.internal.AbstractNode -import net.corda.node.internal.ServiceFlowInfo import net.corda.node.services.config.NodeConfiguration import net.corda.node.services.identity.InMemoryIdentityService import net.corda.node.services.keys.E2ETestKeyManagementService import net.corda.node.services.messaging.MessagingService import net.corda.node.services.network.InMemoryNetworkMapService import net.corda.node.services.network.NetworkMapService -import net.corda.node.services.statemachine.flowVersion import net.corda.node.services.transactions.InMemoryTransactionVerifierService import net.corda.node.services.transactions.InMemoryUniquenessProvider import net.corda.node.services.transactions.SimpleNotaryService @@ -45,7 +41,6 @@ import java.security.KeyPair import java.util.* import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicInteger -import kotlin.reflect.KClass /** * A mock node brings up a suite of in-memory services in a fast manner suitable for unit testing. @@ -232,13 +227,6 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false, // It is used from the network visualiser tool. @Suppress("unused") val place: PhysicalLocation get() = findMyLocation()!! - @VisibleForTesting - fun registerServiceFlow(clientFlowClass: KClass>, - flowVersion: Int = clientFlowClass.java.flowVersion, - serviceFlowFactory: (Party) -> FlowLogic<*>) { - serviceFlowFactories[clientFlowClass.java] = ServiceFlowInfo.CorDapp(flowVersion, serviceFlowFactory) - } - fun pumpReceive(block: Boolean = false): InMemoryMessagingNetwork.MessageTransfer? { return (net as InMemoryMessagingNetwork.InMemoryMessaging).pumpReceive(block) } @@ -262,8 +250,6 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false, * Returns a node, optionally created by the passed factory method. * @param overrideServices a set of service entries to use in place of the node's default service entries, * for example where a node's service is part of a cluster. - * @param entropyRoot the initial entropy value to use when generating keys. Defaults to an (insecure) random value, - * but can be overriden to cause nodes to have stable or colliding identity/service keys. */ fun createNode(networkMapAddress: SingleMessageRecipient? = null, forcedID: Int = -1, nodeFactory: Factory = defaultFactory, start: Boolean = true, legalName: X500Name? = null, overrideServices: Map? = null, diff --git a/test-utils/src/main/kotlin/net/corda/testing/node/MockServices.kt b/test-utils/src/main/kotlin/net/corda/testing/node/MockServices.kt index c09305def7..b9bf2ae80b 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/node/MockServices.kt +++ b/test-utils/src/main/kotlin/net/corda/testing/node/MockServices.kt @@ -8,6 +8,7 @@ import net.corda.core.messaging.SingleMessageRecipient import net.corda.core.node.NodeInfo import net.corda.core.node.ServiceHub import net.corda.core.node.services.* +import net.corda.core.serialization.SerializeAsToken import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.core.transactions.SignedTransaction import net.corda.core.utilities.DUMMY_NOTARY @@ -28,6 +29,7 @@ import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream import java.io.File import java.io.InputStream +import java.nio.file.Path import java.nio.file.Paths import java.security.KeyPair import java.security.PrivateKey @@ -75,6 +77,8 @@ open class MockServices(vararg val keys: KeyPair) : ServiceHub { HibernateObserver(vaultService.rawUpdates, NodeSchemaService()) return vaultService } + + override fun cordaService(type: Class): T = throw IllegalArgumentException("${type.name} not found") } class MockKeyManagementService(val identityService: IdentityService, @@ -91,7 +95,9 @@ class MockKeyManagementService(val identityService: IdentityService, return k.public } - override fun freshKeyAndCert(identity: Party, revocationEnabled: Boolean): Pair = freshKeyAndCert(this, identityService, identity, revocationEnabled) + override fun freshKeyAndCert(identity: Party, revocationEnabled: Boolean): Pair { + return freshKeyAndCert(this, identityService, identity, revocationEnabled) + } private fun getSigningKeyPair(publicKey: PublicKey): KeyPair { val pk = publicKey.keys.first { keyStore.containsKey(it) } @@ -108,7 +114,7 @@ class MockKeyManagementService(val identityService: IdentityService, class MockAttachmentStorage : AttachmentStorage { val files = HashMap() override var automaticallyExtractAttachments = false - override var storePath = Paths.get("") + override var storePath: Path = Paths.get("") override fun openAttachment(id: SecureHash): Attachment? { val f = files[id] ?: return null diff --git a/tools/explorer/src/main/kotlin/net/corda/explorer/plugin/ExplorerPlugin.kt b/tools/explorer/src/main/kotlin/net/corda/explorer/plugin/ExplorerPlugin.kt deleted file mode 100644 index 0dbc6b5e4e..0000000000 --- a/tools/explorer/src/main/kotlin/net/corda/explorer/plugin/ExplorerPlugin.kt +++ /dev/null @@ -1,10 +0,0 @@ -package net.corda.explorer.plugin - -import net.corda.core.identity.Party -import net.corda.core.node.CordaPluginRegistry -import net.corda.flows.IssuerFlow -import java.util.function.Function - -class ExplorerPlugin : CordaPluginRegistry() { - override val servicePlugins = listOf(Function(IssuerFlow.Issuer::Service)) -} diff --git a/tools/explorer/src/main/resources/META-INF/services/net.corda.core.node.CordaPluginRegistry b/tools/explorer/src/main/resources/META-INF/services/net.corda.core.node.CordaPluginRegistry deleted file mode 100644 index bb2442e787..0000000000 --- a/tools/explorer/src/main/resources/META-INF/services/net.corda.core.node.CordaPluginRegistry +++ /dev/null @@ -1,2 +0,0 @@ -# Register a ServiceLoader service extending from net.corda.node.CordaPluginRegistry -net.corda.explorer.plugin.ExplorerPlugin From 47b1ec49aa7b520118b75e7aa2d69b9d28df8bc2 Mon Sep 17 00:00:00 2001 From: Katarzyna Streich Date: Wed, 31 May 2017 11:14:53 +0100 Subject: [PATCH 018/126] Fix Bank of Corda, Trader and Notary demos. (#752) Fix Bank of Corda, Trader and Notary demos. In Notary demo, introduce deployNodes task, that deploys all three types of Notary into different directories (so there is no need to do clean, when you want to run them one after another). --- docs/source/running-the-demos.rst | 12 +++++++----- samples/bank-of-corda-demo/build.gradle | 2 +- samples/notary-demo/build.gradle | 5 +++++ samples/trader-demo/build.gradle | 2 +- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/docs/source/running-the-demos.rst b/docs/source/running-the-demos.rst index 206a68fc48..3ce2b57cb2 100644 --- a/docs/source/running-the-demos.rst +++ b/docs/source/running-the-demos.rst @@ -123,21 +123,23 @@ You will notice that successive transactions get signed by different members of To run the Raft version of the demo from the command line in Unix: -1. Run ``./gradlew samples:notary-demo:deployNodesRaft``, which will create node directories with configs under ``samples/notary-demo/build/nodes``. -2. Run ``./samples/notary-demo/build/nodes/runnodes``, which will start the nodes in separate terminal windows/tabs. +1. Run ``./gradlew samples:notary-demo:deployNodes``, which will create all three types of notaries' node directories +with configs under ``samples/notary-demo/build/nodes/nodesRaft`` (``nodesBFT`` and ``nodesSingle`` for BFT and 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 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: -1. Run ``gradlew samples:notary-demo:deployNodesRaft``, which will create node directories with configs under ``samples\notary-demo\build\nodes``. -2. Run ``samples\notary-demo\build\nodes\runnodes``, which will start the nodes in separate terminal windows/tabs. +1. Run ``gradlew samples:notary-demo:deployNodes``, which will create all three types of notaries' node directories +with configs under ``samples/notary-demo/build/nodes/nodesRaft`` (``nodesBFT`` and ``nodesSingle`` for BFT and 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 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 ``deployNodesBFT`` instead of ``deployNodesRaft``. For a single notary node, use ``deployNodesSingle``. +To run the BFT SMaRt notary demo, use ``nodesBFT`` instead of ``nodesRaft`` in the path. For a single notary node, use ``nodesSingle``. Notary nodes store consumed states in a replicated commit log, which is backed by a H2 database on each node. You can ascertain that the commit log is synchronised across the cluster by accessing and comparing each of the nodes' backing stores diff --git a/samples/bank-of-corda-demo/build.gradle b/samples/bank-of-corda-demo/build.gradle index 39ea0da9ec..4d1b593b74 100644 --- a/samples/bank-of-corda-demo/build.gradle +++ b/samples/bank-of-corda-demo/build.gradle @@ -52,7 +52,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { cordapps = [] } node { - name "CN=BankOfCorda,O=R3,OU=Corda QA Department,L=New York,C=US" + name "CN=BankOfCorda,O=R3,L=New York,C=US" nearestCity "New York" advertisedServices = ["corda.issuer.USD"] p2pPort 10005 diff --git a/samples/notary-demo/build.gradle b/samples/notary-demo/build.gradle index 09842d2694..c526c4ab9b 100644 --- a/samples/notary-demo/build.gradle +++ b/samples/notary-demo/build.gradle @@ -49,15 +49,20 @@ publishing { } } +task deployNodes(dependsOn: ['deployNodesSingle', 'deployNodesRaft', 'deployNodesBFT']) + task deployNodesSingle(type: Cordform, dependsOn: 'jar') { + directory "./build/nodes/nodesSingle" definitionClass = 'net.corda.notarydemo.SingleNotaryCordform' } task deployNodesRaft(type: Cordform, dependsOn: 'jar') { + directory "./build/nodes/nodesRaft" definitionClass = 'net.corda.notarydemo.RaftNotaryCordform' } task deployNodesBFT(type: Cordform, dependsOn: 'jar') { + directory "./build/nodes/nodesBFT" definitionClass = 'net.corda.notarydemo.BFTNotaryCordform' } diff --git a/samples/trader-demo/build.gradle b/samples/trader-demo/build.gradle index 0d02f23f78..779fd725f8 100644 --- a/samples/trader-demo/build.gradle +++ b/samples/trader-demo/build.gradle @@ -85,7 +85,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { rpcUsers = ext.rpcUsers } node { - name "CN=BankOfCorda,O=R3,OU=corda,L=New York,C=US" + name "CN=BankOfCorda,O=R3,L=New York,C=US" nearestCity "London" advertisedServices = [] p2pPort 10011 From f148765c57b286b47904a423e70a5595c83c095a Mon Sep 17 00:00:00 2001 From: Ross Nicoll Date: Wed, 31 May 2017 01:23:06 +0100 Subject: [PATCH 019/126] Add RPC registration diagnostics Add diagnostic information if attempting to use an RPC interface with duplicate method names, rather than throwing a collection error. --- .../net/corda/node/services/messaging/RPCServer.kt | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/RPCServer.kt b/node/src/main/kotlin/net/corda/node/services/messaging/RPCServer.kt index 81935366a9..e001d4a248 100644 --- a/node/src/main/kotlin/net/corda/node/services/messaging/RPCServer.kt +++ b/node/src/main/kotlin/net/corda/node/services/messaging/RPCServer.kt @@ -40,6 +40,7 @@ import rx.Observable import rx.Subscriber import rx.Subscription import java.lang.reflect.InvocationTargetException +import java.lang.reflect.Method import java.time.Duration import java.util.* import java.util.concurrent.* @@ -92,7 +93,7 @@ class RPCServer( } private val lifeCycle = LifeCycle(State.UNSTARTED) // The methodname->Method map to use for dispatching. - private val methodTable = ops.javaClass.declaredMethods.groupBy { it.name }.mapValues { it.value.single() } + private val methodTable: Map // The observable subscription mapping. private val observableMap = createObservableSubscriptionMap() // A mapping from client addresses to IDs of associated Observables @@ -114,6 +115,16 @@ class RPCServer( private var clientBindingRemovalConsumer: ClientConsumer? = null private var serverControl: ActiveMQServerControl? = null + init { + val groupedMethods = ops.javaClass.declaredMethods.groupBy { it.name } + groupedMethods.forEach { name, methods -> + if (methods.size > 1) { + throw IllegalArgumentException("Encountered more than one method called ${name} on ${ops.javaClass.name}") + } + } + methodTable = groupedMethods.mapValues { it.value.single() } + } + private fun createObservableSubscriptionMap(): ObservableSubscriptionMap { val onObservableRemove = RemovalListener { log.debug { "Unsubscribing from Observable with id ${it.key} because of ${it.cause}" } From 08c91bd61180fe2efb1473b7430c4162852b119c Mon Sep 17 00:00:00 2001 From: Ross Nicoll Date: Wed, 31 May 2017 11:52:50 +0100 Subject: [PATCH 020/126] Add certificate to node identity (#769) Add certificate and path to node identity via the `NodeInfo` class. --- .../node/services/BFTNotaryServiceTests.kt | 2 ++ .../services/messaging/P2PMessagingTest.kt | 1 + .../services/messaging/P2PSecurityTest.kt | 4 +-- .../kotlin/net/corda/node/driver/Driver.kt | 2 +- .../net/corda/node/internal/AbstractNode.kt | 33 +++++++++++-------- .../utilities/ServiceIdentityGenerator.kt | 19 ++++++++--- .../net/corda/notarydemo/BFTNotaryCordform.kt | 3 +- .../corda/notarydemo/RaftNotaryCordform.kt | 3 +- .../net/corda/testing/node/MockServices.kt | 3 +- .../net/corda/testing/node/NodeBasedTest.kt | 2 ++ 10 files changed, 49 insertions(+), 23 deletions(-) diff --git a/node/src/integration-test/kotlin/net/corda/node/services/BFTNotaryServiceTests.kt b/node/src/integration-test/kotlin/net/corda/node/services/BFTNotaryServiceTests.kt index 155fe9c43c..57c0330e39 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/BFTNotaryServiceTests.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/BFTNotaryServiceTests.kt @@ -10,6 +10,7 @@ import net.corda.core.identity.Party import net.corda.core.node.services.ServiceInfo import net.corda.core.node.services.ServiceType import net.corda.core.utilities.ALICE +import net.corda.core.utilities.DUMMY_CA import net.corda.core.utilities.DUMMY_NOTARY import net.corda.flows.NotaryError import net.corda.flows.NotaryException @@ -66,6 +67,7 @@ class BFTNotaryServiceTests : NodeBasedTest() { val replicaNames = (0 until clusterSize).map { DUMMY_NOTARY.name.appendToCommonName(" $it") } ServiceIdentityGenerator.generateToDisk( replicaNames.map { baseDirectory(it) }, + DUMMY_CA, serviceType.id, clusterName, minCorrectReplicas(clusterSize)) diff --git a/node/src/integration-test/kotlin/net/corda/services/messaging/P2PMessagingTest.kt b/node/src/integration-test/kotlin/net/corda/services/messaging/P2PMessagingTest.kt index b4332d56b9..04b69f6c86 100644 --- a/node/src/integration-test/kotlin/net/corda/services/messaging/P2PMessagingTest.kt +++ b/node/src/integration-test/kotlin/net/corda/services/messaging/P2PMessagingTest.kt @@ -64,6 +64,7 @@ class P2PMessagingTest : NodeBasedTest() { fun `communicating with a distributed service which the network map node is part of`() { ServiceIdentityGenerator.generateToDisk( listOf(DUMMY_MAP.name, SERVICE_2_NAME).map { baseDirectory(it) }, + DUMMY_CA, RaftValidatingNotaryService.type.id, DISTRIBUTED_SERVICE_NAME) diff --git a/node/src/integration-test/kotlin/net/corda/services/messaging/P2PSecurityTest.kt b/node/src/integration-test/kotlin/net/corda/services/messaging/P2PSecurityTest.kt index 95fb7c9b23..79d042304b 100644 --- a/node/src/integration-test/kotlin/net/corda/services/messaging/P2PSecurityTest.kt +++ b/node/src/integration-test/kotlin/net/corda/services/messaging/P2PSecurityTest.kt @@ -3,13 +3,13 @@ package net.corda.services.messaging import com.google.common.util.concurrent.ListenableFuture import net.corda.core.crypto.X509Utilities import net.corda.core.getOrThrow -import net.corda.core.identity.Party import net.corda.core.node.NodeInfo import net.corda.core.random63BitValue import net.corda.core.seconds import net.corda.core.utilities.BOB import net.corda.core.utilities.DUMMY_BANK_A import net.corda.core.utilities.DUMMY_BANK_B +import net.corda.core.utilities.getTestPartyAndCertificate import net.corda.node.internal.NetworkMapInfo import net.corda.node.services.config.configureWithDevSSLCertificate import net.corda.node.services.messaging.sendRequest @@ -66,7 +66,7 @@ class P2PSecurityTest : NodeBasedTest() { } private fun SimpleNode.registerWithNetworkMap(registrationName: X500Name): ListenableFuture { - val nodeInfo = NodeInfo(net.myAddress, Party(registrationName, identity.public), MOCK_VERSION_INFO.platformVersion) + val nodeInfo = NodeInfo(net.myAddress, getTestPartyAndCertificate(registrationName, identity.public), MOCK_VERSION_INFO.platformVersion) val registration = NodeRegistration(nodeInfo, System.currentTimeMillis(), AddOrRemove.ADD, Instant.MAX) val request = RegistrationRequest(registration.toWire(keyService, identity.public), net.myAddress) return net.sendRequest(NetworkMapService.REGISTER_TOPIC, request, networkMapNode.net.myAddress) diff --git a/node/src/main/kotlin/net/corda/node/driver/Driver.kt b/node/src/main/kotlin/net/corda/node/driver/Driver.kt index 0d9bfe3273..58ecd6c17d 100644 --- a/node/src/main/kotlin/net/corda/node/driver/Driver.kt +++ b/node/src/main/kotlin/net/corda/node/driver/Driver.kt @@ -556,7 +556,7 @@ class DriverDSL( ): ListenableFuture>> { val nodeNames = (0 until clusterSize).map { DUMMY_NOTARY.name.appendToCommonName(" $it") } val paths = nodeNames.map { baseDirectory(it) } - ServiceIdentityGenerator.generateToDisk(paths, type.id, notaryName) + ServiceIdentityGenerator.generateToDisk(paths, DUMMY_CA, type.id, notaryName) val advertisedServices = setOf(ServiceInfo(type, notaryName)) val notaryClusterAddress = portAllocation.nextHostAndPort() diff --git a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt index c87b0361b0..cd23b29918 100644 --- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt @@ -12,6 +12,7 @@ import net.corda.core.* import net.corda.core.crypto.* import net.corda.core.flows.* import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.messaging.CordaRPCOps import net.corda.core.messaging.RPCOps import net.corda.core.messaging.SingleMessageRecipient @@ -708,11 +709,11 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, stateMachineRecordedTransactionMappingStorage: StateMachineRecordedTransactionMappingStorage) = StorageServiceImpl(attachments, transactionStorage, stateMachineRecordedTransactionMappingStorage) - protected fun obtainLegalIdentity(): Party = identityKeyPair.first + protected fun obtainLegalIdentity(): PartyAndCertificate = identityKeyPair.first protected fun obtainLegalIdentityKey(): KeyPair = identityKeyPair.second private val identityKeyPair by lazy { obtainKeyPair("identity", configuration.myLegalName) } - private fun obtainKeyPair(serviceId: String, serviceName: X500Name): Pair { + private fun obtainKeyPair(serviceId: String, serviceName: X500Name): Pair { // Load the private identity key, creating it if necessary. The identity key is a long term well known key that // is distributed to other peers and we use it (or a key signed by it) when we need to do something // "permissioned". The identity file is what gets distributed and contains the node's legal name along with @@ -724,21 +725,24 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, val privateKeyAlias = "$serviceId-private-key" val privKeyFile = configuration.baseDirectory / privateKeyAlias val pubIdentityFile = configuration.baseDirectory / "$serviceId-public" - val identityAndKey = keyStore.certificateAndKeyPair(privateKeyAlias)?.let { (cert, keyPair) -> + val certificateAndKeyPair = keyStore.certificateAndKeyPair(privateKeyAlias) + val identityCertPathAndKey: Pair = if (certificateAndKeyPair != null) { + val (cert, keyPair) = certificateAndKeyPair // Get keys from keystore. val loadedServiceName = X509CertificateHolder(cert.encoded).subject if (loadedServiceName != serviceName) { throw ConfigurationException("The legal name in the config file doesn't match the stored identity keystore:" + "$serviceName vs $loadedServiceName") } - Pair(Party(loadedServiceName, keyPair.public), keyPair) - } ?: if (privKeyFile.exists()) { + val certPath = X509Utilities.createCertificatePath(cert, cert, revocationEnabled = false) + Pair(PartyAndCertificate(loadedServiceName, keyPair.public, cert, certPath), keyPair) + } else if (privKeyFile.exists()) { // Get keys from key file. // TODO: this is here to smooth out the key storage transition, remove this in future release. // Check that the identity in the config file matches the identity file we have stored to disk. // This is just a sanity check. It shouldn't fail unless the admin has fiddled with the files and messed // things up for us. - val myIdentity = pubIdentityFile.readAll().deserialize() + val myIdentity = pubIdentityFile.readAll().deserialize() if (myIdentity.name != serviceName) throw ConfigurationException("The legal name in the config file doesn't match the stored identity file:" + "$serviceName vs ${myIdentity.name}") @@ -749,14 +753,18 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, } Pair(myIdentity, keyPair) } else { + val clientCA = keyStore.certificateAndKeyPair(X509Utilities.CORDA_CLIENT_CA)!! // Create new keys and store in keystore. log.info("Identity key not found, generating fresh key!") val keyPair: KeyPair = generateKeyPair() + val cert = X509Utilities.createCertificate(CertificateType.IDENTITY, clientCA.certificate, clientCA.keyPair, serviceName, keyPair.public) + val certPath = X509Utilities.createCertificatePath(cert, cert, revocationEnabled = false) keyStore.save(serviceName, privateKeyAlias, keyPair) - Pair(Party(serviceName, keyPair.public), keyPair) + require(certPath.certificates.isNotEmpty()) { "Certificate path cannot be empty" } + Pair(PartyAndCertificate(serviceName, keyPair.public, cert, certPath), keyPair) } - partyKeys += identityAndKey.second - return identityAndKey + partyKeys += identityCertPathAndKey.second + return identityCertPathAndKey } protected open fun generateKeyPair() = cryptoGenerateKeyPair() @@ -783,11 +791,10 @@ private class KeyStoreWrapper(private val storePath: Path, private val storePass } fun save(serviceName: X500Name, privateKeyAlias: String, keyPair: KeyPair) { - val clientCA = keyStore.getCertificateAndKeyPair(X509Utilities.CORDA_CLIENT_CA, storePassword) val converter = JcaX509CertificateConverter() - val cert = X509Utilities.createCertificate(CertificateType.IDENTITY, clientCA.certificate, clientCA.keyPair, serviceName, keyPair.public) - keyStore.addOrReplaceKey(privateKeyAlias, keyPair.private, storePassword.toCharArray(), - arrayOf(converter.getCertificate(cert), *keyStore.getCertificateChain(X509Utilities.CORDA_CLIENT_CA))) + val clientCA = keyStore.getCertificateAndKeyPair(X509Utilities.CORDA_CLIENT_CA, storePassword) + val cert = converter.getCertificate(X509Utilities.createCertificate(CertificateType.IDENTITY, clientCA.certificate, clientCA.keyPair, serviceName, keyPair.public)) + keyStore.addOrReplaceKey(privateKeyAlias, keyPair.private, storePassword.toCharArray(), arrayOf(cert, *keyStore.getCertificateChain(X509Utilities.CORDA_CLIENT_CA))) keyStore.save(storePath, storePassword) } } diff --git a/node/src/main/kotlin/net/corda/node/utilities/ServiceIdentityGenerator.kt b/node/src/main/kotlin/net/corda/node/utilities/ServiceIdentityGenerator.kt index 31d0bce621..21e535e51e 100644 --- a/node/src/main/kotlin/net/corda/node/utilities/ServiceIdentityGenerator.kt +++ b/node/src/main/kotlin/net/corda/node/utilities/ServiceIdentityGenerator.kt @@ -1,8 +1,8 @@ package net.corda.node.utilities -import net.corda.core.crypto.CompositeKey +import net.corda.core.crypto.* import net.corda.core.identity.Party -import net.corda.core.crypto.generateKeyPair +import net.corda.core.identity.PartyAndCertificate import net.corda.core.serialization.serialize import net.corda.core.serialization.storageKryo import net.corda.core.utilities.loggerFor @@ -20,16 +20,27 @@ object ServiceIdentityGenerator { * This method should be called *before* any of the nodes are started. * * @param dirs List of node directories to place the generated identity and key pairs in. + * @param serviceCa Certificate authority to use when signing identity certificates. * @param serviceId The service id of the distributed service. * @param serviceName The legal name of the distributed service. * @param threshold The threshold for the generated group [CompositeKey]. */ - fun generateToDisk(dirs: List, serviceId: String, serviceName: X500Name, threshold: Int = 1) { + // TODO: This needs to write out to the key store, not just files on disk + fun generateToDisk(dirs: List, + serviceCa: CertificateAndKeyPair, + serviceId: String, + serviceName: X500Name, + threshold: Int = 1) { log.trace { "Generating a group identity \"serviceName\" for nodes: ${dirs.joinToString()}" } val keyPairs = (1..dirs.size).map { generateKeyPair() } val notaryKey = CompositeKey.Builder().addKeys(keyPairs.map { it.public }).build(threshold) - val notaryParty = Party(serviceName, notaryKey).serialize() + // TODO: This doesn't work until we have composite keys in X.509 certificates, so we make up a certificate that nothing checks + // val notaryCert = X509Utilities.createCertificate(CertificateType.IDENTITY, serviceCa.certificate, + // serviceCa.keyPair, serviceName, notaryKey) + val notaryCert = X509Utilities.createSelfSignedCACertificate(serviceName, generateKeyPair()) + val notaryCertPath = X509Utilities.createCertificatePath(serviceCa.certificate, notaryCert, revocationEnabled = false) + val notaryParty = PartyAndCertificate(serviceName, notaryKey, notaryCert, notaryCertPath).serialize() keyPairs.zip(dirs) { keyPair, dir -> Files.createDirectories(dir) diff --git a/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/BFTNotaryCordform.kt b/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/BFTNotaryCordform.kt index 06a198c41d..a1decb054c 100644 --- a/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/BFTNotaryCordform.kt +++ b/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/BFTNotaryCordform.kt @@ -5,6 +5,7 @@ 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_CA import net.corda.demorun.util.* import net.corda.demorun.runNodes import net.corda.node.services.transactions.BFTNonValidatingNotaryService @@ -64,6 +65,6 @@ object BFTNotaryCordform : CordformDefinition("build" / "notary-demo-nodes", not } override fun setup(context: CordformContext) { - ServiceIdentityGenerator.generateToDisk(notaryNames.map { context.baseDirectory(it) }, advertisedService.type.id, clusterName, minCorrectReplicas(clusterSize)) + ServiceIdentityGenerator.generateToDisk(notaryNames.map { context.baseDirectory(it) }, DUMMY_CA, advertisedService.type.id, clusterName, minCorrectReplicas(clusterSize)) } } diff --git a/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/RaftNotaryCordform.kt b/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/RaftNotaryCordform.kt index 7c2dd027bf..fd818bb9a3 100644 --- a/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/RaftNotaryCordform.kt +++ b/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/RaftNotaryCordform.kt @@ -6,6 +6,7 @@ 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_CA import net.corda.core.utilities.DUMMY_NOTARY import net.corda.demorun.util.* import net.corda.node.services.transactions.RaftValidatingNotaryService @@ -65,6 +66,6 @@ object RaftNotaryCordform : CordformDefinition("build" / "notary-demo-nodes", no } override fun setup(context: CordformContext) { - ServiceIdentityGenerator.generateToDisk(notaryNames.map { context.baseDirectory(it) }, advertisedService.type.id, clusterName) + ServiceIdentityGenerator.generateToDisk(notaryNames.map { context.baseDirectory(it) }, DUMMY_CA, advertisedService.type.id, clusterName) } } diff --git a/test-utils/src/main/kotlin/net/corda/testing/node/MockServices.kt b/test-utils/src/main/kotlin/net/corda/testing/node/MockServices.kt index b9bf2ae80b..a41d27720e 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/node/MockServices.kt +++ b/test-utils/src/main/kotlin/net/corda/testing/node/MockServices.kt @@ -12,6 +12,7 @@ import net.corda.core.serialization.SerializeAsToken import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.core.transactions.SignedTransaction import net.corda.core.utilities.DUMMY_NOTARY +import net.corda.core.utilities.getTestPartyAndCertificate import net.corda.node.services.identity.InMemoryIdentityService import net.corda.node.services.keys.freshKeyAndCert import net.corda.node.services.persistence.InMemoryStateMachineRecordedTransactionMappingStorage @@ -68,7 +69,7 @@ open class MockServices(vararg val keys: KeyPair) : ServiceHub { override val vaultService: VaultService get() = throw UnsupportedOperationException() override val networkMapCache: NetworkMapCache get() = throw UnsupportedOperationException() override val clock: Clock get() = Clock.systemUTC() - override val myInfo: NodeInfo get() = NodeInfo(object : SingleMessageRecipient {}, Party(MEGA_CORP.name, key.public), MOCK_VERSION_INFO.platformVersion) + override val myInfo: NodeInfo get() = NodeInfo(object : SingleMessageRecipient {}, getTestPartyAndCertificate(MEGA_CORP.name, key.public), MOCK_VERSION_INFO.platformVersion) override val transactionVerifierService: TransactionVerifierService get() = InMemoryTransactionVerifierService(2) fun makeVaultService(dataSourceProps: Properties): VaultService { diff --git a/test-utils/src/main/kotlin/net/corda/testing/node/NodeBasedTest.kt b/test-utils/src/main/kotlin/net/corda/testing/node/NodeBasedTest.kt index 7b44b39910..47afafc3dc 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/node/NodeBasedTest.kt +++ b/test-utils/src/main/kotlin/net/corda/testing/node/NodeBasedTest.kt @@ -8,6 +8,7 @@ import net.corda.core.crypto.appendToCommonName import net.corda.core.crypto.commonName import net.corda.core.node.services.ServiceInfo import net.corda.core.node.services.ServiceType +import net.corda.core.utilities.DUMMY_CA import net.corda.core.utilities.DUMMY_MAP import net.corda.core.utilities.WHITESPACE import net.corda.node.driver.addressMustNotBeBound @@ -110,6 +111,7 @@ abstract class NodeBasedTest { serviceType: ServiceType = RaftValidatingNotaryService.type): ListenableFuture> { ServiceIdentityGenerator.generateToDisk( (0 until clusterSize).map { baseDirectory(notaryName.appendToCommonName("-$it")) }, + DUMMY_CA, serviceType.id, notaryName) From 34eb5a3b7045748513d463926bfebde8e8d8f7c8 Mon Sep 17 00:00:00 2001 From: Ross Nicoll Date: Wed, 31 May 2017 14:45:58 +0100 Subject: [PATCH 021/126] Store certificate and path with well known identity (#726) * Construct standard flows using PartyAndCertificate, and add support for launching flows that are constructed with PartyAndCertificate or just Party. * Store PartyAndCertificate in network map service * Expand identity service to store certificates along with all identities. --- .../kotlin/net/corda/core/flows/TxKeyFlow.kt | 56 ++++++-------- .../core/identity/PartyAndCertificate.kt | 3 - .../net/corda/core/messaging/CordaRPCOps.kt | 7 +- .../kotlin/net/corda/core/node/NodeInfo.kt | 10 ++- .../net/corda/core/node/PluginServiceHub.kt | 3 +- .../core/node/services/IdentityService.kt | 42 +++++----- .../net/corda/core/node/services/Services.kt | 4 +- .../flows/AbstractStateReplacementFlow.kt | 3 +- .../net/corda/flows/CollectSignaturesFlow.kt | 3 +- .../net/corda/flows/FetchAttachmentsFlow.kt | 4 +- .../kotlin/net/corda/flows/FetchDataFlow.kt | 3 +- .../net/corda/flows/FetchTransactionsFlow.kt | 4 +- .../net/corda/flows/NotaryChangeFlow.kt | 3 +- .../main/kotlin/net/corda/flows/NotaryFlow.kt | 3 +- .../corda/flows/ResolveTransactionsFlow.kt | 8 +- .../net/corda/flows/TwoPartyDealFlow.kt | 5 +- .../core/flows/CollectSignaturesFlowTests.kt | 5 +- .../net/corda/core/flows/TxKeyFlowTests.kt | 8 +- .../AttachmentSerializationTest.kt | 3 +- docs/source/changelog.rst | 9 +++ .../corda/docs/FxTransactionBuildTutorial.kt | 12 +-- .../net/corda/flows/TwoPartyTradeFlow.kt | 8 +- .../AbstractStateReplacementFlowTest.java | 3 +- .../services/messaging/P2PSecurityTest.kt | 9 ++- .../kotlin/net/corda/node/driver/Driver.kt | 9 ++- .../net/corda/node/internal/AbstractNode.kt | 15 +++- .../node/internal/InitiatedFlowFactory.kt | 9 ++- .../corda/node/services/CoreFlowHandlers.kt | 17 ++-- .../identity/InMemoryIdentityService.kt | 77 ++++++++++++++----- .../keys/E2ETestKeyManagementService.kt | 7 +- .../net/corda/node/services/keys/KMSUtils.kt | 43 +++++++---- .../keys/PersistentKeyManagementService.kt | 9 ++- .../services/network/NetworkMapService.kt | 5 +- .../network/PersistentNetworkMapService.kt | 15 ++-- .../statemachine/StateMachineManager.kt | 3 +- .../BFTNonValidatingNotaryService.kt | 8 +- .../node/services/transactions/BFTSMaRt.kt | 8 +- .../transactions/NonValidatingNotaryFlow.kt | 4 +- .../services/transactions/NotaryService.kt | 8 +- .../RaftNonValidatingNotaryService.kt | 4 +- .../RaftValidatingNotaryService.kt | 4 +- .../transactions/SimpleNotaryService.kt | 4 +- .../transactions/ValidatingNotaryFlow.kt | 4 +- .../transactions/ValidatingNotaryService.kt | 4 +- .../net/corda/node/InteractiveShellTest.kt | 7 +- .../node/messaging/TwoPartyTradeFlowTests.kt | 8 +- .../node/services/MockServiceHubInternal.kt | 1 + .../corda/node/services/NotaryChangeTests.kt | 3 +- .../events/NodeSchedulerServiceTest.kt | 3 +- .../network/InMemoryIdentityServiceTests.kt | 37 ++++----- .../persistence/DataVendingServiceTests.kt | 6 +- .../statemachine/FlowFrameworkTests.kt | 5 +- .../NetworkisRegistrationHelperTest.kt | 2 + .../kotlin/net/corda/irs/flows/FixingFlow.kt | 6 +- .../net/corda/irs/simulation/IRSSimulation.kt | 6 +- .../kotlin/net/corda/vega/api/PortfolioApi.kt | 5 +- .../net/corda/vega/flows/IRSTradeFlow.kt | 3 +- .../kotlin/net/corda/vega/flows/SimmFlow.kt | 3 +- .../net/corda/vega/flows/StateRevisionFlow.kt | 3 +- .../net/corda/traderdemo/flow/BuyerFlow.kt | 4 +- .../net/corda/traderdemo/flow/SellerFlow.kt | 5 +- .../kotlin/net/corda/testing/CoreTestUtils.kt | 12 +-- .../kotlin/net/corda/testing/node/MockNode.kt | 10 ++- .../net/corda/testing/node/MockServices.kt | 16 ++-- .../net/corda/testing/node/SimpleNode.kt | 6 +- .../views/cordapps/cash/NewTransaction.kt | 2 +- 66 files changed, 379 insertions(+), 249 deletions(-) diff --git a/core/src/main/kotlin/net/corda/core/flows/TxKeyFlow.kt b/core/src/main/kotlin/net/corda/core/flows/TxKeyFlow.kt index 417ea63d2e..571174942a 100644 --- a/core/src/main/kotlin/net/corda/core/flows/TxKeyFlow.kt +++ b/core/src/main/kotlin/net/corda/core/flows/TxKeyFlow.kt @@ -3,45 +3,34 @@ package net.corda.core.flows import co.paralleluniverse.fibers.Suspendable import net.corda.core.identity.AnonymousParty import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate +import net.corda.core.serialization.CordaSerializable import net.corda.core.utilities.ProgressTracker import net.corda.core.utilities.unwrap -import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.cert.X509CertificateHolder import java.security.cert.CertPath -import java.security.cert.X509Certificate /** * Very basic flow which exchanges transaction key and certificate paths between two parties in a transaction. * This is intended for use as a subflow of another flow. */ object TxKeyFlow { - abstract class AbstractIdentityFlow(val otherSide: Party): FlowLogic() { - fun validateIdentity(untrustedIdentity: Pair): AnonymousIdentity { - val (wellKnownCert, certPath) = untrustedIdentity - val theirCert = certPath.certificates.last() - // TODO: Don't trust self-signed certificates - return if (theirCert is X509Certificate) { - val certName = X500Name(theirCert.subjectDN.name) - if (certName == otherSide.name) { - val anonymousParty = AnonymousParty(theirCert.publicKey) - serviceHub.identityService.registerPath(wellKnownCert, anonymousParty, certPath) - AnonymousIdentity(certPath, X509CertificateHolder(theirCert.encoded), anonymousParty) - } else { - throw IllegalStateException("Expected certificate subject to be ${otherSide.name} but found $certName") - } - } else { - throw IllegalStateException("Expected an X.509 certificate but received ${theirCert.javaClass.name}") - } + abstract class AbstractIdentityFlow(val otherSide: PartyAndCertificate, val revocationEnabled: Boolean): FlowLogic() { + fun validateIdentity(untrustedIdentity: AnonymousIdentity): AnonymousIdentity { + val (certPath, theirCert, txIdentity) = untrustedIdentity + if (theirCert.subject == otherSide.name) { + serviceHub.identityService.registerAnonymousIdentity(txIdentity, otherSide, certPath) + return AnonymousIdentity(certPath, theirCert, txIdentity) + } else + throw IllegalStateException("Expected certificate subject to be ${otherSide.name} but found ${theirCert.subject}") } } @StartableByRPC @InitiatingFlow - class Requester(otherSide: Party, - val revocationEnabled: Boolean, - override val progressTracker: ProgressTracker) : AbstractIdentityFlow>(otherSide) { - constructor(otherSide: Party, revocationEnabled: Boolean) : this(otherSide, revocationEnabled, tracker()) - + class Requester(otherSide: PartyAndCertificate, + override val progressTracker: ProgressTracker) : AbstractIdentityFlow>(otherSide, false) { + constructor(otherSide: PartyAndCertificate) : this(otherSide, tracker()) companion object { object AWAITING_KEY : ProgressTracker.Step("Awaiting key") @@ -52,9 +41,10 @@ object TxKeyFlow { override fun call(): Map { progressTracker.currentStep = AWAITING_KEY val myIdentityFragment = serviceHub.keyManagementService.freshKeyAndCert(serviceHub.myInfo.legalIdentity, revocationEnabled) - val theirIdentity = receive>(otherSide).unwrap { validateIdentity(it) } - send(otherSide, myIdentityFragment) - return mapOf(Pair(otherSide, AnonymousIdentity(myIdentityFragment)), + val myIdentity = AnonymousIdentity(myIdentityFragment) + val theirIdentity = receive(otherSide).unwrap { validateIdentity(it) } + send(otherSide, myIdentity) + return mapOf(Pair(otherSide, myIdentity), Pair(serviceHub.myInfo.legalIdentity, theirIdentity)) } } @@ -64,7 +54,7 @@ object TxKeyFlow { * counterparty and as the result from the flow. */ @InitiatedBy(Requester::class) - class Provider(otherSide: Party) : AbstractIdentityFlow(otherSide) { + class Provider(otherSide: PartyAndCertificate) : AbstractIdentityFlow>(otherSide, false) { companion object { object SENDING_KEY : ProgressTracker.Step("Sending key") } @@ -72,15 +62,19 @@ object TxKeyFlow { override val progressTracker: ProgressTracker = ProgressTracker(SENDING_KEY) @Suspendable - override fun call() { + override fun call(): Map { val revocationEnabled = false progressTracker.currentStep = SENDING_KEY val myIdentityFragment = serviceHub.keyManagementService.freshKeyAndCert(serviceHub.myInfo.legalIdentity, revocationEnabled) - send(otherSide, myIdentityFragment) - receive>(otherSide).unwrap { validateIdentity(it) } + val myIdentity = AnonymousIdentity(myIdentityFragment) + send(otherSide, myIdentity) + val theirIdentity = receive(otherSide).unwrap { validateIdentity(it) } + return mapOf(Pair(otherSide, myIdentity), + Pair(serviceHub.myInfo.legalIdentity, theirIdentity)) } } + @CordaSerializable data class AnonymousIdentity( val certPath: CertPath, val certificate: X509CertificateHolder, diff --git a/core/src/main/kotlin/net/corda/core/identity/PartyAndCertificate.kt b/core/src/main/kotlin/net/corda/core/identity/PartyAndCertificate.kt index b758dbfd0d..a145ce7021 100644 --- a/core/src/main/kotlin/net/corda/core/identity/PartyAndCertificate.kt +++ b/core/src/main/kotlin/net/corda/core/identity/PartyAndCertificate.kt @@ -1,12 +1,9 @@ package net.corda.core.identity -import net.corda.core.contracts.PartyAndReference -import net.corda.core.serialization.OpaqueBytes import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.cert.X509CertificateHolder import java.security.PublicKey import java.security.cert.CertPath -import java.security.cert.X509Certificate /** * A full party plus the X.509 certificate and path linking the party back to a trust root. diff --git a/core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt b/core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt index 190f2456a0..99d53d0b7d 100644 --- a/core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt +++ b/core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt @@ -11,6 +11,7 @@ import net.corda.core.flows.FlowInitiator import net.corda.core.flows.FlowLogic import net.corda.core.flows.StateMachineRunId import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.NodeInfo import net.corda.core.node.services.NetworkMapCache import net.corda.core.node.services.StateMachineTransactionMapping @@ -231,18 +232,18 @@ interface CordaRPCOps : RPCOps { /** * Returns the [Party] corresponding to the given key, if found. */ - fun partyFromKey(key: PublicKey): Party? + fun partyFromKey(key: PublicKey): PartyAndCertificate? /** * Returns the [Party] with the given name as it's [Party.name] */ @Deprecated("Use partyFromX500Name instead") - fun partyFromName(name: String): Party? + fun partyFromName(name: String): PartyAndCertificate? /** * Returns the [Party] with the X.500 principal as it's [Party.name] */ - fun partyFromX500Name(x500Name: X500Name): Party? + fun partyFromX500Name(x500Name: X500Name): PartyAndCertificate? /** Enumerates the class names of the flows that this node knows about. */ fun registeredFlows(): List diff --git a/core/src/main/kotlin/net/corda/core/node/NodeInfo.kt b/core/src/main/kotlin/net/corda/core/node/NodeInfo.kt index e7c542cdca..805d5ad0a7 100644 --- a/core/src/main/kotlin/net/corda/core/node/NodeInfo.kt +++ b/core/src/main/kotlin/net/corda/core/node/NodeInfo.kt @@ -1,24 +1,28 @@ package net.corda.core.node import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.messaging.SingleMessageRecipient import net.corda.core.node.services.ServiceInfo import net.corda.core.node.services.ServiceType import net.corda.core.serialization.CordaSerializable +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter +import java.security.cert.TrustAnchor +import java.security.cert.X509Certificate /** * Information for an advertised service including the service specific identity information. * The identity can be used in flows and is distinct from the Node's legalIdentity */ @CordaSerializable -data class ServiceEntry(val info: ServiceInfo, val identity: Party) +data class ServiceEntry(val info: ServiceInfo, val identity: PartyAndCertificate) /** * Info about a network node that acts on behalf of some form of contract party. */ @CordaSerializable data class NodeInfo(val address: SingleMessageRecipient, - val legalIdentity: Party, + val legalIdentity: PartyAndCertificate, val platformVersion: Int, var advertisedServices: List = emptyList(), val physicalLocation: PhysicalLocation? = null) { @@ -26,6 +30,6 @@ data class NodeInfo(val address: SingleMessageRecipient, require(advertisedServices.none { it.identity == legalIdentity }) { "Service identities must be different from node legal identity" } } - val notaryIdentity: Party get() = advertisedServices.single { it.info.type.isNotary() }.identity + val notaryIdentity: PartyAndCertificate get() = advertisedServices.single { it.info.type.isNotary() }.identity fun serviceIdentities(type: ServiceType): List = advertisedServices.filter { it.info.type.isSubTypeOf(type) }.map { it.identity } } diff --git a/core/src/main/kotlin/net/corda/core/node/PluginServiceHub.kt b/core/src/main/kotlin/net/corda/core/node/PluginServiceHub.kt index be193d2dfe..dbb6133ce9 100644 --- a/core/src/main/kotlin/net/corda/core/node/PluginServiceHub.kt +++ b/core/src/main/kotlin/net/corda/core/node/PluginServiceHub.kt @@ -2,6 +2,7 @@ package net.corda.core.node import net.corda.core.flows.FlowLogic import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate /** * A service hub to be used by the [CordaPluginRegistry] @@ -9,5 +10,5 @@ import net.corda.core.identity.Party interface PluginServiceHub : ServiceHub { @Deprecated("This is no longer used. Instead annotate the flows produced by your factory with @InitiatedBy and have " + "them point to the initiating flow class.", level = DeprecationLevel.ERROR) - fun registerFlowInitiator(initiatingFlowClass: Class>, serviceFlowFactory: (Party) -> FlowLogic<*>) = Unit + fun registerFlowInitiator(initiatingFlowClass: Class>, serviceFlowFactory: (PartyAndCertificate) -> FlowLogic<*>) = Unit } diff --git a/core/src/main/kotlin/net/corda/core/node/services/IdentityService.kt b/core/src/main/kotlin/net/corda/core/node/services/IdentityService.kt index 71cb0c7b38..97b3529668 100644 --- a/core/src/main/kotlin/net/corda/core/node/services/IdentityService.kt +++ b/core/src/main/kotlin/net/corda/core/node/services/IdentityService.kt @@ -1,15 +1,16 @@ package net.corda.core.node.services import net.corda.core.contracts.PartyAndReference -import net.corda.core.crypto.toStringShort import net.corda.core.identity.AbstractParty import net.corda.core.identity.AnonymousParty import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import org.bouncycastle.asn1.x500.X500Name -import org.bouncycastle.cert.X509CertificateHolder +import java.security.InvalidAlgorithmParameterException import java.security.PublicKey import java.security.cert.CertPath -import java.security.cert.X509Certificate +import java.security.cert.CertificateExpiredException +import java.security.cert.CertificateNotYetValidException /** * An identity service maintains an bidirectional map of [Party]s to their associated public keys and thus supports @@ -17,21 +18,26 @@ import java.security.cert.X509Certificate * service would provide. */ interface IdentityService { - fun registerIdentity(party: Party) + /** + * Verify and then store a well known identity. + * + * @param party a party representing a legal entity. + * @throws IllegalArgumentException if the certificate path is invalid, or if there is already an existing + * certificate chain for the anonymous party. + */ + @Throws(CertificateExpiredException::class, CertificateNotYetValidException::class, InvalidAlgorithmParameterException::class) + fun registerIdentity(party: PartyAndCertificate) /** - * Verify and then store the certificates proving that an anonymous party's key is owned by the given full - * party. + * Verify and then store an identity. * - * @param trustedRoot trusted root certificate, typically the R3 master signing certificate. - * @param anonymousParty an anonymised party belonging to the legal entity. - * @param path certificate path from the trusted root to the anonymised party. - * @throws IllegalArgumentException if the chain does not link the two parties, or if there is already an existing - * certificate chain for the anonymous party. Anonymous parties must always resolve to a single owning party. + * @param anonymousParty a party representing a legal entity in a transaction. + * @param path certificate path from the trusted root to the party. + * @throws IllegalArgumentException if the certificate path is invalid, or if there is already an existing + * certificate chain for the anonymous party. */ - // TODO: Move this into internal identity service once available - @Throws(IllegalArgumentException::class) - fun registerPath(trustedRoot: X509CertificateHolder, anonymousParty: AnonymousParty, path: CertPath) + @Throws(CertificateExpiredException::class, CertificateNotYetValidException::class, InvalidAlgorithmParameterException::class) + fun registerAnonymousIdentity(anonymousParty: AnonymousParty, fullParty: PartyAndCertificate, path: CertPath) /** * Asserts that an anonymous party maps to the given full party, by looking up the certificate chain associated with @@ -52,10 +58,10 @@ interface IdentityService { // indefinitely. It may be that in the long term we need to drop or archive very old Party information for space, // but for now this is not supported. - fun partyFromKey(key: PublicKey): Party? + fun partyFromKey(key: PublicKey): PartyAndCertificate? @Deprecated("Use partyFromX500Name") - fun partyFromName(name: String): Party? - fun partyFromX500Name(principal: X500Name): Party? + fun partyFromName(name: String): PartyAndCertificate? + fun partyFromX500Name(principal: X500Name): PartyAndCertificate? /** * Resolve the well known identity of a party. If the party passed in is already a well known identity @@ -63,7 +69,7 @@ interface IdentityService { * * @return the well known identity, or null if unknown. */ - fun partyFromAnonymous(party: AbstractParty): Party? + fun partyFromAnonymous(party: AbstractParty): PartyAndCertificate? /** * Resolve the well known identity of a party. If the party passed in is already a well known identity diff --git a/core/src/main/kotlin/net/corda/core/node/services/Services.kt b/core/src/main/kotlin/net/corda/core/node/services/Services.kt index 97cc2bce84..cc891304f9 100644 --- a/core/src/main/kotlin/net/corda/core/node/services/Services.kt +++ b/core/src/main/kotlin/net/corda/core/node/services/Services.kt @@ -10,6 +10,7 @@ import net.corda.core.crypto.keys import net.corda.core.flows.FlowException import net.corda.core.identity.AbstractParty import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.services.vault.PageSpecification import net.corda.core.node.services.vault.QueryCriteria import net.corda.core.node.services.vault.Sort @@ -20,6 +21,7 @@ import net.corda.core.transactions.LedgerTransaction import net.corda.core.transactions.TransactionBuilder import net.corda.core.transactions.WireTransaction import org.bouncycastle.cert.X509CertificateHolder +import org.bouncycastle.operator.ContentSigner import rx.Observable import java.io.InputStream import java.security.PublicKey @@ -399,7 +401,7 @@ interface KeyManagementService { * @return X.509 certificate and path to the trust root. */ @Suspendable - fun freshKeyAndCert(identity: Party, revocationEnabled: Boolean): Pair + fun freshKeyAndCert(identity: PartyAndCertificate, revocationEnabled: Boolean): Pair /** Using the provided signing [PublicKey] internally looks up the matching [PrivateKey] and signs the data. * @param bytes The data to sign over using the chosen key. diff --git a/core/src/main/kotlin/net/corda/flows/AbstractStateReplacementFlow.kt b/core/src/main/kotlin/net/corda/flows/AbstractStateReplacementFlow.kt index f00941e786..ba2251c272 100644 --- a/core/src/main/kotlin/net/corda/flows/AbstractStateReplacementFlow.kt +++ b/core/src/main/kotlin/net/corda/flows/AbstractStateReplacementFlow.kt @@ -10,6 +10,7 @@ import net.corda.core.flows.FlowException import net.corda.core.flows.FlowLogic import net.corda.core.identity.AbstractParty import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.serialization.CordaSerializable import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.WireTransaction @@ -119,7 +120,7 @@ abstract class AbstractStateReplacementFlow { // Type parameter should ideally be Unit but that prevents Java code from subclassing it (https://youtrack.jetbrains.com/issue/KT-15964). // We use Void? instead of Unit? as that's what you'd use in Java. - abstract class Acceptor(val otherSide: Party, + abstract class Acceptor(val otherSide: PartyAndCertificate, override val progressTracker: ProgressTracker = tracker()) : FlowLogic() { companion object { object VERIFYING : ProgressTracker.Step("Verifying state replacement proposal") diff --git a/core/src/main/kotlin/net/corda/flows/CollectSignaturesFlow.kt b/core/src/main/kotlin/net/corda/flows/CollectSignaturesFlow.kt index acfbba8541..64280d1c8c 100644 --- a/core/src/main/kotlin/net/corda/flows/CollectSignaturesFlow.kt +++ b/core/src/main/kotlin/net/corda/flows/CollectSignaturesFlow.kt @@ -7,6 +7,7 @@ import net.corda.core.crypto.toBase58String import net.corda.core.flows.FlowException import net.corda.core.flows.FlowLogic import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.ServiceHub import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.WireTransaction @@ -173,7 +174,7 @@ class CollectSignaturesFlow(val partiallySignedTx: SignedTransaction, * * @param otherParty The counter-party which is providing you a transaction to sign. */ -abstract class SignTransactionFlow(val otherParty: Party, +abstract class SignTransactionFlow(val otherParty: PartyAndCertificate, override val progressTracker: ProgressTracker = tracker()) : FlowLogic() { companion object { diff --git a/core/src/main/kotlin/net/corda/flows/FetchAttachmentsFlow.kt b/core/src/main/kotlin/net/corda/flows/FetchAttachmentsFlow.kt index 3ca8c8f695..5ac5e6c329 100644 --- a/core/src/main/kotlin/net/corda/flows/FetchAttachmentsFlow.kt +++ b/core/src/main/kotlin/net/corda/flows/FetchAttachmentsFlow.kt @@ -5,7 +5,7 @@ import net.corda.core.contracts.Attachment import net.corda.core.crypto.SecureHash import net.corda.core.crypto.sha256 import net.corda.core.flows.InitiatingFlow -import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.serialization.SerializationToken import net.corda.core.serialization.SerializeAsToken import net.corda.core.serialization.SerializeAsTokenContext @@ -16,7 +16,7 @@ import net.corda.core.serialization.SerializeAsTokenContext */ @InitiatingFlow class FetchAttachmentsFlow(requests: Set, - otherSide: Party) : FetchDataFlow(requests, otherSide) { + otherSide: PartyAndCertificate) : FetchDataFlow(requests, otherSide) { override fun load(txid: SecureHash): Attachment? = serviceHub.storageService.attachments.openAttachment(txid) diff --git a/core/src/main/kotlin/net/corda/flows/FetchDataFlow.kt b/core/src/main/kotlin/net/corda/flows/FetchDataFlow.kt index efbe720210..0603a15fb7 100644 --- a/core/src/main/kotlin/net/corda/flows/FetchDataFlow.kt +++ b/core/src/main/kotlin/net/corda/flows/FetchDataFlow.kt @@ -6,6 +6,7 @@ import net.corda.core.crypto.SecureHash import net.corda.core.flows.FlowException import net.corda.core.flows.FlowLogic import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.serialization.CordaSerializable import net.corda.core.utilities.UntrustworthyData import net.corda.core.utilities.unwrap @@ -31,7 +32,7 @@ import java.util.* */ abstract class FetchDataFlow( protected val requests: Set, - protected val otherSide: Party) : FlowLogic>() { + protected val otherSide: PartyAndCertificate) : FlowLogic>() { @CordaSerializable class DownloadedVsRequestedDataMismatch(val requested: SecureHash, val got: SecureHash) : IllegalArgumentException() diff --git a/core/src/main/kotlin/net/corda/flows/FetchTransactionsFlow.kt b/core/src/main/kotlin/net/corda/flows/FetchTransactionsFlow.kt index 6e9c1055a8..e0dcb24266 100644 --- a/core/src/main/kotlin/net/corda/flows/FetchTransactionsFlow.kt +++ b/core/src/main/kotlin/net/corda/flows/FetchTransactionsFlow.kt @@ -2,7 +2,7 @@ package net.corda.flows import net.corda.core.crypto.SecureHash import net.corda.core.flows.InitiatingFlow -import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.transactions.SignedTransaction /** @@ -14,7 +14,7 @@ import net.corda.core.transactions.SignedTransaction * the database, because it's up to the caller to actually verify the transactions are valid. */ @InitiatingFlow -class FetchTransactionsFlow(requests: Set, otherSide: Party) : +class FetchTransactionsFlow(requests: Set, otherSide: PartyAndCertificate) : FetchDataFlow(requests, otherSide) { override fun load(txid: SecureHash): SignedTransaction? { diff --git a/core/src/main/kotlin/net/corda/flows/NotaryChangeFlow.kt b/core/src/main/kotlin/net/corda/flows/NotaryChangeFlow.kt index 8de5b096e7..172d2787ce 100644 --- a/core/src/main/kotlin/net/corda/flows/NotaryChangeFlow.kt +++ b/core/src/main/kotlin/net/corda/flows/NotaryChangeFlow.kt @@ -4,6 +4,7 @@ import net.corda.core.contracts.* import net.corda.core.flows.InitiatingFlow import net.corda.core.identity.AbstractParty import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.TransactionBuilder import net.corda.core.utilities.ProgressTracker @@ -21,7 +22,7 @@ import java.security.PublicKey @InitiatingFlow class NotaryChangeFlow( originalState: StateAndRef, - newNotary: Party, + newNotary: PartyAndCertificate, progressTracker: ProgressTracker = tracker()) : AbstractStateReplacementFlow.Instigator(originalState, newNotary, progressTracker) { diff --git a/core/src/main/kotlin/net/corda/flows/NotaryFlow.kt b/core/src/main/kotlin/net/corda/flows/NotaryFlow.kt index 3c67bb35e3..999c6f688c 100644 --- a/core/src/main/kotlin/net/corda/flows/NotaryFlow.kt +++ b/core/src/main/kotlin/net/corda/flows/NotaryFlow.kt @@ -11,6 +11,7 @@ import net.corda.core.flows.FlowException import net.corda.core.flows.FlowLogic import net.corda.core.flows.InitiatingFlow import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.services.TimeWindowChecker import net.corda.core.node.services.UniquenessException import net.corda.core.node.services.UniquenessProvider @@ -96,7 +97,7 @@ object NotaryFlow { * Additional transaction validation logic can be added when implementing [receiveAndVerifyTx]. */ // See AbstractStateReplacementFlow.Acceptor for why it's Void? - abstract class Service(val otherSide: Party, + abstract class Service(val otherSide: PartyAndCertificate, val timeWindowChecker: TimeWindowChecker, val uniquenessProvider: UniquenessProvider) : FlowLogic() { @Suspendable diff --git a/core/src/main/kotlin/net/corda/flows/ResolveTransactionsFlow.kt b/core/src/main/kotlin/net/corda/flows/ResolveTransactionsFlow.kt index 1b6d3d4b91..fe17f8708e 100644 --- a/core/src/main/kotlin/net/corda/flows/ResolveTransactionsFlow.kt +++ b/core/src/main/kotlin/net/corda/flows/ResolveTransactionsFlow.kt @@ -5,7 +5,7 @@ import net.corda.core.checkedAdd import net.corda.core.crypto.SecureHash import net.corda.core.flows.FlowLogic import net.corda.core.getOrThrow -import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.serialization.CordaSerializable import net.corda.core.transactions.LedgerTransaction import net.corda.core.transactions.SignedTransaction @@ -30,7 +30,7 @@ import java.util.* * The flow returns a list of verified [LedgerTransaction] objects, in a depth-first order. */ class ResolveTransactionsFlow(private val txHashes: Set, - private val otherSide: Party) : FlowLogic>() { + private val otherSide: PartyAndCertificate) : FlowLogic>() { companion object { private fun dependencyIDs(wtx: WireTransaction) = wtx.inputs.map { it.txhash }.toSet() @@ -82,14 +82,14 @@ class ResolveTransactionsFlow(private val txHashes: Set, /** * Resolve the full history of a transaction and verify it with its dependencies. */ - constructor(stx: SignedTransaction, otherSide: Party) : this(stx.tx, otherSide) { + constructor(stx: SignedTransaction, otherSide: PartyAndCertificate) : this(stx.tx, otherSide) { this.stx = stx } /** * Resolve the full history of a transaction and verify it with its dependencies. */ - constructor(wtx: WireTransaction, otherSide: Party) : this(dependencyIDs(wtx), otherSide) { + constructor(wtx: WireTransaction, otherSide: PartyAndCertificate) : this(dependencyIDs(wtx), otherSide) { this.wtx = wtx } diff --git a/core/src/main/kotlin/net/corda/flows/TwoPartyDealFlow.kt b/core/src/main/kotlin/net/corda/flows/TwoPartyDealFlow.kt index 45b8694c80..5108f01b3e 100644 --- a/core/src/main/kotlin/net/corda/flows/TwoPartyDealFlow.kt +++ b/core/src/main/kotlin/net/corda/flows/TwoPartyDealFlow.kt @@ -7,6 +7,7 @@ import net.corda.core.crypto.SecureHash import net.corda.core.flows.FlowLogic import net.corda.core.identity.AbstractParty import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.NodeInfo import net.corda.core.node.services.ServiceType import net.corda.core.seconds @@ -45,7 +46,7 @@ object TwoPartyDealFlow { abstract val payload: Any abstract val notaryNode: NodeInfo - abstract val otherParty: Party + abstract val otherParty: PartyAndCertificate abstract val myKey: PublicKey @Suspendable override fun call(): SignedTransaction { @@ -149,7 +150,7 @@ object TwoPartyDealFlow { /** * One side of the flow for inserting a pre-agreed deal. */ - open class Instigator(override val otherParty: Party, + open class Instigator(override val otherParty: PartyAndCertificate, override val payload: AutoOffer, override val myKey: PublicKey, override val progressTracker: ProgressTracker = Primary.tracker()) : Primary() { diff --git a/core/src/test/kotlin/net/corda/core/flows/CollectSignaturesFlowTests.kt b/core/src/test/kotlin/net/corda/core/flows/CollectSignaturesFlowTests.kt index 1396799b8c..08c19b7b00 100644 --- a/core/src/test/kotlin/net/corda/core/flows/CollectSignaturesFlowTests.kt +++ b/core/src/test/kotlin/net/corda/core/flows/CollectSignaturesFlowTests.kt @@ -7,6 +7,7 @@ import net.corda.core.contracts.TransactionType import net.corda.core.contracts.requireThat import net.corda.core.getOrThrow import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.transactions.SignedTransaction import net.corda.core.utilities.unwrap import net.corda.flows.CollectSignaturesFlow @@ -54,7 +55,7 @@ class CollectSignaturesFlowTests { // "collectSignaturesFlow" and "SignTransactionFlow" can be used in practise. object TestFlow { @InitiatingFlow - class Initiator(val state: DummyContract.MultiOwnerState, val otherParty: Party) : FlowLogic() { + class Initiator(val state: DummyContract.MultiOwnerState, val otherParty: PartyAndCertificate) : FlowLogic() { @Suspendable override fun call(): SignedTransaction { send(otherParty, state) @@ -114,7 +115,7 @@ class CollectSignaturesFlowTests { } @InitiatedBy(TestFlowTwo.Initiator::class) - class Responder(val otherParty: Party) : FlowLogic() { + class Responder(val otherParty: PartyAndCertificate) : FlowLogic() { @Suspendable override fun call(): SignedTransaction { val flow = object : SignTransactionFlow(otherParty) { @Suspendable override fun checkTransaction(stx: SignedTransaction) = requireThat { diff --git a/core/src/test/kotlin/net/corda/core/flows/TxKeyFlowTests.kt b/core/src/test/kotlin/net/corda/core/flows/TxKeyFlowTests.kt index ee69808222..6f6f49182f 100644 --- a/core/src/test/kotlin/net/corda/core/flows/TxKeyFlowTests.kt +++ b/core/src/test/kotlin/net/corda/core/flows/TxKeyFlowTests.kt @@ -3,6 +3,7 @@ package net.corda.core.flows import net.corda.core.getOrThrow import net.corda.core.identity.AbstractParty import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.utilities.ALICE import net.corda.core.utilities.BOB import net.corda.core.utilities.DUMMY_NOTARY @@ -26,12 +27,11 @@ class TxKeyFlowTests { net = MockNetwork(false, true) // Set up values we'll need - val revocationEnabled = false val notaryNode = net.createNotaryNode(null, DUMMY_NOTARY.name) val aliceNode = net.createPartyNode(notaryNode.info.address, ALICE.name) val bobNode = net.createPartyNode(notaryNode.info.address, BOB.name) - val alice: Party = aliceNode.services.myInfo.legalIdentity - val bob: Party = bobNode.services.myInfo.legalIdentity + val alice: PartyAndCertificate = aliceNode.services.myInfo.legalIdentity + val bob: PartyAndCertificate = bobNode.services.myInfo.legalIdentity aliceNode.services.identityService.registerIdentity(bob) aliceNode.services.identityService.registerIdentity(notaryNode.info.legalIdentity) bobNode.services.identityService.registerIdentity(alice) @@ -39,7 +39,7 @@ class TxKeyFlowTests { // Run the flows bobNode.registerInitiatedFlow(TxKeyFlow.Provider::class.java) - val requesterFlow = aliceNode.services.startFlow(TxKeyFlow.Requester(bob, revocationEnabled)) + val requesterFlow = aliceNode.services.startFlow(TxKeyFlow.Requester(bob)) // Get the results val actual: Map = requesterFlow.resultFuture.getOrThrow() diff --git a/core/src/test/kotlin/net/corda/core/serialization/AttachmentSerializationTest.kt b/core/src/test/kotlin/net/corda/core/serialization/AttachmentSerializationTest.kt index 2e300844c9..4eb871ad5e 100644 --- a/core/src/test/kotlin/net/corda/core/serialization/AttachmentSerializationTest.kt +++ b/core/src/test/kotlin/net/corda/core/serialization/AttachmentSerializationTest.kt @@ -7,6 +7,7 @@ import net.corda.core.flows.FlowLogic import net.corda.core.flows.InitiatingFlow import net.corda.core.getOrThrow import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.messaging.RPCOps import net.corda.core.messaging.SingleMessageRecipient import net.corda.core.node.services.ServiceInfo @@ -139,7 +140,7 @@ class AttachmentSerializationTest { private fun launchFlow(clientLogic: ClientLogic, rounds: Int) { server.registerFlowFactory(ClientLogic::class.java, object : InitiatedFlowFactory { - override fun createFlow(platformVersion: Int, otherParty: Party, sessionInit: SessionInit): ServerLogic { + override fun createFlow(platformVersion: Int, otherParty: PartyAndCertificate, sessionInit: SessionInit): ServerLogic { return ServerLogic(otherParty) } }, ServerLogic::class.java, track = false) diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index 38c6fb8e15..f3ae69dbbf 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -43,9 +43,18 @@ UNRELEASED * There is a new ``AbstractParty`` superclass to ``Party``, which contains just the public key. This now replaces use of ``Party`` and ``PublicKey`` in state objects, and allows use of full or anonymised parties depending on use-case. + * A new ``PartyAndCertificate`` class has been added which contains an X.509 certificate and certificate path back + to a network trust root. This is widely used in place of ``Party`` inside Corda, with the exception of a few cases + where proof of identity is not required. * Names of parties are now stored as a ``X500Name`` rather than a ``String``, to correctly enforce basic structure of the name. As a result all node legal names must now be structured as X.500 distinguished names. +* Flows can now accept ``PartyAndCertificate`` instead of ``Party`` in their constructor, which should be the default for + new flows. The sample flows have been updated to use ``PartyAndCertificate`` to illustrate this. + +* The identity management service takes an optional network trust root which it will validate certificate paths to, if + provided. A later release will make this a required parameter. + * There are major changes to transaction signing in flows: * You should use the new ``CollectSignaturesFlow`` and corresponding ``SignTransactionFlow`` which handle most diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/FxTransactionBuildTutorial.kt b/docs/source/example-code/src/main/kotlin/net/corda/docs/FxTransactionBuildTutorial.kt index 33d75ce6ee..6f7f9e3a24 100644 --- a/docs/source/example-code/src/main/kotlin/net/corda/docs/FxTransactionBuildTutorial.kt +++ b/docs/source/example-code/src/main/kotlin/net/corda/docs/FxTransactionBuildTutorial.kt @@ -12,6 +12,8 @@ import net.corda.core.flows.FlowLogic import net.corda.core.flows.InitiatedBy import net.corda.core.flows.InitiatingFlow import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate +import net.corda.core.node.PluginServiceHub import net.corda.core.node.ServiceHub import net.corda.core.node.services.unconsumedStates import net.corda.core.serialization.CordaSerializable @@ -24,8 +26,8 @@ import java.util.* @CordaSerializable private data class FxRequest(val tradeId: String, val amount: Amount>, - val owner: Party, - val counterparty: Party, + val owner: PartyAndCertificate, + val counterparty: PartyAndCertificate, val notary: Party? = null) @CordaSerializable @@ -101,8 +103,8 @@ private fun prepareOurInputsAndOutputs(serviceHub: ServiceHub, request: FxReques class ForeignExchangeFlow(val tradeId: String, val baseCurrencyAmount: Amount>, val quoteCurrencyAmount: Amount>, - val baseCurrencyBuyer: Party, - val baseCurrencySeller: Party) : FlowLogic() { + val baseCurrencyBuyer: PartyAndCertificate, + val baseCurrencySeller: PartyAndCertificate) : FlowLogic() { @Suspendable override fun call(): SecureHash { // Select correct sides of the Fx exchange to query for. @@ -206,7 +208,7 @@ class ForeignExchangeFlow(val tradeId: String, } @InitiatedBy(ForeignExchangeFlow::class) -class ForeignExchangeRemoteFlow(val source: Party) : FlowLogic() { +class ForeignExchangeRemoteFlow(val source: PartyAndCertificate) : FlowLogic() { @Suspendable override fun call() { // Initial receive from remote party diff --git a/finance/src/main/kotlin/net/corda/flows/TwoPartyTradeFlow.kt b/finance/src/main/kotlin/net/corda/flows/TwoPartyTradeFlow.kt index 49c6d7b26a..210cc9b46f 100644 --- a/finance/src/main/kotlin/net/corda/flows/TwoPartyTradeFlow.kt +++ b/finance/src/main/kotlin/net/corda/flows/TwoPartyTradeFlow.kt @@ -7,7 +7,7 @@ import net.corda.core.crypto.DigitalSignature import net.corda.core.flows.FlowException import net.corda.core.flows.FlowLogic import net.corda.core.identity.AnonymousParty -import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.NodeInfo import net.corda.core.seconds import net.corda.core.serialization.CordaSerializable @@ -61,7 +61,7 @@ object TwoPartyTradeFlow { data class SignaturesFromSeller(val sellerSig: DigitalSignature.WithKey, val notarySig: DigitalSignature.WithKey) - open class Seller(val otherParty: Party, + open class Seller(val otherParty: PartyAndCertificate, val notaryNode: NodeInfo, val assetToSell: StateAndRef, val price: Amount, @@ -141,8 +141,8 @@ object TwoPartyTradeFlow { } } - open class Buyer(val otherParty: Party, - val notary: Party, + open class Buyer(val otherParty: PartyAndCertificate, + val notary: PartyAndCertificate, val acceptablePrice: Amount, val typeToBuy: Class) : FlowLogic() { // DOCSTART 2 diff --git a/finance/src/test/java/net/corda/flows/AbstractStateReplacementFlowTest.java b/finance/src/test/java/net/corda/flows/AbstractStateReplacementFlowTest.java index 657f80059d..4230b63b82 100644 --- a/finance/src/test/java/net/corda/flows/AbstractStateReplacementFlowTest.java +++ b/finance/src/test/java/net/corda/flows/AbstractStateReplacementFlowTest.java @@ -1,6 +1,7 @@ package net.corda.flows; import net.corda.core.identity.Party; +import net.corda.core.identity.PartyAndCertificate; import net.corda.core.utilities.*; import org.jetbrains.annotations.*; @@ -9,7 +10,7 @@ public class AbstractStateReplacementFlowTest { // Acceptor used to have a type parameter of Unit which prevented Java code from subclassing it (https://youtrack.jetbrains.com/issue/KT-15964). private static class TestAcceptorCanBeInheritedInJava extends AbstractStateReplacementFlow.Acceptor { - public TestAcceptorCanBeInheritedInJava(@NotNull Party otherSide, @NotNull ProgressTracker progressTracker) { + public TestAcceptorCanBeInheritedInJava(@NotNull PartyAndCertificate otherSide, @NotNull ProgressTracker progressTracker) { super(otherSide, progressTracker); } diff --git a/node/src/integration-test/kotlin/net/corda/services/messaging/P2PSecurityTest.kt b/node/src/integration-test/kotlin/net/corda/services/messaging/P2PSecurityTest.kt index 79d042304b..2e37fa7595 100644 --- a/node/src/integration-test/kotlin/net/corda/services/messaging/P2PSecurityTest.kt +++ b/node/src/integration-test/kotlin/net/corda/services/messaging/P2PSecurityTest.kt @@ -24,6 +24,7 @@ import net.corda.testing.node.SimpleNode import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.assertj.core.api.Assertions.assertThatThrownBy import org.bouncycastle.asn1.x500.X500Name +import org.bouncycastle.cert.X509CertificateHolder import org.junit.Test import java.time.Instant import java.util.concurrent.TimeoutException @@ -56,17 +57,19 @@ class P2PSecurityTest : NodeBasedTest() { } } - private fun startSimpleNode(legalName: X500Name): SimpleNode { + private fun startSimpleNode(legalName: X500Name, + trustRoot: X509CertificateHolder? = null): SimpleNode { val config = TestNodeConfiguration( baseDirectory = baseDirectory(legalName), myLegalName = legalName, networkMapService = NetworkMapInfo(networkMapNode.configuration.p2pAddress, networkMapNode.info.legalIdentity.name)) config.configureWithDevSSLCertificate() // This creates the node's TLS cert with the CN as the legal name - return SimpleNode(config).apply { start() } + return SimpleNode(config, trustRoot = trustRoot).apply { start() } } private fun SimpleNode.registerWithNetworkMap(registrationName: X500Name): ListenableFuture { - val nodeInfo = NodeInfo(net.myAddress, getTestPartyAndCertificate(registrationName, identity.public), MOCK_VERSION_INFO.platformVersion) + val legalIdentity = getTestPartyAndCertificate(registrationName, identity.public) + val nodeInfo = NodeInfo(net.myAddress, legalIdentity, MOCK_VERSION_INFO.platformVersion) val registration = NodeRegistration(nodeInfo, System.currentTimeMillis(), AddOrRemove.ADD, Instant.MAX) val request = RegistrationRequest(registration.toWire(keyService, identity.public), net.myAddress) return net.sendRequest(NetworkMapService.REGISTER_TOPIC, request, networkMapNode.net.myAddress) diff --git a/node/src/main/kotlin/net/corda/node/driver/Driver.kt b/node/src/main/kotlin/net/corda/node/driver/Driver.kt index 58ecd6c17d..237ee6e7e6 100644 --- a/node/src/main/kotlin/net/corda/node/driver/Driver.kt +++ b/node/src/main/kotlin/net/corda/node/driver/Driver.kt @@ -14,6 +14,9 @@ import net.corda.core.crypto.X509Utilities import net.corda.core.crypto.appendToCommonName import net.corda.core.crypto.commonName import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate +import net.corda.core.internal.ShutdownHook +import net.corda.core.internal.addShutdownHook import net.corda.core.messaging.CordaRPCOps import net.corda.core.node.NodeInfo import net.corda.core.node.services.ServiceInfo @@ -28,8 +31,6 @@ 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.core.internal.ShutdownHook -import net.corda.core.internal.addShutdownHook import okhttp3.OkHttpClient import okhttp3.Request import org.bouncycastle.asn1.x500.X500Name @@ -96,7 +97,7 @@ interface DriverDSLExposedInterface : CordformContext { clusterSize: Int = 3, type: ServiceType = RaftValidatingNotaryService.type, verifierType: VerifierType = VerifierType.InMemory, - rpcUsers: List = emptyList()): Future>> + rpcUsers: List = emptyList()): Future>> /** * Starts a web server for a node @@ -553,7 +554,7 @@ class DriverDSL( type: ServiceType, verifierType: VerifierType, rpcUsers: List - ): ListenableFuture>> { + ): ListenableFuture>> { val nodeNames = (0 until clusterSize).map { DUMMY_NOTARY.name.appendToCommonName(" $it") } val paths = nodeNames.map { baseDirectory(it) } ServiceIdentityGenerator.generateToDisk(paths, DUMMY_CA, type.id, notaryName) diff --git a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt index cd23b29918..f1375da51b 100644 --- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt @@ -71,6 +71,7 @@ import java.nio.file.Path import java.nio.file.Paths import java.security.KeyPair import java.security.KeyStoreException +import java.security.cert.X509Certificate import java.time.Clock import java.util.* import java.util.concurrent.ConcurrentHashMap @@ -346,7 +347,13 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, } private fun > registerInitiatedFlowInternal(initiatedFlow: Class, track: Boolean): Observable { - val ctor = initiatedFlow.getDeclaredConstructor(Party::class.java).apply { isAccessible = true } + val ctor = try { + initiatedFlow.getDeclaredConstructor(PartyAndCertificate::class.java).apply { isAccessible = true } + } catch(ex: NoSuchMethodException) { + // Fall back to a constructor that takes in a Party + // TODO: Consider removing for 1.0 release, as flows should generally take the more detailed class + initiatedFlow.getDeclaredConstructor(Party::class.java).apply { isAccessible = true } + } val initiatingFlow = initiatedFlow.requireAnnotation().value.java val (version, classWithAnnotation) = initiatingFlow.flowVersionAndInitiatingClass require(classWithAnnotation == initiatingFlow) { @@ -394,7 +401,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, * @suppress */ @VisibleForTesting - fun installCoreFlow(clientFlowClass: KClass>, flowFactory: (Party, Int) -> FlowLogic<*>) { + fun installCoreFlow(clientFlowClass: KClass>, flowFactory: (PartyAndCertificate, Int) -> FlowLogic<*>) { require(clientFlowClass.java.flowVersionAndInitiatingClass.first == 1) { "${InitiatingFlow::class.java.name}.version not applicable for core flows; their version is the node's platform version" } @@ -656,7 +663,9 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, protected abstract fun makeUniquenessProvider(type: ServiceType): UniquenessProvider protected open fun makeIdentityService(): IdentityService { - val service = InMemoryIdentityService() + val keyStore = KeyStoreUtilities.loadKeyStore(configuration.trustStoreFile, configuration.trustStorePassword) + val trustRoot = keyStore.getCertificate(X509Utilities.CORDA_ROOT_CA) as? X509Certificate + val service = InMemoryIdentityService(trustRoot = trustRoot) service.registerIdentity(info.legalIdentity) services.networkMapCache.partyNodes.forEach { service.registerIdentity(it.legalIdentity) } netMapCache.changed.subscribe { mapChange -> diff --git a/node/src/main/kotlin/net/corda/node/internal/InitiatedFlowFactory.kt b/node/src/main/kotlin/net/corda/node/internal/InitiatedFlowFactory.kt index 06a0a7cc61..6bbe03e9bc 100644 --- a/node/src/main/kotlin/net/corda/node/internal/InitiatedFlowFactory.kt +++ b/node/src/main/kotlin/net/corda/node/internal/InitiatedFlowFactory.kt @@ -2,19 +2,20 @@ package net.corda.node.internal import net.corda.core.flows.FlowLogic import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.node.services.statemachine.SessionInit interface InitiatedFlowFactory> { - fun createFlow(platformVersion: Int, otherParty: Party, sessionInit: SessionInit): F + fun createFlow(platformVersion: Int, otherParty: PartyAndCertificate, sessionInit: SessionInit): F - data class Core>(val factory: (Party, Int) -> F) : InitiatedFlowFactory { - override fun createFlow(platformVersion: Int, otherParty: Party, sessionInit: SessionInit): F { + data class Core>(val factory: (PartyAndCertificate, Int) -> F) : InitiatedFlowFactory { + override fun createFlow(platformVersion: Int, otherParty: PartyAndCertificate, sessionInit: SessionInit): F { return factory(otherParty, platformVersion) } } data class CorDapp>(val version: Int, val factory: (Party) -> F) : InitiatedFlowFactory { - override fun createFlow(platformVersion: Int, otherParty: Party, sessionInit: SessionInit): F { + override fun createFlow(platformVersion: Int, otherParty: PartyAndCertificate, sessionInit: SessionInit): F { // TODO Add support for multiple versions of the same flow when CorDapps are loaded in separate class loaders if (sessionInit.flowVerison == version) return factory(otherParty) throw SessionRejectException( diff --git a/node/src/main/kotlin/net/corda/node/services/CoreFlowHandlers.kt b/node/src/main/kotlin/net/corda/node/services/CoreFlowHandlers.kt index 33658c855c..b05cd06952 100644 --- a/node/src/main/kotlin/net/corda/node/services/CoreFlowHandlers.kt +++ b/node/src/main/kotlin/net/corda/node/services/CoreFlowHandlers.kt @@ -5,10 +5,11 @@ import net.corda.core.contracts.ContractState import net.corda.core.contracts.TransactionType import net.corda.core.contracts.UpgradedContract import net.corda.core.contracts.requireThat -import net.corda.core.identity.Party import net.corda.core.crypto.SecureHash import net.corda.core.flows.FlowException import net.corda.core.flows.FlowLogic +import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.transactions.SignedTransaction import net.corda.core.utilities.unwrap import net.corda.flows.* @@ -25,20 +26,20 @@ import net.corda.flows.* * * Additionally, because nodes do not store invalid transactions, requesting such a transaction will always yield null. */ -class FetchTransactionsHandler(otherParty: Party) : FetchDataHandler(otherParty) { +class FetchTransactionsHandler(otherParty: PartyAndCertificate) : FetchDataHandler(otherParty) { override fun getData(id: SecureHash): SignedTransaction? { return serviceHub.storageService.validatedTransactions.getTransaction(id) } } // TODO: Use Artemis message streaming support here, called "large messages". This avoids the need to buffer. -class FetchAttachmentsHandler(otherParty: Party) : FetchDataHandler(otherParty) { +class FetchAttachmentsHandler(otherParty: PartyAndCertificate) : FetchDataHandler(otherParty) { override fun getData(id: SecureHash): ByteArray? { return serviceHub.storageService.attachments.openAttachment(id)?.open()?.readBytes() } } -abstract class FetchDataHandler(val otherParty: Party) : FlowLogic() { +abstract class FetchDataHandler(val otherParty: PartyAndCertificate) : FlowLogic() { @Suspendable @Throws(FetchDataFlow.HashNotFound::class) override fun call() { @@ -59,7 +60,7 @@ abstract class FetchDataHandler(val otherParty: Party) : FlowLogic( // includes us in any outside that list. Potentially just if it includes any outside that list at all. // TODO: Do we want to be able to reject specific transactions on more complex rules, for example reject incoming // cash without from unknown parties? -class NotifyTransactionHandler(val otherParty: Party) : FlowLogic() { +class NotifyTransactionHandler(val otherParty: PartyAndCertificate) : FlowLogic() { @Suspendable override fun call() { val request = receive(otherParty).unwrap { it } @@ -68,7 +69,7 @@ class NotifyTransactionHandler(val otherParty: Party) : FlowLogic() { } } -class NotaryChangeHandler(otherSide: Party) : AbstractStateReplacementFlow.Acceptor(otherSide) { +class NotaryChangeHandler(otherSide: PartyAndCertificate) : AbstractStateReplacementFlow.Acceptor(otherSide) { /** * Check the notary change proposal. * @@ -76,7 +77,7 @@ class NotaryChangeHandler(otherSide: Party) : AbstractStateReplacementFlow.Accep * and is also in a geographically convenient location we can just automatically approve the change. * TODO: In more difficult cases this should call for human attention to manually verify and approve the proposal */ - override fun verifyProposal(proposal: AbstractStateReplacementFlow.Proposal): Unit { + override fun verifyProposal(proposal: AbstractStateReplacementFlow.Proposal): Unit { val state = proposal.stateRef val proposedTx = proposal.stx.tx @@ -101,7 +102,7 @@ class NotaryChangeHandler(otherSide: Party) : AbstractStateReplacementFlow.Accep } } -class ContractUpgradeHandler(otherSide: Party) : AbstractStateReplacementFlow.Acceptor>>(otherSide) { +class ContractUpgradeHandler(otherSide: PartyAndCertificate) : AbstractStateReplacementFlow.Acceptor>>(otherSide) { @Suspendable @Throws(StateReplacementException::class) override fun verifyProposal(proposal: AbstractStateReplacementFlow.Proposal>>) { diff --git a/node/src/main/kotlin/net/corda/node/services/identity/InMemoryIdentityService.kt b/node/src/main/kotlin/net/corda/node/services/identity/InMemoryIdentityService.kt index 5e60a04cfd..92fbe5adb6 100644 --- a/node/src/main/kotlin/net/corda/node/services/identity/InMemoryIdentityService.kt +++ b/node/src/main/kotlin/net/corda/node/services/identity/InMemoryIdentityService.kt @@ -2,10 +2,12 @@ package net.corda.node.services.identity import net.corda.core.contracts.PartyAndReference import net.corda.core.contracts.requireThat +import net.corda.core.crypto.subject import net.corda.core.crypto.toStringShort import net.corda.core.identity.AbstractParty import net.corda.core.identity.AnonymousParty import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.services.IdentityService import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.core.utilities.loggerFor @@ -27,15 +29,20 @@ import javax.annotation.concurrent.ThreadSafe * @param certPaths initial set of certificate paths for the service, typically only used for unit tests. */ @ThreadSafe -class InMemoryIdentityService(identities: Iterable = emptySet(), - certPaths: Map = emptyMap()) : SingletonSerializeAsToken(), IdentityService { +class InMemoryIdentityService(identities: Iterable = emptySet(), + certPaths: Map = emptyMap(), + val trustRoot: X509Certificate?) : SingletonSerializeAsToken(), IdentityService { + constructor(identities: Iterable = emptySet(), + certPaths: Map = emptyMap(), + trustRoot: X509CertificateHolder?) : this(identities, certPaths, trustRoot?.let { JcaX509CertificateConverter().getCertificate(it) }) companion object { private val log = loggerFor() } - private val keyToParties = ConcurrentHashMap() - private val principalToParties = ConcurrentHashMap() - private val partyToPath = ConcurrentHashMap() + private val trustAnchor: TrustAnchor? = trustRoot?.let { cert -> TrustAnchor(cert, null) } + private val keyToParties = ConcurrentHashMap() + private val principalToParties = ConcurrentHashMap() + private val partyToPath = ConcurrentHashMap() init { keyToParties.putAll(identities.associateBy { it.owningKey } ) @@ -43,8 +50,29 @@ class InMemoryIdentityService(identities: Iterable = emptySet(), partyToPath.putAll(certPaths) } - override fun registerIdentity(party: Party) { + // TODO: Check the validation logic + @Throws(CertificateExpiredException::class, CertificateNotYetValidException::class, InvalidAlgorithmParameterException::class) + override fun registerIdentity(party: PartyAndCertificate) { + require(party.certPath.certificates.isNotEmpty()) { "Certificate path must contain at least one certificate" } + // Validate the chain first, before we do anything clever with it + val validatorParameters = if (trustAnchor != null) { + PKIXParameters(setOf(trustAnchor)) + } else { + // TODO: We should always require a full chain back to a trust anchor, but until we have a network + // trust anchor everywhere, this will have to do. + val converter = JcaX509CertificateConverter() + PKIXParameters(setOf(TrustAnchor(converter.getCertificate(party.certificate), null))) + } + val validator = CertPathValidator.getInstance("PKIX") + validatorParameters.isRevocationEnabled = false + // TODO: val result = validator.validate(party.certPath, validatorParameters) as PKIXCertPathValidatorResult + // require(trustAnchor == null || result.trustAnchor == trustAnchor) + // require(result.publicKey == party.owningKey) { "Certificate path validation must end at transaction key ${anonymousParty.owningKey.toStringShort()}, found ${result.publicKey.toStringShort()}" } + log.trace { "Registering identity $party" } + require(Arrays.equals(party.certificate.subjectPublicKeyInfo.encoded, party.owningKey.encoded)) { "Party certificate must end with party's public key" } + + partyToPath[party] = party.certPath keyToParties[party.owningKey] = party principalToParties[party.name] = party } @@ -52,12 +80,12 @@ class InMemoryIdentityService(identities: Iterable = emptySet(), // We give the caller a copy of the data set to avoid any locking problems override fun getAllIdentities(): Iterable = ArrayList(keyToParties.values) - override fun partyFromKey(key: PublicKey): Party? = keyToParties[key] + override fun partyFromKey(key: PublicKey): PartyAndCertificate? = keyToParties[key] @Deprecated("Use partyFromX500Name") - override fun partyFromName(name: String): Party? = principalToParties[X500Name(name)] - override fun partyFromX500Name(principal: X500Name): Party? = principalToParties[principal] - override fun partyFromAnonymous(party: AbstractParty): Party? { - return if (party is Party) { + override fun partyFromName(name: String): PartyAndCertificate? = principalToParties[X500Name(name)] + override fun partyFromX500Name(principal: X500Name): PartyAndCertificate? = principalToParties[principal] + override fun partyFromAnonymous(party: AbstractParty): PartyAndCertificate? { + return if (party is PartyAndCertificate) { party } else { partyFromKey(party.owningKey) @@ -84,20 +112,29 @@ class InMemoryIdentityService(identities: Iterable = emptySet(), override fun pathForAnonymous(anonymousParty: AnonymousParty): CertPath? = partyToPath[anonymousParty] @Throws(CertificateExpiredException::class, CertificateNotYetValidException::class, InvalidAlgorithmParameterException::class) - override fun registerPath(trustedRoot: X509CertificateHolder, anonymousParty: AnonymousParty, path: CertPath) { - val converter = JcaX509CertificateConverter() - val expectedTrustAnchor = TrustAnchor(converter.getCertificate(trustedRoot), null) + override fun registerAnonymousIdentity(anonymousParty: AnonymousParty, fullParty: PartyAndCertificate, path: CertPath) { require(path.certificates.isNotEmpty()) { "Certificate path must contain at least one certificate" } - val target = path.certificates.last() as X509Certificate - require(target.publicKey == anonymousParty.owningKey) { "Certificate path must end with anonymous party's public key" } + // Validate the chain first, before we do anything clever with it val validator = CertPathValidator.getInstance("PKIX") - val validatorParameters = PKIXParameters(setOf(expectedTrustAnchor)).apply { - isRevocationEnabled = false + val validatorParameters = if (trustAnchor != null) { + PKIXParameters(setOf(trustAnchor)) + } else { + // TODO: We should always require a full chain back to a trust anchor, but until we have a network + // trust anchor everywhere, this will have to do. + val converter = JcaX509CertificateConverter() + PKIXParameters(setOf(TrustAnchor(converter.getCertificate(fullParty.certificate), null))) } + validatorParameters.isRevocationEnabled = false val result = validator.validate(path, validatorParameters) as PKIXCertPathValidatorResult - require(result.trustAnchor == expectedTrustAnchor) - require(result.publicKey == anonymousParty.owningKey) + val subjectCertificate = path.certificates.first() + require(trustAnchor == null || result.trustAnchor == trustAnchor) + require(result.publicKey == anonymousParty.owningKey) { "Certificate path validation must end at transaction key ${anonymousParty.owningKey.toStringShort()}, found ${result.publicKey.toStringShort()}" } + require(subjectCertificate is X509Certificate && subjectCertificate.subject == fullParty.name) { "Subject of the transaction certificate must match the well known identity" } + + log.trace { "Registering identity $fullParty" } partyToPath[anonymousParty] = path + keyToParties[anonymousParty.owningKey] = fullParty + principalToParties[fullParty.name] = fullParty } } diff --git a/node/src/main/kotlin/net/corda/node/services/keys/E2ETestKeyManagementService.kt b/node/src/main/kotlin/net/corda/node/services/keys/E2ETestKeyManagementService.kt index 85d90980bc..fd7074833f 100644 --- a/node/src/main/kotlin/net/corda/node/services/keys/E2ETestKeyManagementService.kt +++ b/node/src/main/kotlin/net/corda/node/services/keys/E2ETestKeyManagementService.kt @@ -6,6 +6,7 @@ import net.corda.core.crypto.generateKeyPair import net.corda.core.crypto.keys import net.corda.core.crypto.sign import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.services.IdentityService import net.corda.core.node.services.KeyManagementService import net.corda.core.serialization.SingletonSerializeAsToken @@ -57,7 +58,11 @@ class E2ETestKeyManagementService(val identityService: IdentityService, return keyPair.public } - override fun freshKeyAndCert(identity: Party, revocationEnabled: Boolean): Pair = freshKeyAndCert(this, identityService, identity, revocationEnabled) + override fun freshKeyAndCert(identity: PartyAndCertificate, revocationEnabled: Boolean): Pair { + return freshCertificate(identityService, freshKey(), identity, getSigner(identity.owningKey), revocationEnabled) + } + + private fun getSigner(publicKey: PublicKey): ContentSigner = getSigner(getSigningKeyPair(publicKey)) private fun getSigningKeyPair(publicKey: PublicKey): KeyPair { return mutex.locked { diff --git a/node/src/main/kotlin/net/corda/node/services/keys/KMSUtils.kt b/node/src/main/kotlin/net/corda/node/services/keys/KMSUtils.kt index 03f1dae235..2da401e08d 100644 --- a/node/src/main/kotlin/net/corda/node/services/keys/KMSUtils.kt +++ b/node/src/main/kotlin/net/corda/node/services/keys/KMSUtils.kt @@ -5,38 +5,49 @@ import net.corda.core.crypto.ContentSignerBuilder import net.corda.core.crypto.Crypto import net.corda.core.crypto.X509Utilities import net.corda.core.identity.AnonymousParty -import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.services.IdentityService -import net.corda.core.node.services.KeyManagementService import org.bouncycastle.cert.X509CertificateHolder import org.bouncycastle.operator.ContentSigner import java.security.KeyPair +import java.security.PublicKey import java.security.Security import java.security.cert.CertPath import java.security.cert.X509Certificate +import java.time.Duration +import java.util.* /** * Generates a new random [KeyPair], adds it to the internal key storage, then generates a corresponding * [X509Certificate] and adds it to the identity service. * - * @param keyManagementService key service to use when generating the new key. - * @param identityService identity service to use when registering the certificate. - * @param identity identity to generate a key and certificate for. Must be an identity this node has CA privileges for. + * @param subjectPublicKey public key of new identity. + * @param issuerSigner a content signer for the issuer. + * @param identityService issuer service to use when registering the certificate. + * @param issuer issuer to generate a key and certificate for. Must be an identity this node has the private key for. * @param revocationEnabled whether to check revocation status of certificates in the certificate path. * @return X.509 certificate and path to the trust root. */ -fun freshKeyAndCert(keyManagementService: KeyManagementService, - identityService: IdentityService, - identity: Party, - revocationEnabled: Boolean = false): Pair { - val ourPublicKey = keyManagementService.freshKey() - // FIXME: Use the actual certificate for the identity the flow is presenting themselves as - val issuerKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_IDENTITY_SIGNATURE_SCHEME) - val issuerCertificate = X509Utilities.createSelfSignedCACertificate(identity.name, issuerKey) - val ourCertificate = X509Utilities.createCertificate(CertificateType.IDENTITY, issuerCertificate, issuerKey, identity.name, ourPublicKey) +fun freshCertificate(identityService: IdentityService, + subjectPublicKey: PublicKey, + issuer: PartyAndCertificate, + issuerSigner: ContentSigner, + revocationEnabled: Boolean = false): Pair { + val issuerCertificate = issuer.certificate + val window = X509Utilities.getCertificateValidityWindow(Duration.ZERO, Duration.ofDays(10 * 365), issuerCertificate) + val ourCertificate = Crypto.createCertificate(CertificateType.IDENTITY, issuerCertificate.subject, issuerSigner, issuer.name, subjectPublicKey, window) + val actualPublicKey = Crypto.toSupportedPublicKey(ourCertificate.subjectPublicKeyInfo) + require(subjectPublicKey == actualPublicKey) val ourCertPath = X509Utilities.createCertificatePath(issuerCertificate, ourCertificate, revocationEnabled = revocationEnabled) - identityService.registerPath(issuerCertificate, - AnonymousParty(ourPublicKey), + require(Arrays.equals(ourCertificate.subjectPublicKeyInfo.encoded, subjectPublicKey.encoded)) + identityService.registerAnonymousIdentity(AnonymousParty(subjectPublicKey), + issuer, ourCertPath) return Pair(issuerCertificate, ourCertPath) +} + +fun getSigner(issuerKeyPair: KeyPair): ContentSigner { + val signatureScheme = Crypto.findSignatureScheme(issuerKeyPair.private) + val provider = Security.getProvider(signatureScheme.providerName) + return ContentSignerBuilder.build(signatureScheme, issuerKeyPair.private, provider) } \ No newline at end of file diff --git a/node/src/main/kotlin/net/corda/node/services/keys/PersistentKeyManagementService.kt b/node/src/main/kotlin/net/corda/node/services/keys/PersistentKeyManagementService.kt index 53233a6002..c1f2c692a5 100644 --- a/node/src/main/kotlin/net/corda/node/services/keys/PersistentKeyManagementService.kt +++ b/node/src/main/kotlin/net/corda/node/services/keys/PersistentKeyManagementService.kt @@ -5,7 +5,7 @@ import net.corda.core.crypto.DigitalSignature import net.corda.core.crypto.generateKeyPair import net.corda.core.crypto.keys import net.corda.core.crypto.sign -import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.services.IdentityService import net.corda.core.node.services.KeyManagementService import net.corda.core.serialization.SingletonSerializeAsToken @@ -67,7 +67,12 @@ class PersistentKeyManagementService(val identityService: IdentityService, } return keyPair.public } - override fun freshKeyAndCert(identity: Party, revocationEnabled: Boolean): Pair = freshKeyAndCert(this, identityService, identity, revocationEnabled) + + override fun freshKeyAndCert(identity: PartyAndCertificate, revocationEnabled: Boolean): Pair { + return freshCertificate(identityService, freshKey(), identity, getSigner(identity.owningKey), revocationEnabled) + } + + private fun getSigner(publicKey: PublicKey): ContentSigner = getSigner(getSigningKeyPair(publicKey)) private fun getSigningKeyPair(publicKey: PublicKey): KeyPair { return mutex.locked { diff --git a/node/src/main/kotlin/net/corda/node/services/network/NetworkMapService.kt b/node/src/main/kotlin/net/corda/node/services/network/NetworkMapService.kt index 7c65f3d02c..6de2164a04 100644 --- a/node/src/main/kotlin/net/corda/node/services/network/NetworkMapService.kt +++ b/node/src/main/kotlin/net/corda/node/services/network/NetworkMapService.kt @@ -6,6 +6,7 @@ import net.corda.core.crypto.DigitalSignature import net.corda.core.crypto.SignedData import net.corda.core.crypto.isFulfilledBy import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.messaging.MessageRecipients import net.corda.core.messaging.SingleMessageRecipient import net.corda.core.node.NodeInfo @@ -116,7 +117,7 @@ interface NetworkMapService { class InMemoryNetworkMapService(services: ServiceHubInternal, minimumPlatformVersion: Int) : AbstractNetworkMapService(services, minimumPlatformVersion) { - override val nodeRegistrations: MutableMap = ConcurrentHashMap() + override val nodeRegistrations: MutableMap = ConcurrentHashMap() override val subscribers = ThreadBox(mutableMapOf()) init { @@ -142,7 +143,7 @@ abstract class AbstractNetworkMapService(services: ServiceHubInternal, private val logger = loggerFor() } - protected abstract val nodeRegistrations: MutableMap + protected abstract val nodeRegistrations: MutableMap // Map from subscriber address, to most recently acknowledged update map version. protected abstract val subscribers: ThreadBox> diff --git a/node/src/main/kotlin/net/corda/node/services/network/PersistentNetworkMapService.kt b/node/src/main/kotlin/net/corda/node/services/network/PersistentNetworkMapService.kt index 83a2dd12a1..2220d94a19 100644 --- a/node/src/main/kotlin/net/corda/node/services/network/PersistentNetworkMapService.kt +++ b/node/src/main/kotlin/net/corda/node/services/network/PersistentNetworkMapService.kt @@ -1,7 +1,7 @@ package net.corda.node.services.network import net.corda.core.ThreadBox -import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.messaging.SingleMessageRecipient import net.corda.node.services.api.ServiceHubInternal import net.corda.node.utilities.* @@ -22,22 +22,25 @@ class PersistentNetworkMapService(services: ServiceHubInternal, minimumPlatformV : AbstractNetworkMapService(services, minimumPlatformVersion) { private object Table : JDBCHashedTable("${NODE_DATABASE_PREFIX}network_map_nodes") { - val nodeParty = party("node_party_name", "node_party_key") + val nodeParty = partyAndCertificate("node_party_name", "node_party_key", "node_party_certificate", "node_party_path") val registrationInfo = blob("node_registration_info") } - override val nodeRegistrations: MutableMap = synchronizedMap(object : AbstractJDBCHashMap(Table, loadOnInit = true) { + override val nodeRegistrations: MutableMap = synchronizedMap(object : AbstractJDBCHashMap(Table, loadOnInit = true) { // TODO: We should understand an X500Name database field type, rather than manually doing the conversion ourselves - override fun keyFromRow(row: ResultRow): Party = Party(X500Name(row[table.nodeParty.name]), row[table.nodeParty.owningKey]) + override fun keyFromRow(row: ResultRow): PartyAndCertificate = PartyAndCertificate(X500Name(row[table.nodeParty.name]), row[table.nodeParty.owningKey], + row[table.nodeParty.certificate], row[table.nodeParty.certPath]) override fun valueFromRow(row: ResultRow): NodeRegistrationInfo = deserializeFromBlob(row[table.registrationInfo]) - override fun addKeyToInsert(insert: InsertStatement, entry: Map.Entry, finalizables: MutableList<() -> Unit>) { + override fun addKeyToInsert(insert: InsertStatement, entry: Map.Entry, finalizables: MutableList<() -> Unit>) { insert[table.nodeParty.name] = entry.key.name.toString() insert[table.nodeParty.owningKey] = entry.key.owningKey + insert[table.nodeParty.certPath] = entry.key.certPath + insert[table.nodeParty.certificate] = entry.key.certificate } - override fun addValueToInsert(insert: InsertStatement, entry: Map.Entry, finalizables: MutableList<() -> Unit>) { + override fun addValueToInsert(insert: InsertStatement, entry: Map.Entry, finalizables: MutableList<() -> Unit>) { insert[table.registrationInfo] = serializeToBlob(entry.value, finalizables) } }) diff --git a/node/src/main/kotlin/net/corda/node/services/statemachine/StateMachineManager.kt b/node/src/main/kotlin/net/corda/node/services/statemachine/StateMachineManager.kt index db7d34b490..159e833e8b 100644 --- a/node/src/main/kotlin/net/corda/node/services/statemachine/StateMachineManager.kt +++ b/node/src/main/kotlin/net/corda/node/services/statemachine/StateMachineManager.kt @@ -18,6 +18,7 @@ import net.corda.core.* import net.corda.core.crypto.SecureHash import net.corda.core.flows.* import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.serialization.* import net.corda.core.utilities.debug import net.corda.core.utilities.loggerFor @@ -339,7 +340,7 @@ class StateMachineManager(val serviceHub: ServiceHubInternal, waitingForResponse is WaitForLedgerCommit && message is ErrorSessionEnd } - private fun onSessionInit(sessionInit: SessionInit, receivedMessage: ReceivedMessage, sender: Party) { + private fun onSessionInit(sessionInit: SessionInit, receivedMessage: ReceivedMessage, sender: PartyAndCertificate) { logger.trace { "Received $sessionInit from $sender" } val otherPartySessionId = sessionInit.initiatorSessionId diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/BFTNonValidatingNotaryService.kt b/node/src/main/kotlin/net/corda/node/services/transactions/BFTNonValidatingNotaryService.kt index c039689d50..f02fd34fcc 100644 --- a/node/src/main/kotlin/net/corda/node/services/transactions/BFTNonValidatingNotaryService.kt +++ b/node/src/main/kotlin/net/corda/node/services/transactions/BFTNonValidatingNotaryService.kt @@ -3,7 +3,7 @@ package net.corda.node.services.transactions import co.paralleluniverse.fibers.Suspendable import net.corda.core.crypto.DigitalSignature import net.corda.core.flows.FlowLogic -import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.services.TimeWindowChecker import net.corda.core.serialization.deserialize import net.corda.core.serialization.serialize @@ -42,11 +42,11 @@ class BFTNonValidatingNotaryService(config: BFTSMaRtConfig, private val log = loggerFor() } - override val serviceFlowFactory: (Party, Int) -> FlowLogic = { otherParty, _ -> + override val serviceFlowFactory: (PartyAndCertificate, Int) -> FlowLogic = { otherParty, _ -> ServiceFlow(otherParty, client) } - private class ServiceFlow(val otherSide: Party, val client: BFTSMaRt.Client) : FlowLogic() { + private class ServiceFlow(val otherSide: PartyAndCertificate, val client: BFTSMaRt.Client) : FlowLogic() { @Suspendable override fun call(): Void? { val stx = receive(otherSide).unwrap { it } @@ -81,7 +81,7 @@ class BFTNonValidatingNotaryService(config: BFTSMaRtConfig, return response.serialize().bytes } - fun verifyAndCommitTx(ftx: FilteredTransaction, callerIdentity: Party): BFTSMaRt.ReplicaResponse { + fun verifyAndCommitTx(ftx: FilteredTransaction, callerIdentity: PartyAndCertificate): BFTSMaRt.ReplicaResponse { return try { val id = ftx.rootHash val inputs = ftx.filteredLeaves.inputs diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/BFTSMaRt.kt b/node/src/main/kotlin/net/corda/node/services/transactions/BFTSMaRt.kt index 795a129665..5596f61d6f 100644 --- a/node/src/main/kotlin/net/corda/node/services/transactions/BFTSMaRt.kt +++ b/node/src/main/kotlin/net/corda/node/services/transactions/BFTSMaRt.kt @@ -13,7 +13,7 @@ import net.corda.core.crypto.DigitalSignature import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SignedData import net.corda.core.crypto.sign -import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.services.TimeWindowChecker import net.corda.core.node.services.UniquenessProvider import net.corda.core.serialization.CordaSerializable @@ -51,7 +51,7 @@ import java.util.* object BFTSMaRt { /** Sent from [Client] to [Server]. */ @CordaSerializable - data class CommitRequest(val tx: Any, val callerIdentity: Party) + data class CommitRequest(val tx: Any, val callerIdentity: PartyAndCertificate) /** Sent from [Server] to [Client]. */ @CordaSerializable @@ -83,7 +83,7 @@ object BFTSMaRt { * Sends a transaction commit request to the BFT cluster. The [proxy] will deliver the request to every * replica, and block until a sufficient number of replies are received. */ - fun commitTransaction(transaction: Any, otherSide: Party): ClusterResponse { + fun commitTransaction(transaction: Any, otherSide: PartyAndCertificate): ClusterResponse { require(transaction is FilteredTransaction || transaction is SignedTransaction) { "Unsupported transaction type: ${transaction.javaClass.name}" } val request = CommitRequest(transaction, otherSide) val responseBytes = proxy.invokeOrdered(request.serialize().bytes) @@ -178,7 +178,7 @@ object BFTSMaRt { */ abstract fun executeCommand(command: ByteArray): ByteArray? - protected fun commitInputStates(states: List, txId: SecureHash, callerIdentity: Party) { + protected fun commitInputStates(states: List, txId: SecureHash, callerIdentity: PartyAndCertificate) { log.debug { "Attempting to commit inputs for transaction: $txId" } val conflicts = mutableMapOf() db.transaction { diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/NonValidatingNotaryFlow.kt b/node/src/main/kotlin/net/corda/node/services/transactions/NonValidatingNotaryFlow.kt index c6a01cec51..942db3008f 100644 --- a/node/src/main/kotlin/net/corda/node/services/transactions/NonValidatingNotaryFlow.kt +++ b/node/src/main/kotlin/net/corda/node/services/transactions/NonValidatingNotaryFlow.kt @@ -1,7 +1,7 @@ package net.corda.node.services.transactions import co.paralleluniverse.fibers.Suspendable -import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.services.TimeWindowChecker import net.corda.core.node.services.UniquenessProvider import net.corda.core.transactions.FilteredTransaction @@ -9,7 +9,7 @@ import net.corda.core.utilities.unwrap import net.corda.flows.NotaryFlow import net.corda.flows.TransactionParts -class NonValidatingNotaryFlow(otherSide: Party, +class NonValidatingNotaryFlow(otherSide: PartyAndCertificate, timeWindowChecker: TimeWindowChecker, uniquenessProvider: UniquenessProvider) : NotaryFlow.Service(otherSide, timeWindowChecker, uniquenessProvider) { /** diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/NotaryService.kt b/node/src/main/kotlin/net/corda/node/services/transactions/NotaryService.kt index 9d6b13f7db..888026bf1a 100644 --- a/node/src/main/kotlin/net/corda/node/services/transactions/NotaryService.kt +++ b/node/src/main/kotlin/net/corda/node/services/transactions/NotaryService.kt @@ -2,13 +2,15 @@ package net.corda.node.services.transactions import net.corda.core.flows.FlowLogic import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate interface NotaryService { /** * Factory for producing notary service flows which have the corresponding sends and receives as NotaryFlow.Client. - * The first parameter is the client [Party] making the request and the second is the platform version of the client's - * node. Use this version parameter to provide backwards compatibility if the notary flow protocol changes. + * The first parameter is the client [PartyAndCertificate] making the request and the second is the platform version + * of the client's node. Use this version parameter to provide backwards compatibility if the notary flow protocol + * changes. */ - val serviceFlowFactory: (Party, Int) -> FlowLogic + val serviceFlowFactory: (PartyAndCertificate, Int) -> FlowLogic } diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/RaftNonValidatingNotaryService.kt b/node/src/main/kotlin/net/corda/node/services/transactions/RaftNonValidatingNotaryService.kt index 614dfdeb36..e584dd9edb 100644 --- a/node/src/main/kotlin/net/corda/node/services/transactions/RaftNonValidatingNotaryService.kt +++ b/node/src/main/kotlin/net/corda/node/services/transactions/RaftNonValidatingNotaryService.kt @@ -1,7 +1,7 @@ package net.corda.node.services.transactions import net.corda.core.flows.FlowLogic -import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.services.TimeWindowChecker /** A non-validating notary service operated by a group of mutually trusting parties, uses the Raft algorithm to achieve consensus. */ @@ -11,7 +11,7 @@ class RaftNonValidatingNotaryService(val timeWindowChecker: TimeWindowChecker, val type = SimpleNotaryService.type.getSubType("raft") } - override val serviceFlowFactory: (Party, Int) -> FlowLogic = { otherParty, _ -> + override val serviceFlowFactory: (PartyAndCertificate, Int) -> FlowLogic = { otherParty, _ -> NonValidatingNotaryFlow(otherParty, timeWindowChecker, uniquenessProvider) } } diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/RaftValidatingNotaryService.kt b/node/src/main/kotlin/net/corda/node/services/transactions/RaftValidatingNotaryService.kt index ff0217d12d..d78899231c 100644 --- a/node/src/main/kotlin/net/corda/node/services/transactions/RaftValidatingNotaryService.kt +++ b/node/src/main/kotlin/net/corda/node/services/transactions/RaftValidatingNotaryService.kt @@ -1,7 +1,7 @@ package net.corda.node.services.transactions import net.corda.core.flows.FlowLogic -import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.services.TimeWindowChecker /** A validating notary service operated by a group of mutually trusting parties, uses the Raft algorithm to achieve consensus. */ @@ -11,7 +11,7 @@ class RaftValidatingNotaryService(val timeWindowChecker: TimeWindowChecker, val type = ValidatingNotaryService.type.getSubType("raft") } - override val serviceFlowFactory: (Party, Int) -> FlowLogic = { otherParty, _ -> + override val serviceFlowFactory: (PartyAndCertificate, Int) -> FlowLogic = { otherParty, _ -> ValidatingNotaryFlow(otherParty, timeWindowChecker, uniquenessProvider) } } diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/SimpleNotaryService.kt b/node/src/main/kotlin/net/corda/node/services/transactions/SimpleNotaryService.kt index 5ac707bc9e..924f5f2190 100644 --- a/node/src/main/kotlin/net/corda/node/services/transactions/SimpleNotaryService.kt +++ b/node/src/main/kotlin/net/corda/node/services/transactions/SimpleNotaryService.kt @@ -1,7 +1,7 @@ package net.corda.node.services.transactions import net.corda.core.flows.FlowLogic -import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.services.ServiceType import net.corda.core.node.services.TimeWindowChecker import net.corda.core.node.services.UniquenessProvider @@ -13,7 +13,7 @@ class SimpleNotaryService(val timeWindowChecker: TimeWindowChecker, val type = ServiceType.notary.getSubType("simple") } - override val serviceFlowFactory: (Party, Int) -> FlowLogic = { otherParty, _ -> + override val serviceFlowFactory: (PartyAndCertificate, Int) -> FlowLogic = { otherParty, _ -> NonValidatingNotaryFlow(otherParty, timeWindowChecker, uniquenessProvider) } } diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/ValidatingNotaryFlow.kt b/node/src/main/kotlin/net/corda/node/services/transactions/ValidatingNotaryFlow.kt index d30180db05..915412e2a9 100644 --- a/node/src/main/kotlin/net/corda/node/services/transactions/ValidatingNotaryFlow.kt +++ b/node/src/main/kotlin/net/corda/node/services/transactions/ValidatingNotaryFlow.kt @@ -2,7 +2,7 @@ package net.corda.node.services.transactions import co.paralleluniverse.fibers.Suspendable import net.corda.core.contracts.TransactionVerificationException -import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.services.TimeWindowChecker import net.corda.core.node.services.UniquenessProvider import net.corda.core.transactions.SignedTransaction @@ -17,7 +17,7 @@ import java.security.SignatureException * has its input states "blocked" by a transaction from another party, and needs to establish whether that transaction was * indeed valid. */ -class ValidatingNotaryFlow(otherSide: Party, +class ValidatingNotaryFlow(otherSide: PartyAndCertificate, timeWindowChecker: TimeWindowChecker, uniquenessProvider: UniquenessProvider) : NotaryFlow.Service(otherSide, timeWindowChecker, uniquenessProvider) { diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/ValidatingNotaryService.kt b/node/src/main/kotlin/net/corda/node/services/transactions/ValidatingNotaryService.kt index 72b819e90a..c18b8792ff 100644 --- a/node/src/main/kotlin/net/corda/node/services/transactions/ValidatingNotaryService.kt +++ b/node/src/main/kotlin/net/corda/node/services/transactions/ValidatingNotaryService.kt @@ -1,7 +1,7 @@ package net.corda.node.services.transactions import net.corda.core.flows.FlowLogic -import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.services.ServiceType import net.corda.core.node.services.TimeWindowChecker import net.corda.core.node.services.UniquenessProvider @@ -13,7 +13,7 @@ class ValidatingNotaryService(val timeWindowChecker: TimeWindowChecker, val type = ServiceType.notary.getSubType("validating") } - override val serviceFlowFactory: (Party, Int) -> FlowLogic = { otherParty, _ -> + override val serviceFlowFactory: (PartyAndCertificate, Int) -> FlowLogic = { otherParty, _ -> ValidatingNotaryFlow(otherParty, timeWindowChecker, uniquenessProvider) } } diff --git a/node/src/test/kotlin/net/corda/node/InteractiveShellTest.kt b/node/src/test/kotlin/net/corda/node/InteractiveShellTest.kt index ea16f4dcf5..44343cb469 100644 --- a/node/src/test/kotlin/net/corda/node/InteractiveShellTest.kt +++ b/node/src/test/kotlin/net/corda/node/InteractiveShellTest.kt @@ -11,7 +11,7 @@ import net.corda.core.flows.StateMachineRunId import net.corda.core.identity.Party import net.corda.core.node.ServiceHub import net.corda.core.transactions.SignedTransaction -import net.corda.core.utilities.DUMMY_PUBKEY_1 +import net.corda.core.utilities.DUMMY_CA import net.corda.core.utilities.UntrustworthyData import net.corda.jackson.JacksonSupport import net.corda.node.services.identity.InMemoryIdentityService @@ -33,8 +33,7 @@ class InteractiveShellTest { override fun call() = a } - private val someCorpLegalName = MEGA_CORP.name - private val ids = InMemoryIdentityService().apply { registerIdentity(Party(someCorpLegalName, DUMMY_PUBKEY_1)) } + private val ids = InMemoryIdentityService(listOf(MEGA_CORP), trustRoot = DUMMY_CA.certificate) private val om = JacksonSupport.createInMemoryMapper(ids, YAMLFactory()) private fun check(input: String, expected: String) { @@ -67,7 +66,7 @@ class InteractiveShellTest { fun flowTooManyParams() = check("b: 12, c: Yo, d: Bar", "") @Test - fun party() = check("party: \"$someCorpLegalName\"", someCorpLegalName.toString()) + fun party() = check("party: \"${MEGA_CORP.name}\"", MEGA_CORP.name.toString()) class DummyFSM(val logic: FlowA) : FlowStateMachine { override fun sendAndReceive(receiveType: Class, otherParty: Party, payload: Any, sessionFlow: FlowLogic<*>, retrySend: Boolean): UntrustworthyData { diff --git a/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt b/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt index ed89f2e424..d1e235ca06 100644 --- a/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt +++ b/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt @@ -13,6 +13,8 @@ import net.corda.core.flows.* import net.corda.core.identity.AbstractParty import net.corda.core.identity.AnonymousParty import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate +import net.corda.core.map import net.corda.core.messaging.SingleMessageRecipient import net.corda.core.node.NodeInfo import net.corda.core.node.services.* @@ -493,7 +495,7 @@ class TwoPartyTradeFlowTests { } @InitiatingFlow - class SellerInitiator(val buyer: Party, + class SellerInitiator(val buyer: PartyAndCertificate, val notary: NodeInfo, val assetToSell: StateAndRef, val price: Amount) : FlowLogic() { @@ -510,10 +512,10 @@ class TwoPartyTradeFlowTests { } @InitiatedBy(SellerInitiator::class) - class BuyerAcceptor(val seller: Party) : FlowLogic() { + class BuyerAcceptor(val seller: PartyAndCertificate) : FlowLogic() { @Suspendable override fun call(): SignedTransaction { - val (notary, price) = receive>>(seller).unwrap { + val (notary, price) = receive>>(seller).unwrap { require(serviceHub.networkMapCache.isNotary(it.first)) { "${it.first} is not a notary" } it } diff --git a/node/src/test/kotlin/net/corda/node/services/MockServiceHubInternal.kt b/node/src/test/kotlin/net/corda/node/services/MockServiceHubInternal.kt index 4b21b7fbd9..1fb1fb80d4 100644 --- a/node/src/test/kotlin/net/corda/node/services/MockServiceHubInternal.kt +++ b/node/src/test/kotlin/net/corda/node/services/MockServiceHubInternal.kt @@ -3,6 +3,7 @@ package net.corda.node.services import com.codahale.metrics.MetricRegistry import net.corda.core.flows.FlowInitiator import net.corda.core.flows.FlowLogic +import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.NodeInfo import net.corda.core.node.services.* import net.corda.core.serialization.SerializeAsToken diff --git a/node/src/test/kotlin/net/corda/node/services/NotaryChangeTests.kt b/node/src/test/kotlin/net/corda/node/services/NotaryChangeTests.kt index 3216dfe83b..b6cd68488e 100644 --- a/node/src/test/kotlin/net/corda/node/services/NotaryChangeTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/NotaryChangeTests.kt @@ -8,6 +8,7 @@ import net.corda.core.node.services.ServiceInfo import net.corda.core.seconds import net.corda.core.transactions.WireTransaction import net.corda.core.utilities.DUMMY_NOTARY +import net.corda.core.utilities.getTestPartyAndCertificate import net.corda.flows.NotaryChangeFlow import net.corda.flows.StateReplacementException import net.corda.node.internal.AbstractNode @@ -75,7 +76,7 @@ class NotaryChangeTests { @Test fun `should throw when a participant refuses to change Notary`() { val state = issueMultiPartyState(clientNodeA, clientNodeB, oldNotaryNode) - val newEvilNotary = Party(X500Name("CN=Evil Notary,O=Evil R3,OU=corda,L=London,C=UK"), generateKeyPair().public) + val newEvilNotary = getTestPartyAndCertificate(X500Name("CN=Evil Notary,O=Evil R3,OU=corda,L=London,C=UK"), generateKeyPair().public) val flow = NotaryChangeFlow(state, newEvilNotary) val future = clientNodeA.services.startFlow(flow) diff --git a/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt b/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt index caafeeda0c..9c8704e951 100644 --- a/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt @@ -10,6 +10,7 @@ import net.corda.core.node.ServiceHub import net.corda.core.node.services.VaultService import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.core.utilities.ALICE_KEY +import net.corda.core.utilities.DUMMY_CA import net.corda.core.utilities.DUMMY_NOTARY import net.corda.node.services.MockServiceHubInternal import net.corda.node.services.identity.InMemoryIdentityService @@ -76,7 +77,7 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() { val dataSourceAndDatabase = configureDatabase(dataSourceProps) dataSource = dataSourceAndDatabase.first database = dataSourceAndDatabase.second - val identityService = InMemoryIdentityService() + val identityService = InMemoryIdentityService(trustRoot = DUMMY_CA.certificate) val kms = MockKeyManagementService(identityService, ALICE_KEY) database.transaction { diff --git a/node/src/test/kotlin/net/corda/node/services/network/InMemoryIdentityServiceTests.kt b/node/src/test/kotlin/net/corda/node/services/network/InMemoryIdentityServiceTests.kt index 0bd8c3cd56..648f025869 100644 --- a/node/src/test/kotlin/net/corda/node/services/network/InMemoryIdentityServiceTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/network/InMemoryIdentityServiceTests.kt @@ -3,14 +3,15 @@ package net.corda.node.services.network import net.corda.core.crypto.* import net.corda.core.identity.AnonymousParty import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.services.IdentityService -import net.corda.core.utilities.ALICE -import net.corda.core.utilities.BOB +import net.corda.core.utilities.* import net.corda.node.services.identity.InMemoryIdentityService import net.corda.testing.ALICE_PUBKEY import net.corda.testing.BOB_PUBKEY import org.bouncycastle.asn1.x500.X500Name import org.junit.Test +import java.security.cert.X509Certificate import kotlin.test.assertEquals import kotlin.test.assertFailsWith import kotlin.test.assertNull @@ -21,7 +22,7 @@ import kotlin.test.assertNull class InMemoryIdentityServiceTests { @Test fun `get all identities`() { - val service = InMemoryIdentityService() + val service = InMemoryIdentityService(trustRoot = DUMMY_CA.certificate) assertNull(service.getAllIdentities().firstOrNull()) service.registerIdentity(ALICE) var expected = setOf(ALICE) @@ -37,7 +38,7 @@ class InMemoryIdentityServiceTests { @Test fun `get identity by key`() { - val service = InMemoryIdentityService() + val service = InMemoryIdentityService(trustRoot = DUMMY_CA.certificate) assertNull(service.partyFromKey(ALICE_PUBKEY)) service.registerIdentity(ALICE) assertEquals(ALICE, service.partyFromKey(ALICE_PUBKEY)) @@ -46,15 +47,15 @@ class InMemoryIdentityServiceTests { @Test fun `get identity by name with no registered identities`() { - val service = InMemoryIdentityService() + val service = InMemoryIdentityService(trustRoot = DUMMY_CA.certificate) assertNull(service.partyFromX500Name(ALICE.name)) } @Test fun `get identity by name`() { - val service = InMemoryIdentityService() + val service = InMemoryIdentityService(trustRoot = DUMMY_CA.certificate) val identities = listOf("Node A", "Node B", "Node C") - .map { Party(X500Name("CN=$it,O=R3,OU=corda,L=London,C=UK"), generateKeyPair().public) } + .map { getTestPartyAndCertificate(X500Name("CN=$it,O=R3,OU=corda,L=London,C=UK"), generateKeyPair().public) } assertNull(service.partyFromX500Name(identities.first().name)) identities.forEach { service.registerIdentity(it) } identities.forEach { assertEquals(it, service.partyFromX500Name(it.name)) } @@ -68,7 +69,7 @@ class InMemoryIdentityServiceTests { val rootKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) val rootCert = X509Utilities.createSelfSignedCACertificate(ALICE.name, rootKey) val txKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) - val service = InMemoryIdentityService() + val service = InMemoryIdentityService(trustRoot = DUMMY_CA.certificate) // TODO: Generate certificate with an EdDSA key rather than ECDSA val identity = Party(CertificateAndKeyPair(rootCert, rootKey)) val txIdentity = AnonymousParty(txKey.public) @@ -84,26 +85,26 @@ class InMemoryIdentityServiceTests { */ @Test fun `assert ownership`() { + val service = InMemoryIdentityService(trustRoot = null as X509Certificate?) val aliceRootKey = Crypto.generateKeyPair() val aliceRootCert = X509Utilities.createSelfSignedCACertificate(ALICE.name, aliceRootKey) val aliceTxKey = Crypto.generateKeyPair() - val aliceTxCert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, aliceRootCert, aliceRootKey, ALICE.name, aliceTxKey.public) + val aliceTxCert = X509Utilities.createCertificate(CertificateType.IDENTITY, aliceRootCert, aliceRootKey, ALICE.name, aliceTxKey.public) val aliceCertPath = X509Utilities.createCertificatePath(aliceRootCert, aliceTxCert, revocationEnabled = false) + val alice = PartyAndCertificate(ALICE.name, aliceRootKey.public, aliceRootCert, aliceCertPath) + + val anonymousAlice = AnonymousParty(aliceTxKey.public) + service.registerAnonymousIdentity(anonymousAlice, alice, aliceCertPath) val bobRootKey = Crypto.generateKeyPair() val bobRootCert = X509Utilities.createSelfSignedCACertificate(BOB.name, bobRootKey) val bobTxKey = Crypto.generateKeyPair() - val bobTxCert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, bobRootCert, bobRootKey, BOB.name, bobTxKey.public) + val bobTxCert = X509Utilities.createCertificate(CertificateType.IDENTITY, bobRootCert, bobRootKey, BOB.name, bobTxKey.public) val bobCertPath = X509Utilities.createCertificatePath(bobRootCert, bobTxCert, revocationEnabled = false) + val bob = PartyAndCertificate(BOB.name, bobRootKey.public, bobRootCert, bobCertPath) - val service = InMemoryIdentityService() - val alice = Party(CertificateAndKeyPair(aliceRootCert, aliceRootKey)) - val anonymousAlice = AnonymousParty(aliceTxKey.public) - val bob = Party(CertificateAndKeyPair(bobRootCert, bobRootKey)) val anonymousBob = AnonymousParty(bobTxKey.public) - - service.registerPath(aliceRootCert, anonymousAlice, aliceCertPath) - service.registerPath(bobRootCert, anonymousBob, bobCertPath) + service.registerAnonymousIdentity(anonymousBob, bob, bobCertPath) // Verify that paths are verified service.assertOwnership(alice, anonymousAlice) @@ -122,7 +123,7 @@ class InMemoryIdentityServiceTests { @Test fun `deanonymising a well known identity`() { val expected = ALICE - val actual = InMemoryIdentityService().partyFromAnonymous(expected) + val actual = InMemoryIdentityService(trustRoot = null as X509Certificate?).partyFromAnonymous(expected) assertEquals(expected, actual) } } diff --git a/node/src/test/kotlin/net/corda/node/services/persistence/DataVendingServiceTests.kt b/node/src/test/kotlin/net/corda/node/services/persistence/DataVendingServiceTests.kt index 95072b0a7f..68cba37758 100644 --- a/node/src/test/kotlin/net/corda/node/services/persistence/DataVendingServiceTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/persistence/DataVendingServiceTests.kt @@ -9,7 +9,7 @@ import net.corda.core.contracts.USD import net.corda.core.flows.FlowLogic import net.corda.core.flows.InitiatedBy import net.corda.core.flows.InitiatingFlow -import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.services.unconsumedStates import net.corda.core.transactions.SignedTransaction import net.corda.core.utilities.DUMMY_NOTARY @@ -93,13 +93,13 @@ class DataVendingServiceTests { } @InitiatingFlow - private class NotifyTxFlow(val otherParty: Party, val stx: SignedTransaction) : FlowLogic() { + private class NotifyTxFlow(val otherParty: PartyAndCertificate, val stx: SignedTransaction) : FlowLogic() { @Suspendable override fun call() = send(otherParty, NotifyTxRequest(stx)) } @InitiatedBy(NotifyTxFlow::class) - private class InitiateNotifyTxFlow(val otherParty: Party) : FlowLogic() { + private class InitiateNotifyTxFlow(val otherParty: PartyAndCertificate) : FlowLogic() { @Suspendable override fun call() = subFlow(NotifyTransactionHandler(otherParty)) } diff --git a/node/src/test/kotlin/net/corda/node/services/statemachine/FlowFrameworkTests.kt b/node/src/test/kotlin/net/corda/node/services/statemachine/FlowFrameworkTests.kt index 3248cb33c5..b2054254fd 100644 --- a/node/src/test/kotlin/net/corda/node/services/statemachine/FlowFrameworkTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/statemachine/FlowFrameworkTests.kt @@ -14,6 +14,7 @@ import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowSessionException import net.corda.core.flows.InitiatingFlow import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.messaging.MessageRecipients import net.corda.core.node.services.PartyInfo import net.corda.core.node.services.ServiceInfo @@ -673,10 +674,10 @@ class FlowFrameworkTests { private inline fun > MockNode.registerFlowFactory( initiatingFlowClass: KClass>, - noinline flowFactory: (Party) -> P): ListenableFuture

+ noinline flowFactory: (PartyAndCertificate) -> P): ListenableFuture

{ val observable = registerFlowFactory(initiatingFlowClass.java, object : InitiatedFlowFactory

{ - override fun createFlow(platformVersion: Int, otherParty: Party, sessionInit: SessionInit): P { + override fun createFlow(platformVersion: Int, otherParty: PartyAndCertificate, sessionInit: SessionInit): P { return flowFactory(otherParty) } }, P::class.java, track = true) diff --git a/node/src/test/kotlin/net/corda/node/utilities/registration/NetworkisRegistrationHelperTest.kt b/node/src/test/kotlin/net/corda/node/utilities/registration/NetworkisRegistrationHelperTest.kt index 0ada571887..c97def38ce 100644 --- a/node/src/test/kotlin/net/corda/node/utilities/registration/NetworkisRegistrationHelperTest.kt +++ b/node/src/test/kotlin/net/corda/node/utilities/registration/NetworkisRegistrationHelperTest.kt @@ -7,6 +7,7 @@ import net.corda.core.crypto.* import net.corda.core.exists import net.corda.core.mapToArray import net.corda.core.utilities.ALICE +import net.corda.core.utilities.getTestPartyAndCertificate import net.corda.testing.TestNodeConfiguration import net.corda.testing.getTestX509Name import org.bouncycastle.cert.X509CertificateHolder @@ -14,6 +15,7 @@ import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder +import java.security.cert.Certificate import kotlin.test.assertEquals import kotlin.test.assertFalse import kotlin.test.assertTrue diff --git a/samples/irs-demo/src/main/kotlin/net/corda/irs/flows/FixingFlow.kt b/samples/irs-demo/src/main/kotlin/net/corda/irs/flows/FixingFlow.kt index 1350c68187..f06129d8ff 100644 --- a/samples/irs-demo/src/main/kotlin/net/corda/irs/flows/FixingFlow.kt +++ b/samples/irs-demo/src/main/kotlin/net/corda/irs/flows/FixingFlow.kt @@ -9,6 +9,7 @@ import net.corda.core.flows.InitiatedBy import net.corda.core.flows.InitiatingFlow import net.corda.core.flows.SchedulableFlow import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.NodeInfo import net.corda.core.node.services.ServiceType import net.corda.core.seconds @@ -30,8 +31,7 @@ object FixingFlow { * who does what in the flow. */ @InitiatedBy(FixingRoleDecider::class) - class Fixer(override val otherParty: Party) : TwoPartyDealFlow.Secondary() { - override val progressTracker: ProgressTracker = TwoPartyDealFlow.Secondary.tracker() + class Fixer(override val otherParty: PartyAndCertificate) : TwoPartyDealFlow.Secondary() { private lateinit var txState: TransactionState<*> private lateinit var deal: FixableDealState @@ -97,7 +97,7 @@ object FixingFlow { * is just the "side" of the flow run by the party with the floating leg as a way of deciding who * does what in the flow. */ - class Floater(override val otherParty: Party, + class Floater(override val otherParty: PartyAndCertificate, override val payload: FixingSession, override val progressTracker: ProgressTracker = TwoPartyDealFlow.Primary.tracker()) : TwoPartyDealFlow.Primary() { diff --git a/samples/irs-demo/src/main/kotlin/net/corda/irs/simulation/IRSSimulation.kt b/samples/irs-demo/src/main/kotlin/net/corda/irs/simulation/IRSSimulation.kt index 369d8537ba..734e33dd51 100644 --- a/samples/irs-demo/src/main/kotlin/net/corda/irs/simulation/IRSSimulation.kt +++ b/samples/irs-demo/src/main/kotlin/net/corda/irs/simulation/IRSSimulation.kt @@ -15,8 +15,10 @@ import net.corda.core.flows.FlowStateMachine import net.corda.core.flows.InitiatedBy import net.corda.core.flows.InitiatingFlow import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.services.linearHeadsOfType import net.corda.core.transactions.SignedTransaction +import net.corda.core.utilities.DUMMY_CA import net.corda.flows.TwoPartyDealFlow.Acceptor import net.corda.flows.TwoPartyDealFlow.AutoOffer import net.corda.flows.TwoPartyDealFlow.Instigator @@ -46,7 +48,7 @@ class IRSSimulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, laten override fun startMainSimulation(): ListenableFuture { val future = SettableFuture.create() - om = JacksonSupport.createInMemoryMapper(InMemoryIdentityService((banks + regulators + networkMap).map { it.info.legalIdentity })) + om = JacksonSupport.createInMemoryMapper(InMemoryIdentityService((banks + regulators + networkMap).map { it.info.legalIdentity }, trustRoot = DUMMY_CA.certificate)) startIRSDealBetween(0, 1).success { // Next iteration is a pause. @@ -129,7 +131,7 @@ class IRSSimulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, laten node2.registerInitiatedFlow(FixingFlow.Fixer::class.java) @InitiatingFlow - class StartDealFlow(val otherParty: Party, + class StartDealFlow(val otherParty: PartyAndCertificate, val payload: AutoOffer, val myKey: PublicKey) : FlowLogic() { @Suspendable diff --git a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/api/PortfolioApi.kt b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/api/PortfolioApi.kt index 58349e9309..97934e830a 100644 --- a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/api/PortfolioApi.kt +++ b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/api/PortfolioApi.kt @@ -9,6 +9,7 @@ import net.corda.core.crypto.* import net.corda.core.getOrThrow import net.corda.core.identity.AbstractParty import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.messaging.CordaRPCOps import net.corda.core.messaging.startFlow import net.corda.core.utilities.DUMMY_MAP @@ -35,7 +36,7 @@ import javax.ws.rs.core.Response @Path("simmvaluationdemo") class PortfolioApi(val rpc: CordaRPCOps) { - private val ownParty: Party get() = rpc.nodeIdentity().legalIdentity + private val ownParty: PartyAndCertificate get() = rpc.nodeIdentity().legalIdentity private val portfolioUtils = PortfolioApiUtils(ownParty) private inline fun dealsWith(party: AbstractParty): List> { @@ -48,7 +49,7 @@ class PortfolioApi(val rpc: CordaRPCOps) { * DSL to get a party and then executing the passed function with the party as a parameter. * Used as such: withParty(name) { doSomethingWith(it) } */ - private fun withParty(partyName: String, func: (Party) -> Response): Response { + private fun withParty(partyName: String, func: (PartyAndCertificate) -> Response): Response { val otherParty = rpc.partyFromKey(parsePublicKeyBase58(partyName)) return if (otherParty != null) { func(otherParty) diff --git a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/IRSTradeFlow.kt b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/IRSTradeFlow.kt index ec39e261a0..3ca522d9f1 100644 --- a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/IRSTradeFlow.kt +++ b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/IRSTradeFlow.kt @@ -6,6 +6,7 @@ import net.corda.core.flows.InitiatedBy import net.corda.core.flows.InitiatingFlow import net.corda.core.flows.StartableByRPC import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.serialization.CordaSerializable import net.corda.core.transactions.SignedTransaction import net.corda.core.utilities.unwrap @@ -20,7 +21,7 @@ object IRSTradeFlow { @InitiatingFlow @StartableByRPC - class Requester(val swap: SwapData, val otherParty: Party) : FlowLogic() { + class Requester(val swap: SwapData, val otherParty: PartyAndCertificate) : FlowLogic() { @Suspendable override fun call(): SignedTransaction { require(serviceHub.networkMapCache.notaryNodes.isNotEmpty()) { "No notary nodes registered" } diff --git a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/SimmFlow.kt b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/SimmFlow.kt index 7a359c0824..ab2588c2a7 100644 --- a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/SimmFlow.kt +++ b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/SimmFlow.kt @@ -15,6 +15,7 @@ import net.corda.core.flows.InitiatedBy import net.corda.core.flows.InitiatingFlow import net.corda.core.flows.StartableByRPC import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.PluginServiceHub import net.corda.core.node.services.dealsWith import net.corda.core.serialization.CordaSerializable @@ -185,7 +186,7 @@ object SimmFlow { * Receives and validates a portfolio and comes to consensus over the portfolio initial margin using SIMM. */ @InitiatedBy(Requester::class) - class Receiver(val replyToParty: Party) : FlowLogic() { + class Receiver(val replyToParty: PartyAndCertificate) : FlowLogic() { lateinit var ownParty: Party lateinit var offer: OfferMessage diff --git a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/StateRevisionFlow.kt b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/StateRevisionFlow.kt index 889a7071b1..1cac27e850 100644 --- a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/StateRevisionFlow.kt +++ b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/StateRevisionFlow.kt @@ -3,6 +3,7 @@ package net.corda.vega.flows import net.corda.core.contracts.StateAndRef import net.corda.core.identity.AbstractParty import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.seconds import net.corda.core.transactions.SignedTransaction import net.corda.flows.AbstractStateReplacementFlow @@ -26,7 +27,7 @@ object StateRevisionFlow { } } - open class Receiver(otherParty: Party) : AbstractStateReplacementFlow.Acceptor(otherParty) { + open class Receiver(otherParty: PartyAndCertificate) : AbstractStateReplacementFlow.Acceptor(otherParty) { override fun verifyProposal(proposal: AbstractStateReplacementFlow.Proposal) { val proposedTx = proposal.stx.tx val state = proposal.stateRef diff --git a/samples/trader-demo/src/main/kotlin/net/corda/traderdemo/flow/BuyerFlow.kt b/samples/trader-demo/src/main/kotlin/net/corda/traderdemo/flow/BuyerFlow.kt index 53024ad9a5..b667b04651 100644 --- a/samples/trader-demo/src/main/kotlin/net/corda/traderdemo/flow/BuyerFlow.kt +++ b/samples/trader-demo/src/main/kotlin/net/corda/traderdemo/flow/BuyerFlow.kt @@ -7,7 +7,7 @@ import net.corda.core.contracts.TransactionGraphSearch import net.corda.core.div import net.corda.core.flows.FlowLogic import net.corda.core.flows.InitiatedBy -import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.NodeInfo import net.corda.core.transactions.SignedTransaction import net.corda.core.utilities.Emoji @@ -17,7 +17,7 @@ import net.corda.flows.TwoPartyTradeFlow import java.util.* @InitiatedBy(SellerFlow::class) -class BuyerFlow(val otherParty: Party) : FlowLogic() { +class BuyerFlow(val otherParty: PartyAndCertificate) : FlowLogic() { object STARTING_BUY : ProgressTracker.Step("Seller connected, purchasing commercial paper asset") diff --git a/samples/trader-demo/src/main/kotlin/net/corda/traderdemo/flow/SellerFlow.kt b/samples/trader-demo/src/main/kotlin/net/corda/traderdemo/flow/SellerFlow.kt index 3a7ecba1d7..d4d24a3872 100644 --- a/samples/trader-demo/src/main/kotlin/net/corda/traderdemo/flow/SellerFlow.kt +++ b/samples/trader-demo/src/main/kotlin/net/corda/traderdemo/flow/SellerFlow.kt @@ -12,6 +12,7 @@ import net.corda.core.flows.InitiatingFlow import net.corda.core.flows.StartableByRPC import net.corda.core.identity.AbstractParty import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.NodeInfo import net.corda.core.seconds import net.corda.core.transactions.SignedTransaction @@ -24,10 +25,10 @@ import java.util.* @InitiatingFlow @StartableByRPC -class SellerFlow(val otherParty: Party, +class SellerFlow(val otherParty: PartyAndCertificate, val amount: Amount, override val progressTracker: ProgressTracker) : FlowLogic() { - constructor(otherParty: Party, amount: Amount) : this(otherParty, amount, tracker()) + constructor(otherParty: PartyAndCertificate, amount: Amount) : this(otherParty, amount, tracker()) companion object { val PROSPECTUS_HASH = SecureHash.parse("decd098666b9657314870e192ced0c3519c2c9d395507a238338f8d003929de9") diff --git a/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt b/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt index 24d0a67eb8..05a4bb8de0 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt +++ b/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt @@ -9,7 +9,7 @@ import net.corda.core.crypto.SecureHash import net.corda.core.crypto.X509Utilities import net.corda.core.crypto.commonName import net.corda.core.crypto.generateKeyPair -import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.ServiceHub import net.corda.core.node.VersionInfo import net.corda.core.node.services.IdentityService @@ -66,22 +66,22 @@ val ALICE_PUBKEY: PublicKey get() = ALICE_KEY.public val BOB_PUBKEY: PublicKey get() = BOB_KEY.public val CHARLIE_PUBKEY: PublicKey get() = CHARLIE_KEY.public -val MEGA_CORP: Party get() = Party(X509Utilities.getDevX509Name("MegaCorp"), MEGA_CORP_PUBKEY) -val MINI_CORP: Party get() = Party(X509Utilities.getDevX509Name("MiniCorp"), MINI_CORP_PUBKEY) +val MEGA_CORP: PartyAndCertificate get() = getTestPartyAndCertificate(X509Utilities.getDevX509Name("MegaCorp"), MEGA_CORP_PUBKEY) +val MINI_CORP: PartyAndCertificate get() = getTestPartyAndCertificate(X509Utilities.getDevX509Name("MiniCorp"), MINI_CORP_PUBKEY) val BOC_KEY: KeyPair by lazy { generateKeyPair() } val BOC_PUBKEY: PublicKey get() = BOC_KEY.public -val BOC: Party get() = Party(getTestX509Name("BankOfCorda"), BOC_PUBKEY) +val BOC: PartyAndCertificate get() = getTestPartyAndCertificate(getTestX509Name("BankOfCorda"), BOC_PUBKEY) val BOC_PARTY_REF = BOC.ref(OpaqueBytes.of(1)).reference val BIG_CORP_KEY: KeyPair by lazy { generateKeyPair() } val BIG_CORP_PUBKEY: PublicKey get() = BIG_CORP_KEY.public -val BIG_CORP: Party get() = Party(X509Utilities.getDevX509Name("BigCorporation"), BIG_CORP_PUBKEY) +val BIG_CORP: PartyAndCertificate get() = getTestPartyAndCertificate(X509Utilities.getDevX509Name("BigCorporation"), BIG_CORP_PUBKEY) val BIG_CORP_PARTY_REF = BIG_CORP.ref(OpaqueBytes.of(1)).reference val ALL_TEST_KEYS: List get() = listOf(MEGA_CORP_KEY, MINI_CORP_KEY, ALICE_KEY, BOB_KEY, DUMMY_NOTARY_KEY) -val MOCK_IDENTITY_SERVICE: IdentityService get() = InMemoryIdentityService(listOf(MEGA_CORP, MINI_CORP, DUMMY_NOTARY)) +val MOCK_IDENTITY_SERVICE: IdentityService get() = InMemoryIdentityService(listOf(MEGA_CORP, MINI_CORP, DUMMY_NOTARY), emptyMap(), DUMMY_CA.certificate) val MOCK_VERSION_INFO = VersionInfo(1, "Mock release", "Mock revision", "Mock Vendor") diff --git a/test-utils/src/main/kotlin/net/corda/testing/node/MockNode.kt b/test-utils/src/main/kotlin/net/corda/testing/node/MockNode.kt index 5014db0a5b..efdab54b7c 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/node/MockNode.kt +++ b/test-utils/src/main/kotlin/net/corda/testing/node/MockNode.kt @@ -7,6 +7,7 @@ import com.google.common.util.concurrent.ListenableFuture import net.corda.core.* import net.corda.core.crypto.entropyToKeyPair import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.messaging.RPCOps import net.corda.core.messaging.SingleMessageRecipient import net.corda.core.node.CordaPluginRegistry @@ -14,6 +15,7 @@ import net.corda.core.node.PhysicalLocation import net.corda.core.node.ServiceEntry import net.corda.core.node.services.* import net.corda.core.utilities.DUMMY_NOTARY_KEY +import net.corda.core.utilities.getTestPartyAndCertificate import net.corda.core.utilities.loggerFor import net.corda.node.internal.AbstractNode import net.corda.node.services.config.NodeConfiguration @@ -38,6 +40,7 @@ import org.slf4j.Logger import java.math.BigInteger import java.nio.file.FileSystem import java.security.KeyPair +import java.security.cert.X509Certificate import java.util.* import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicInteger @@ -68,7 +71,7 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false, // A unique identifier for this network to segregate databases with the same nodeID but different networks. private val networkId = random63BitValue() - val identities = ArrayList() + val identities = ArrayList() private val _nodes = ArrayList() /** A read only view of the current set of executing nodes. */ @@ -162,7 +165,8 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false, .getOrThrow() } - override fun makeIdentityService() = InMemoryIdentityService(mockNet.identities) + // TODO: Specify a CA to validate registration against + override fun makeIdentityService() = InMemoryIdentityService(mockNet.identities, trustRoot = null as X509Certificate?) override fun makeVaultService(dataSourceProperties: Properties): VaultService = NodeVaultService(services, dataSourceProperties) @@ -187,7 +191,7 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false, val override = overrideServices[it.info] if (override != null) { // TODO: Store the key - ServiceEntry(it.info, Party(it.identity.name, override.public)) + ServiceEntry(it.info, getTestPartyAndCertificate(it.identity.name, override.public)) } else { it } diff --git a/test-utils/src/main/kotlin/net/corda/testing/node/MockServices.kt b/test-utils/src/main/kotlin/net/corda/testing/node/MockServices.kt index a41d27720e..7627774628 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/node/MockServices.kt +++ b/test-utils/src/main/kotlin/net/corda/testing/node/MockServices.kt @@ -3,7 +3,7 @@ package net.corda.testing.node import net.corda.core.contracts.Attachment import net.corda.core.crypto.* import net.corda.core.flows.StateMachineRunId -import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.messaging.SingleMessageRecipient import net.corda.core.node.NodeInfo import net.corda.core.node.ServiceHub @@ -11,10 +11,12 @@ import net.corda.core.node.services.* import net.corda.core.serialization.SerializeAsToken import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.core.transactions.SignedTransaction +import net.corda.core.utilities.DUMMY_CA import net.corda.core.utilities.DUMMY_NOTARY import net.corda.core.utilities.getTestPartyAndCertificate import net.corda.node.services.identity.InMemoryIdentityService -import net.corda.node.services.keys.freshKeyAndCert +import net.corda.node.services.keys.freshCertificate +import net.corda.node.services.keys.getSigner import net.corda.node.services.persistence.InMemoryStateMachineRecordedTransactionMappingStorage import net.corda.node.services.schema.HibernateObserver import net.corda.node.services.schema.NodeSchemaService @@ -24,6 +26,7 @@ import net.corda.testing.MEGA_CORP import net.corda.testing.MINI_CORP import net.corda.testing.MOCK_VERSION_INFO import org.bouncycastle.cert.X509CertificateHolder +import org.bouncycastle.operator.ContentSigner import rx.Observable import rx.subjects.PublishSubject import java.io.ByteArrayInputStream @@ -63,7 +66,8 @@ open class MockServices(vararg val keys: KeyPair) : ServiceHub { } override val storageService: TxWritableStorageService = MockStorageService() - override final val identityService: IdentityService = InMemoryIdentityService(listOf(MEGA_CORP, MINI_CORP, DUMMY_NOTARY)) + override final val identityService: IdentityService = InMemoryIdentityService(listOf(MEGA_CORP, MINI_CORP, DUMMY_NOTARY), + trustRoot = DUMMY_CA.certificate) override val keyManagementService: KeyManagementService = MockKeyManagementService(identityService, *keys) override val vaultService: VaultService get() = throw UnsupportedOperationException() @@ -96,10 +100,12 @@ class MockKeyManagementService(val identityService: IdentityService, return k.public } - override fun freshKeyAndCert(identity: Party, revocationEnabled: Boolean): Pair { - return freshKeyAndCert(this, identityService, identity, revocationEnabled) + override fun freshKeyAndCert(identity: PartyAndCertificate, revocationEnabled: Boolean): Pair { + return freshCertificate(identityService, freshKey(), identity, getSigner(identity.owningKey), revocationEnabled) } + private fun getSigner(publicKey: PublicKey): ContentSigner = getSigner(getSigningKeyPair(publicKey)) + private fun getSigningKeyPair(publicKey: PublicKey): KeyPair { val pk = publicKey.keys.first { keyStore.containsKey(it) } return KeyPair(pk, keyStore[pk]!!) diff --git a/test-utils/src/main/kotlin/net/corda/testing/node/SimpleNode.kt b/test-utils/src/main/kotlin/net/corda/testing/node/SimpleNode.kt index 0fb681071c..8717801e62 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/node/SimpleNode.kt +++ b/test-utils/src/main/kotlin/net/corda/testing/node/SimpleNode.kt @@ -3,7 +3,6 @@ package net.corda.testing.node import com.codahale.metrics.MetricRegistry import com.google.common.net.HostAndPort import com.google.common.util.concurrent.SettableFuture -import net.corda.core.crypto.CertificateAndKeyPair import net.corda.core.crypto.commonName import net.corda.core.crypto.generateKeyPair import net.corda.core.messaging.RPCOps @@ -22,6 +21,7 @@ import net.corda.node.utilities.configureDatabase import net.corda.node.utilities.transaction import net.corda.testing.MOCK_VERSION_INFO import net.corda.testing.freeLocalHostAndPort +import org.bouncycastle.cert.X509CertificateHolder import org.jetbrains.exposed.sql.Database import java.io.Closeable import java.security.KeyPair @@ -33,14 +33,14 @@ import kotlin.concurrent.thread */ class SimpleNode(val config: NodeConfiguration, val address: HostAndPort = freeLocalHostAndPort(), rpcAddress: HostAndPort = freeLocalHostAndPort(), - networkRoot: CertificateAndKeyPair? = null) : AutoCloseable { + trustRoot: X509CertificateHolder? = null) : AutoCloseable { private val databaseWithCloseable: Pair = configureDatabase(config.dataSourceProperties) val database: Database get() = databaseWithCloseable.second val userService = RPCUserServiceImpl(config.rpcUsers) val monitoringService = MonitoringService(MetricRegistry()) val identity: KeyPair = generateKeyPair() - val identityService: IdentityService = InMemoryIdentityService() + val identityService: IdentityService = InMemoryIdentityService(trustRoot = trustRoot) val keyService: KeyManagementService = E2ETestKeyManagementService(identityService, setOf(identity)) val executor = ServiceAffinityExecutor(config.myLegalName.commonName, 1) val broker = ArtemisMessagingServer(config, address, rpcAddress, InMemoryNetworkMapCache(), userService) diff --git a/tools/explorer/src/main/kotlin/net/corda/explorer/views/cordapps/cash/NewTransaction.kt b/tools/explorer/src/main/kotlin/net/corda/explorer/views/cordapps/cash/NewTransaction.kt index 81251c9891..e0883cc311 100644 --- a/tools/explorer/src/main/kotlin/net/corda/explorer/views/cordapps/cash/NewTransaction.kt +++ b/tools/explorer/src/main/kotlin/net/corda/explorer/views/cordapps/cash/NewTransaction.kt @@ -183,7 +183,7 @@ class NewTransaction : Fragment() { // Issuer issuerLabel.visibleProperty().bind(transactionTypeCB.valueProperty().isNotNull) issuerChoiceBox.apply { - items = issuers.map { it.legalIdentity }.unique().sorted() + items = issuers.map { it.legalIdentity as Party }.unique().sorted() converter = stringConverter { PartyNameFormatter.short.format(it.name) } visibleProperty().bind(transactionTypeCB.valueProperty().map { it == CashTransaction.Pay }) } From f210370885ebec0941c6a2ef666e1280b6f407bd Mon Sep 17 00:00:00 2001 From: Andrius Dagys Date: Wed, 31 May 2017 11:15:26 +0100 Subject: [PATCH 022/126] Pass ports instead of hostAndPorts to the message broker. Pass an address for the NodeMessagingClient to advertise to the network map service. --- .../kotlin/net/corda/node/internal/Node.kt | 33 +++++++++++++++---- .../messaging/ArtemisMessagingServer.kt | 16 ++++----- .../services/messaging/NodeMessagingClient.kt | 22 ++++--------- .../messaging/ArtemisMessagingTests.kt | 16 ++++----- .../kotlin/net/corda/testing/CoreTestUtils.kt | 13 +++++--- .../net/corda/testing/node/SimpleNode.kt | 2 +- 6 files changed, 59 insertions(+), 43 deletions(-) diff --git a/node/src/main/kotlin/net/corda/node/internal/Node.kt b/node/src/main/kotlin/net/corda/node/internal/Node.kt index 5795aa8627..4a195ff3c2 100644 --- a/node/src/main/kotlin/net/corda/node/internal/Node.kt +++ b/node/src/main/kotlin/net/corda/node/internal/Node.kt @@ -5,15 +5,18 @@ import com.google.common.net.HostAndPort import com.google.common.util.concurrent.Futures import com.google.common.util.concurrent.ListenableFuture import com.google.common.util.concurrent.SettableFuture -import net.corda.core.* +import net.corda.core.flatMap import net.corda.core.internal.ShutdownHook import net.corda.core.internal.addShutdownHook import net.corda.core.messaging.RPCOps +import net.corda.core.minutes import net.corda.core.node.ServiceHub import net.corda.core.node.VersionInfo import net.corda.core.node.services.ServiceInfo import net.corda.core.node.services.ServiceType import net.corda.core.node.services.UniquenessProvider +import net.corda.core.seconds +import net.corda.core.success import net.corda.core.utilities.loggerFor import net.corda.core.utilities.trace import net.corda.node.printBasicNodeInfo @@ -116,7 +119,17 @@ class Node(override val configuration: FullNodeConfiguration, override fun makeMessagingService(): MessagingService { userService = RPCUserServiceImpl(configuration.rpcUsers) - val serverAddress = configuration.messagingServerAddress ?: makeLocalMessageBroker() + + val (serverAddress, advertisedAddress) = with(configuration) { + if (messagingServerAddress != null) { + // External broker + messagingServerAddress to messagingServerAddress + } else { + makeLocalMessageBroker() to getAdvertisedAddress() + } + } + + printBasicNodeInfo("Incoming connection address", advertisedAddress.toString()) val myIdentityOrNullIfNetworkMapService = if (networkMapAddress != null) obtainLegalIdentity().owningKey else null return NodeMessagingClient( @@ -128,15 +141,21 @@ class Node(override val configuration: FullNodeConfiguration, database, networkMapRegistrationFuture, services.monitoringService, - configuration.messagingServerAddress == null) + advertisedAddress) } private fun makeLocalMessageBroker(): HostAndPort { with(configuration) { - val useHost = tryDetectIfNotPublicHost(p2pAddress.host) - val useAddress = useHost?.let { HostAndPort.fromParts(it, p2pAddress.port) } ?: p2pAddress - messageBroker = ArtemisMessagingServer(this, useAddress, rpcAddress, services.networkMapCache, userService) - return useAddress + messageBroker = ArtemisMessagingServer(this, p2pAddress.port, rpcAddress?.port, services.networkMapCache, userService) + return HostAndPort.fromParts("localhost", p2pAddress.port) + } + } + + private fun getAdvertisedAddress(): HostAndPort { + return with(configuration) { + val publicHost = tryDetectIfNotPublicHost(p2pAddress.host) + val useHost = publicHost ?: p2pAddress.host + HostAndPort.fromParts(useHost, p2pAddress.port) } } diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingServer.kt b/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingServer.kt index 8d019f95a5..391d88046d 100644 --- a/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingServer.kt +++ b/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingServer.kt @@ -85,8 +85,8 @@ import javax.security.cert.X509Certificate */ @ThreadSafe class ArtemisMessagingServer(override val config: NodeConfiguration, - val p2pHostPort: HostAndPort, - val rpcHostPort: HostAndPort?, + val p2pPort: Int, + val rpcPort: Int?, val networkMapCache: NetworkMapCache, val userService: RPCUserService) : ArtemisMessagingComponent() { companion object { @@ -156,9 +156,9 @@ class ArtemisMessagingServer(override val config: NodeConfiguration, registerPostQueueDeletionCallback { address, qName -> log.debug { "Queue deleted: $qName for $address" } } } activeMQServer.start() - printBasicNodeInfo("Listening on address", p2pHostPort.toString()) - if (rpcHostPort != null) { - printBasicNodeInfo("RPC service listening on address", rpcHostPort.toString()) + printBasicNodeInfo("Listening on port", p2pPort.toString()) + if (rpcPort != null) { + printBasicNodeInfo("RPC service listening on port", rpcPort.toString()) } } @@ -170,9 +170,9 @@ class ArtemisMessagingServer(override val config: NodeConfiguration, val connectionDirection = ConnectionDirection.Inbound( acceptorFactoryClassName = NettyAcceptorFactory::class.java.name ) - val acceptors = mutableSetOf(createTcpTransport(connectionDirection, "0.0.0.0", p2pHostPort.port)) - if (rpcHostPort != null) { - acceptors.add(createTcpTransport(connectionDirection, "0.0.0.0", rpcHostPort.port, enableSSL = false)) + val acceptors = mutableSetOf(createTcpTransport(connectionDirection, "0.0.0.0", p2pPort)) + if (rpcPort != null) { + acceptors.add(createTcpTransport(connectionDirection, "0.0.0.0", rpcPort, enableSSL = false)) } acceptorConfigurations = acceptors // Enable built in message deduplication. Note we still have to do our own as the delayed commits diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/NodeMessagingClient.kt b/node/src/main/kotlin/net/corda/node/services/messaging/NodeMessagingClient.kt index bebae60032..19e1802dc4 100644 --- a/node/src/main/kotlin/net/corda/node/services/messaging/NodeMessagingClient.kt +++ b/node/src/main/kotlin/net/corda/node/services/messaging/NodeMessagingClient.kt @@ -61,22 +61,23 @@ import javax.annotation.concurrent.ThreadSafe * invoke methods on the provided implementation. There is more documentation on this in the docsite and the * CordaRPCClient class. * - * @param serverHostPort The address of the broker instance to connect to (might be running in the same process). + * @param serverAddress The address of the broker instance to connect to (might be running in the same process). * @param myIdentity Either the public key to be used as the ArtemisMQ address and queue name for the node globally, or null to indicate * that this is a NetworkMapService node which will be bound globally to the name "networkmap". * @param nodeExecutor An executor to run received message tasks upon. - * @param isServerLocal Specify `true` if the provided [serverHostPort] is a locally running broker instance. + * @param advertisedAddress The node address for inbound connections, advertised to the network map service and peers. + * If not provided, will default to [serverAddress]. */ @ThreadSafe class NodeMessagingClient(override val config: NodeConfiguration, val versionInfo: VersionInfo, - val serverHostPort: HostAndPort, + val serverAddress: HostAndPort, val myIdentity: PublicKey?, val nodeExecutor: AffinityExecutor.ServiceAffinityExecutor, val database: Database, val networkMapRegistrationFuture: ListenableFuture, val monitoringService: MonitoringService, - val isServerLocal: Boolean = true + advertisedAddress: HostAndPort = serverAddress ) : ArtemisMessagingComponent(), MessagingService { companion object { private val log = loggerFor() @@ -132,9 +133,9 @@ class NodeMessagingClient(override val config: NodeConfiguration, * Apart from the NetworkMapService this is the only other address accessible to the node outside of lookups against the NetworkMapCache. */ override val myAddress: SingleMessageRecipient = if (myIdentity != null) { - NodeAddress.asPeer(myIdentity, serverHostPort) + NodeAddress.asPeer(myIdentity, advertisedAddress) } else { - NetworkMapAddress(serverHostPort) + NetworkMapAddress(advertisedAddress) } private val state = ThreadBox(InnerState()) @@ -158,8 +159,6 @@ class NodeMessagingClient(override val config: NodeConfiguration, check(!started) { "start can't be called twice" } started = true - val serverAddress = getBrokerAddress() - log.info("Connecting to server: $serverAddress") // TODO Add broker CN to config for host verification in case the embedded broker isn't used val tcpTransport = ArtemisTcpTransport.tcpTransport(ConnectionDirection.Outbound(), serverAddress, config) @@ -216,13 +215,6 @@ class NodeMessagingClient(override val config: NodeConfiguration, resumeMessageRedelivery() } - /** - * If the message broker is running locally and [serverHostPort] specifies a public IP, the messaging client will - * fail to connect on nodes under a NAT with no loopback support. As the local message broker is listening on - * all interfaces it is safer to always use `localhost` instead. - */ - private fun getBrokerAddress() = if (isServerLocal) HostAndPort.fromParts("localhost", serverHostPort.port) else serverHostPort - /** * We make the consumer twice, once to filter for just network map messages, and then once that is complete, we close * the original and make another without a filter. We do this so that there is a network map in place for all other diff --git a/node/src/test/kotlin/net/corda/node/services/messaging/ArtemisMessagingTests.kt b/node/src/test/kotlin/net/corda/node/services/messaging/ArtemisMessagingTests.kt index 41184f80f8..41c4386930 100644 --- a/node/src/test/kotlin/net/corda/node/services/messaging/ArtemisMessagingTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/messaging/ArtemisMessagingTests.kt @@ -24,10 +24,10 @@ import net.corda.node.utilities.transaction import net.corda.testing.MOCK_VERSION_INFO import net.corda.testing.TestNodeConfiguration import net.corda.testing.freeLocalHostAndPort +import net.corda.testing.freePort import net.corda.testing.node.makeTestDataSourceProperties import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThatThrownBy -import org.bouncycastle.asn1.x500.X500Name import org.jetbrains.exposed.sql.Database import org.junit.After import org.junit.Before @@ -46,8 +46,8 @@ import kotlin.test.assertNull class ArtemisMessagingTests { @Rule @JvmField val temporaryFolder = TemporaryFolder() - val hostAndPort = freeLocalHostAndPort() - val rpcHostAndPort = freeLocalHostAndPort() + val serverPort = freePort() + val rpcPort = freePort() val topic = "platform.self" val identity = generateKeyPair() @@ -93,7 +93,7 @@ class ArtemisMessagingTests { @Test fun `server starting with the port already bound should throw`() { - ServerSocket(hostAndPort.port).use { + ServerSocket(serverPort).use { val messagingServer = createMessagingServer() assertThatThrownBy { messagingServer.start() } } @@ -103,7 +103,7 @@ class ArtemisMessagingTests { fun `client should connect to remote server`() { val remoteServerAddress = freeLocalHostAndPort() - createMessagingServer(remoteServerAddress).start() + createMessagingServer(remoteServerAddress.port).start() createMessagingClient(server = remoteServerAddress) startNodeMessagingClient() } @@ -113,7 +113,7 @@ class ArtemisMessagingTests { val serverAddress = freeLocalHostAndPort() val invalidServerAddress = freeLocalHostAndPort() - createMessagingServer(serverAddress).start() + createMessagingServer(serverAddress.port).start() messagingClient = createMessagingClient(server = invalidServerAddress) assertThatThrownBy { startNodeMessagingClient() } @@ -218,7 +218,7 @@ class ArtemisMessagingTests { return messagingClient } - private fun createMessagingClient(server: HostAndPort = hostAndPort): NodeMessagingClient { + private fun createMessagingClient(server: HostAndPort = HostAndPort.fromParts("localhost", serverPort)): NodeMessagingClient { return database.transaction { NodeMessagingClient( config, @@ -235,7 +235,7 @@ class ArtemisMessagingTests { } } - private fun createMessagingServer(local: HostAndPort = hostAndPort, rpc: HostAndPort = rpcHostAndPort): ArtemisMessagingServer { + private fun createMessagingServer(local: Int = serverPort, rpc: Int = rpcPort): ArtemisMessagingServer { return ArtemisMessagingServer(config, local, rpc, networkMapCache, userService).apply { config.configureWithDevSSLCertificate() messagingServer = this diff --git a/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt b/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt index 05a4bb8de0..46dda4ddb4 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt +++ b/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt @@ -88,16 +88,21 @@ val MOCK_VERSION_INFO = VersionInfo(1, "Mock release", "Mock revision", "Mock Ve fun generateStateRef() = StateRef(SecureHash.randomSHA256(), 0) private val freePortCounter = AtomicInteger(30000) +/** + * Returns a localhost address with a free port. + * + * Unsafe for getting multiple ports! + * Use [getFreeLocalPorts] for getting multiple ports. + */ +fun freeLocalHostAndPort(): HostAndPort = HostAndPort.fromParts("localhost", freePort()) + /** * Returns a free port. * * Unsafe for getting multiple ports! * Use [getFreeLocalPorts] for getting multiple ports. */ -fun freeLocalHostAndPort(): HostAndPort { - val freePort = freePortCounter.getAndAccumulate(0) { prev, _ -> 30000 + (prev - 30000 + 1) % 10000 } - return HostAndPort.fromParts("localhost", freePort) -} +fun freePort(): Int = freePortCounter.getAndAccumulate(0) { prev, _ -> 30000 + (prev - 30000 + 1) % 10000 } /** * Creates a specified number of ports for use by the Node. diff --git a/test-utils/src/main/kotlin/net/corda/testing/node/SimpleNode.kt b/test-utils/src/main/kotlin/net/corda/testing/node/SimpleNode.kt index 8717801e62..73de38dc5b 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/node/SimpleNode.kt +++ b/test-utils/src/main/kotlin/net/corda/testing/node/SimpleNode.kt @@ -43,7 +43,7 @@ class SimpleNode(val config: NodeConfiguration, val address: HostAndPort = freeL val identityService: IdentityService = InMemoryIdentityService(trustRoot = trustRoot) val keyService: KeyManagementService = E2ETestKeyManagementService(identityService, setOf(identity)) val executor = ServiceAffinityExecutor(config.myLegalName.commonName, 1) - val broker = ArtemisMessagingServer(config, address, rpcAddress, InMemoryNetworkMapCache(), userService) + val broker = ArtemisMessagingServer(config, address.port, rpcAddress.port, InMemoryNetworkMapCache(), userService) val networkMapRegistrationFuture: SettableFuture = SettableFuture.create() val net = database.transaction { NodeMessagingClient( From 39fdb353ad682225386374f44ee6c1defa71a7b6 Mon Sep 17 00:00:00 2001 From: Katarzyna Streich Date: Wed, 31 May 2017 16:07:13 +0100 Subject: [PATCH 023/126] Remove nearestCity from node configuration. (#721) * Fix bug in demobench. Explorer didn't show correctly location of a node. There was no nearestCity override in config. * Remove nearestCity from node configuration. Now information about the location is always taken from node's legal name. If not present - exception on node startup. * Add X500Name.locationOrNull that soft fails when location is not in X500 name. Address PR comments. * Remove unused imports. --- build.gradle | 3 --- config/dev/generalnodea.conf | 1 - config/dev/generalnodeb.conf | 1 - config/dev/nameservernode.conf | 1 - .../java/net/corda/cordform/CordformNode.java | 9 --------- .../kotlin/net/corda/core/crypto/X509Utilities.kt | 1 + docs/source/corda-configuration-file.rst | 4 ---- docs/source/creating-a-cordapp.rst | 3 --- docs/source/example-code/build.gradle | 2 -- .../main/resources/example-network-map-node.conf | 1 - .../src/main/resources/example-node.conf | 1 - .../example-out-of-process-verifier-node.conf | 1 - docs/source/permissioning.rst | 2 -- docs/source/tutorial-cordapp.rst | 2 -- .../net/corda/node/internal/AbstractNode.kt | 4 +++- .../node/services/config/NodeConfiguration.kt | 2 -- .../registration/NetworkRegistrationHelper.kt | 1 - node/src/main/resources/reference.conf | 1 - samples/attachment-demo/build.gradle | 3 --- samples/bank-of-corda-demo/build.gradle | 3 --- samples/irs-demo/build.gradle | 3 --- .../kotlin/net/corda/irs/simulation/Simulation.kt | 5 ++++- .../net/corda/notarydemo/RaftNotaryCordform.kt | 0 samples/simm-valuation-demo/build.gradle | 4 ---- samples/trader-demo/build.gradle | 4 ---- .../kotlin/net/corda/testing/CoreTestUtils.kt | 2 -- .../net/corda/demobench/model/InstallFactory.kt | 4 ++-- .../net/corda/demobench/model/NodeConfig.kt | 4 ++-- .../net/corda/demobench/views/NodeTabView.kt | 2 +- .../src/main/kotlin/net/corda/explorer/Main.kt | 15 +++++---------- 30 files changed, 18 insertions(+), 71 deletions(-) create mode 100644 samples/raft-notary-demo/src/main/kotlin/net/corda/notarydemo/RaftNotaryCordform.kt diff --git a/build.gradle b/build.gradle index 54bc126c8b..2622190ceb 100644 --- a/build.gradle +++ b/build.gradle @@ -222,14 +222,12 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { networkMap "CN=Controller,O=R3,OU=corda,L=London,C=UK" node { name "CN=Controller,O=R3,OU=corda,L=London,C=UK" - nearestCity "London" advertisedServices = ["corda.notary.validating"] p2pPort 10002 cordapps = [] } node { name "CN=Bank A,O=R3,OU=corda,L=London,C=UK" - nearestCity "London" advertisedServices = [] p2pPort 10012 rpcPort 10013 @@ -238,7 +236,6 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { } node { name "CN=Bank B,O=R3,OU=corda,L=London,C=UK" - nearestCity "New York" advertisedServices = [] p2pPort 10007 rpcPort 10008 diff --git a/config/dev/generalnodea.conf b/config/dev/generalnodea.conf index 1ad2dea3d2..c9693cf232 100644 --- a/config/dev/generalnodea.conf +++ b/config/dev/generalnodea.conf @@ -1,5 +1,4 @@ myLegalName : "CN=Bank A,O=Bank A,L=London,C=UK" -nearestCity : "London" keyStorePassword : "cordacadevpass" trustStorePassword : "trustpass" p2pAddress : "localhost:10002" diff --git a/config/dev/generalnodeb.conf b/config/dev/generalnodeb.conf index 510b3e9b70..65b254ae61 100644 --- a/config/dev/generalnodeb.conf +++ b/config/dev/generalnodeb.conf @@ -1,5 +1,4 @@ myLegalName : "CN=Bank B,O=Bank A,L=London,C=UK" -nearestCity : "London" keyStorePassword : "cordacadevpass" trustStorePassword : "trustpass" p2pAddress : "localhost:10005" diff --git a/config/dev/nameservernode.conf b/config/dev/nameservernode.conf index 73591fa46d..f2592035b3 100644 --- a/config/dev/nameservernode.conf +++ b/config/dev/nameservernode.conf @@ -1,5 +1,4 @@ myLegalName : "CN=Notary Service,O=R3,OU=corda,L=London,C=UK" -nearestCity : "London" keyStorePassword : "cordacadevpass" trustStorePassword : "trustpass" p2pAddress : "localhost:10000" diff --git a/cordform-common/src/main/java/net/corda/cordform/CordformNode.java b/cordform-common/src/main/java/net/corda/cordform/CordformNode.java index 4e73dac456..66e0ba9ca0 100644 --- a/cordform-common/src/main/java/net/corda/cordform/CordformNode.java +++ b/cordform-common/src/main/java/net/corda/cordform/CordformNode.java @@ -55,15 +55,6 @@ public class CordformNode { 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. * diff --git a/core/src/main/kotlin/net/corda/core/crypto/X509Utilities.kt b/core/src/main/kotlin/net/corda/core/crypto/X509Utilities.kt index 865ab09c8e..f038a02d60 100644 --- a/core/src/main/kotlin/net/corda/core/crypto/X509Utilities.kt +++ b/core/src/main/kotlin/net/corda/core/crypto/X509Utilities.kt @@ -280,6 +280,7 @@ private fun X500Name.mutateCommonName(mutator: (ASN1Encodable) -> String): X500N val X500Name.commonName: String get() = getRDNs(BCStyle.CN).first().first.value.toString() val X500Name.orgName: String? get() = getRDNs(BCStyle.O).firstOrNull()?.first?.value?.toString() val X500Name.location: String get() = getRDNs(BCStyle.L).first().first.value.toString() +val X500Name.locationOrNull: String? get() = try { location } catch (e: Exception) { null } val X509Certificate.subject: X500Name get() = X509CertificateHolder(encoded).subject class CertificateStream(val input: InputStream) { diff --git a/docs/source/corda-configuration-file.rst b/docs/source/corda-configuration-file.rst index 39feba07ee..69c0592b18 100644 --- a/docs/source/corda-configuration-file.rst +++ b/docs/source/corda-configuration-file.rst @@ -35,7 +35,6 @@ NetworkMapService plus Simple Notary configuration file. .. parsed-literal:: myLegalName : "CN=Notary Service,O=R3,OU=corda,L=London,C=UK" - nearestCity : "London" keyStorePassword : "cordacadevpass" trustStorePassword : "trustpass" p2pAddress : "localhost:12345" @@ -56,9 +55,6 @@ path to the node's base directory. :myLegalName: The legal identity of the node acts as a human readable alias to the node's public key and several demos use this to lookup the NodeInfo. -:nearestCity: The location of the node as used to locate coordinates on the world map when running the network simulator - demo. See :doc:`network-simulator`. - :keyStorePassword: The password to unlock the KeyStore file (``/certificates/sslkeystore.jks``) containing the node certificate and private key. diff --git a/docs/source/creating-a-cordapp.rst b/docs/source/creating-a-cordapp.rst index 5a31c228a0..65787626af 100644 --- a/docs/source/creating-a-cordapp.rst +++ b/docs/source/creating-a-cordapp.rst @@ -209,7 +209,6 @@ is a three node example; networkMap "CN=Controller,O=R3,OU=corda,L=London,C=UK" // The distinguished name of the node named here will be used as the networkMapService.address on all other nodes. node { name "CN=Controller,O=R3,OU=corda,L=London,C=UK" - nearestCity "London" advertisedServices = [ "corda.notary.validating" ] p2pPort 10002 rpcPort 10003 @@ -219,7 +218,6 @@ is a three node example; } node { name "CN=NodeA,O=R3,OU=corda,L=London,C=UK" - nearestCity "London" advertisedServices = [] p2pPort 10005 rpcPort 10006 @@ -229,7 +227,6 @@ is a three node example; } node { name "CN=NodeB,O=R3,OU=corda,L=New York,C=US" - nearestCity "New York" advertisedServices = [] p2pPort 10008 rpcPort 10009 diff --git a/docs/source/example-code/build.gradle b/docs/source/example-code/build.gradle index 311bf42623..754026fa45 100644 --- a/docs/source/example-code/build.gradle +++ b/docs/source/example-code/build.gradle @@ -73,7 +73,6 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { networkMap "CN=Notary Service,O=R3,OU=corda,L=London,C=UK" node { name "CN=Notary Service,O=R3,OU=corda,L=London,C=UK" - nearestCity "London" advertisedServices = ["corda.notary.validating"] p2pPort 10002 rpcPort 10003 @@ -82,7 +81,6 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { } node { name "CN=Alice Corp,O=Alice Corp,L=London,C=UK" - nearestCity "London" advertisedServices = [] p2pPort 10005 rpcPort 10006 diff --git a/docs/source/example-code/src/main/resources/example-network-map-node.conf b/docs/source/example-code/src/main/resources/example-network-map-node.conf index 1cebb8b8c5..7dfa80e6e1 100644 --- a/docs/source/example-code/src/main/resources/example-network-map-node.conf +++ b/docs/source/example-code/src/main/resources/example-network-map-node.conf @@ -1,5 +1,4 @@ myLegalName : "CN=Notary Service,O=R3,OU=corda,L=London,C=UK" -nearestCity : "London" keyStorePassword : "cordacadevpass" trustStorePassword : "trustpass" p2pAddress : "my-network-map:10000" diff --git a/docs/source/example-code/src/main/resources/example-node.conf b/docs/source/example-code/src/main/resources/example-node.conf index de024c5215..ecf2dd601a 100644 --- a/docs/source/example-code/src/main/resources/example-node.conf +++ b/docs/source/example-code/src/main/resources/example-node.conf @@ -1,5 +1,4 @@ myLegalName : "CN=Bank A,O=Bank A,L=London,C=UK" -nearestCity : "London" keyStorePassword : "cordacadevpass" trustStorePassword : "trustpass" dataSourceProperties : { diff --git a/docs/source/example-code/src/main/resources/example-out-of-process-verifier-node.conf b/docs/source/example-code/src/main/resources/example-out-of-process-verifier-node.conf index f7636fc105..e2c94653d1 100644 --- a/docs/source/example-code/src/main/resources/example-out-of-process-verifier-node.conf +++ b/docs/source/example-code/src/main/resources/example-out-of-process-verifier-node.conf @@ -1,5 +1,4 @@ myLegalName : "CN=Bank A,O=Bank A,L=London,C=UK" -nearestCity : "London" p2pAddress : "my-corda-node:10002" webAddress : "localhost:10003" networkMapService : { diff --git a/docs/source/permissioning.rst b/docs/source/permissioning.rst index 1a75104a7f..420188c73d 100644 --- a/docs/source/permissioning.rst +++ b/docs/source/permissioning.rst @@ -22,8 +22,6 @@ The following information from the node configuration file is needed to generate .. note:: In a future version the uniqueness requirement will be relaxed to a X.500 name. This will allow differentiation between entities with the same name. -:nearestCity: e.g. "London" - :emailAddress: e.g. "admin@company.com" :certificateSigningService: Doorman server URL. A doorman server will be hosted by R3 in the near diff --git a/docs/source/tutorial-cordapp.rst b/docs/source/tutorial-cordapp.rst index 1dd25730e2..3ae1712e65 100644 --- a/docs/source/tutorial-cordapp.rst +++ b/docs/source/tutorial-cordapp.rst @@ -777,7 +777,6 @@ like to deploy for testing. See further details below: networkMap "CN=Controller,O=R3,OU=corda,L=London,C=UK" // The distinguished name of the node to be used as the network map. node { name "CN=Controller,O=R3,OU=corda,L=London,C=UK" // Distinguished name of node to be deployed. - nearestCity "London" // For use with the network visualiser. advertisedServices = ["corda.notary.validating"] // A list of services you wish the node to offer. p2pPort 10002 rpcPort 10003 // Usually 1 higher than the messaging port. @@ -786,7 +785,6 @@ like to deploy for testing. See further details below: } node { // Create an additional node. name "CN=NodeA,O=R3,OU=corda,L=London,C=UK" - nearestCity "London" advertisedServices = [] p2pPort 10005 rpcPort 10006 diff --git a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt index f1375da51b..51d10caacb 100644 --- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt @@ -154,7 +154,9 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, } } - open fun findMyLocation(): PhysicalLocation? = CityDatabase[configuration.nearestCity] + open fun findMyLocation(): PhysicalLocation? { + return configuration.myLegalName.locationOrNull?.let { CityDatabase[it] } + } lateinit var info: NodeInfo lateinit var storage: TxWritableStorageService diff --git a/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt b/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt index 9d7f078516..224c2468cb 100644 --- a/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt +++ b/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt @@ -21,7 +21,6 @@ interface NodeConfiguration : NodeSSLConfiguration { val myLegalName: X500Name val networkMapService: NetworkMapInfo? val minimumPlatformVersion: Int - val nearestCity: String val emailAddress: String val exportJMXto: String val dataSourceProperties: Properties @@ -40,7 +39,6 @@ data class FullNodeConfiguration( ReplaceWith("baseDirectory")) val basedir: Path, override val myLegalName: X500Name, - override val nearestCity: String, override val emailAddress: String, override val keyStorePassword: String, override val trustStorePassword: String, diff --git a/node/src/main/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelper.kt b/node/src/main/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelper.kt index 79a7f8e69f..13f8040a37 100644 --- a/node/src/main/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelper.kt +++ b/node/src/main/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelper.kt @@ -123,7 +123,6 @@ class NetworkRegistrationHelper(val config: NodeConfiguration, val certService: println("Certificate signing request with the following information will be submitted to the Corda certificate signing server.") println() println("Legal Name: ${config.myLegalName}") - println("Nearest City: ${config.nearestCity}") println("Email: ${config.emailAddress}") println() println("Public Key: ${keyPair.public}") diff --git a/node/src/main/resources/reference.conf b/node/src/main/resources/reference.conf index 51b4b29675..7d9f8a2b42 100644 --- a/node/src/main/resources/reference.conf +++ b/node/src/main/resources/reference.conf @@ -1,5 +1,4 @@ myLegalName = "Vast Global MegaCorp, Ltd" -nearestCity = "London" emailAddress = "admin@company.com" exportJMXto = "http" keyStorePassword = "cordacadevpass" diff --git a/samples/attachment-demo/build.gradle b/samples/attachment-demo/build.gradle index 99454ee5d1..ec2d727ff0 100644 --- a/samples/attachment-demo/build.gradle +++ b/samples/attachment-demo/build.gradle @@ -48,7 +48,6 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { networkMap "CN=Notary Service,O=R3,OU=corda,L=London,C=UK" node { name "CN=Notary Service,O=R3,OU=corda,L=London,C=UK" - nearestCity "London" advertisedServices["corda.notary.validating"] p2pPort 10002 rpcPort 10003 @@ -57,7 +56,6 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { } node { name "CN=Bank A,O=Bank A,L=London,C=UK" - nearestCity "London" advertisedServices = [] p2pPort 10005 rpcPort 10006 @@ -66,7 +64,6 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { } node { name "CN=Bank B,O=Bank B,L=New York,C=US" - nearestCity "New York" advertisedServices = [] p2pPort 10008 rpcPort 10009 diff --git a/samples/bank-of-corda-demo/build.gradle b/samples/bank-of-corda-demo/build.gradle index 4d1b593b74..c369d8100d 100644 --- a/samples/bank-of-corda-demo/build.gradle +++ b/samples/bank-of-corda-demo/build.gradle @@ -45,7 +45,6 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { networkMap "CN=Notary Service,O=R3,OU=corda,L=London,C=UK" node { name "CN=Notary Service,O=R3,OU=corda,L=London,C=UK" - nearestCity "London" advertisedServices = ["corda.notary.validating"] p2pPort 10002 rpcPort 10003 @@ -53,7 +52,6 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { } node { name "CN=BankOfCorda,O=R3,L=New York,C=US" - nearestCity "New York" advertisedServices = ["corda.issuer.USD"] p2pPort 10005 rpcPort 10006 @@ -68,7 +66,6 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { } node { name "CN=BigCorporation,O=R3,OU=corda,L=London,C=UK" - nearestCity "New York" advertisedServices = [] p2pPort 10008 rpcPort 10009 diff --git a/samples/irs-demo/build.gradle b/samples/irs-demo/build.gradle index 1f45c1903f..7ef056ceb5 100644 --- a/samples/irs-demo/build.gradle +++ b/samples/irs-demo/build.gradle @@ -50,7 +50,6 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { networkMap "CN=Notary Service,O=R3,OU=corda,L=London,C=UK" node { name "CN=Notary Service,O=R3,OU=corda,L=London,C=UK" - nearestCity "London" advertisedServices = ["corda.notary.validating", "corda.interest_rates"] p2pPort 10002 rpcPort 10003 @@ -60,7 +59,6 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { } node { name "CN=Bank A,O=Bank A,L=London,C=UK" - nearestCity "London" advertisedServices = [] p2pPort 10005 rpcPort 10006 @@ -70,7 +68,6 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { } node { name "CN=Bank B,O=Bank B,L=New York,C=US" - nearestCity "New York" advertisedServices = [] p2pPort 10008 rpcPort 10009 diff --git a/samples/irs-demo/src/main/kotlin/net/corda/irs/simulation/Simulation.kt b/samples/irs-demo/src/main/kotlin/net/corda/irs/simulation/Simulation.kt index a2a89ca38f..c2f93f75f9 100644 --- a/samples/irs-demo/src/main/kotlin/net/corda/irs/simulation/Simulation.kt +++ b/samples/irs-demo/src/main/kotlin/net/corda/irs/simulation/Simulation.kt @@ -2,6 +2,7 @@ package net.corda.irs.simulation import com.google.common.util.concurrent.Futures import com.google.common.util.concurrent.ListenableFuture +import net.corda.core.crypto.locationOrNull import net.corda.core.flatMap import net.corda.core.flows.FlowLogic import net.corda.core.messaging.SingleMessageRecipient @@ -56,7 +57,9 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean, advertisedServices: Set, id: Int, overrideServices: Map?, entropyRoot: BigInteger) : MockNetwork.MockNode(config, mockNet, networkMapAddress, advertisedServices, id, overrideServices, entropyRoot) { - override fun findMyLocation(): PhysicalLocation? = CityDatabase[configuration.nearestCity] + override fun findMyLocation(): PhysicalLocation? { + return configuration.myLegalName.locationOrNull?.let { CityDatabase[it] } + } } inner class BankFactory : MockNetwork.Factory { diff --git a/samples/raft-notary-demo/src/main/kotlin/net/corda/notarydemo/RaftNotaryCordform.kt b/samples/raft-notary-demo/src/main/kotlin/net/corda/notarydemo/RaftNotaryCordform.kt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/samples/simm-valuation-demo/build.gradle b/samples/simm-valuation-demo/build.gradle index 59bd02d389..95c8d55cf5 100644 --- a/samples/simm-valuation-demo/build.gradle +++ b/samples/simm-valuation-demo/build.gradle @@ -61,14 +61,12 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { networkMap "CN=Notary Service,O=R3,OU=corda,L=London,C=UK" node { name "CN=Notary Service,O=R3,OU=corda,L=London,C=UK" - nearestCity "London" advertisedServices = ["corda.notary.validating"] p2pPort 10002 cordapps = [] } node { name "CN=Bank A,O=Bank A,L=London,C=UK" - nearestCity "London" advertisedServices = [] p2pPort 10004 webPort 10005 @@ -76,7 +74,6 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { } node { name "CN=Bank B,O=Bank B,L=New York,C=US" - nearestCity "New York" advertisedServices = [] p2pPort 10006 webPort 10007 @@ -84,7 +81,6 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { } node { name "CN=Bank C,O=Bank C,L=Tokyo,C=Japan" - nearestCity "Tokyo" advertisedServices = [] p2pPort 10008 webPort 10009 diff --git a/samples/trader-demo/build.gradle b/samples/trader-demo/build.gradle index 779fd725f8..58b96b7cf7 100644 --- a/samples/trader-demo/build.gradle +++ b/samples/trader-demo/build.gradle @@ -61,14 +61,12 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { networkMap "CN=Notary Service,O=R3,OU=corda,L=London,C=UK" node { name "CN=Notary Service,O=R3,OU=corda,L=London,C=UK" - nearestCity "London" advertisedServices = ["corda.notary.validating"] p2pPort 10002 cordapps = [] } node { name "CN=Bank A,O=Bank A,L=London,C=UK" - nearestCity "London" advertisedServices = [] p2pPort 10005 rpcPort 10006 @@ -77,7 +75,6 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { } node { name "CN=Bank B,O=Bank B,L=New York,C=US" - nearestCity "New York" advertisedServices = [] p2pPort 10008 rpcPort 10009 @@ -86,7 +83,6 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { } node { name "CN=BankOfCorda,O=R3,L=New York,C=US" - nearestCity "London" advertisedServices = [] p2pPort 10011 cordapps = [] diff --git a/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt b/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt index 46dda4ddb4..8ac5392516 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt +++ b/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt @@ -156,7 +156,6 @@ data class TestNodeConfiguration( override val certificateChainCheckPolicies: List = emptyList(), override val verifierType: VerifierType = VerifierType.InMemory, override val messageRedeliveryDelaySeconds: Int = 5) : NodeConfiguration { - override val nearestCity = myLegalName.getRDNs(BCStyle.L).single().typesAndValues.single().value.toString() } fun testConfiguration(baseDirectory: Path, legalName: X500Name, basePort: Int): FullNodeConfiguration { @@ -164,7 +163,6 @@ fun testConfiguration(baseDirectory: Path, legalName: X500Name, basePort: Int): basedir = baseDirectory, myLegalName = legalName, networkMapService = null, - nearestCity = "Null Island", emailAddress = "", keyStorePassword = "cordacadevpass", trustStorePassword = "trustpass", diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/model/InstallFactory.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/model/InstallFactory.kt index 9a10e04652..c546657e7b 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/model/InstallFactory.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/model/InstallFactory.kt @@ -3,7 +3,6 @@ package net.corda.demobench.model import com.google.common.net.HostAndPort import com.typesafe.config.Config import org.bouncycastle.asn1.x500.X500Name - import tornadofx.* import java.io.IOException import java.nio.file.Files @@ -20,12 +19,13 @@ class InstallFactory : Controller() { val rpcPort = config.parsePort("rpcAddress") val webPort = config.parsePort("webAddress") val h2Port = config.getInt("h2port") + val x500name = X500Name(config.getString("myLegalName")) val extraServices = config.parseExtraServices("extraAdvertisedServiceIds") val tempDir = Files.createTempDirectory(baseDir, ".node") val nodeConfig = NodeConfig( tempDir, - X500Name(config.getString("myLegalName")), + x500name, p2pPort, rpcPort, webPort, diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeConfig.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeConfig.kt index baf94692f5..14ce84779f 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeConfig.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeConfig.kt @@ -1,7 +1,7 @@ package net.corda.demobench.model import com.typesafe.config.* -import net.corda.core.crypto.location +import net.corda.core.crypto.locationOrNull import net.corda.nodeapi.User import org.bouncycastle.asn1.x500.X500Name import java.io.File @@ -26,7 +26,7 @@ class NodeConfig( val defaultUser = user("guest") } - val nearestCity: String? = legalName.location + val nearestCity: String = legalName.locationOrNull ?: "Unknown location" val nodeDir: Path = baseDir.resolve(key) override val pluginDir: Path = nodeDir.resolve("plugins") val explorerDir: Path = baseDir.resolve("$key-explorer") diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/views/NodeTabView.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/views/NodeTabView.kt index 44a62537cb..d63c7ff366 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/views/NodeTabView.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/views/NodeTabView.kt @@ -263,7 +263,7 @@ class NodeTabView : Fragment() { } private fun launchNode(config: NodeConfig) { - val countryCode = CityDatabase.cityMap[config.nearestCity ?: "Nowhere"]?.countryCode + val countryCode = CityDatabase.cityMap[config.nearestCity]?.countryCode if (countryCode != null) { nodeTab.graphic = ImageView(flags.get()[countryCode]).apply { fitWidth = 24.0; isPreserveRatio = true } } diff --git a/tools/explorer/src/main/kotlin/net/corda/explorer/Main.kt b/tools/explorer/src/main/kotlin/net/corda/explorer/Main.kt index 6d8df49bff..652f9a6aad 100644 --- a/tools/explorer/src/main/kotlin/net/corda/explorer/Main.kt +++ b/tools/explorer/src/main/kotlin/net/corda/explorer/Main.kt @@ -166,20 +166,15 @@ fun main(args: Array) { startFlowPermission()) ) // TODO : Supported flow should be exposed somehow from the node instead of set of ServiceInfo. - val notary = startNode(DUMMY_NOTARY.name, advertisedServices = setOf(ServiceInfo(SimpleNotaryService.type)), - customOverrides = mapOf("nearestCity" to "Zurich")) + val notary = startNode(DUMMY_NOTARY.name, advertisedServices = setOf(ServiceInfo(SimpleNotaryService.type))) val alice = startNode(ALICE.name, rpcUsers = arrayListOf(user), - advertisedServices = setOf(ServiceInfo(ServiceType.corda.getSubType("cash"))), - customOverrides = mapOf("nearestCity" to "Milan")) + advertisedServices = setOf(ServiceInfo(ServiceType.corda.getSubType("cash")))) val bob = startNode(BOB.name, rpcUsers = arrayListOf(user), - advertisedServices = setOf(ServiceInfo(ServiceType.corda.getSubType("cash"))), - customOverrides = mapOf("nearestCity" to "Madrid")) + advertisedServices = setOf(ServiceInfo(ServiceType.corda.getSubType("cash")))) val issuerGBP = startNode(X500Name("CN=UK Bank Plc,O=UK Bank Plc,L=London,C=UK"), rpcUsers = arrayListOf(manager), - advertisedServices = setOf(ServiceInfo(ServiceType.corda.getSubType("issuer.GBP"))), - customOverrides = mapOf("nearestCity" to "London")) + advertisedServices = setOf(ServiceInfo(ServiceType.corda.getSubType("issuer.GBP")))) val issuerUSD = startNode(X500Name("CN=USA Bank Corp,O=USA Bank Corp,L=New York,C=US"), rpcUsers = arrayListOf(manager), - advertisedServices = setOf(ServiceInfo(ServiceType.corda.getSubType("issuer.USD"))), - customOverrides = mapOf("nearestCity" to "New York")) + advertisedServices = setOf(ServiceInfo(ServiceType.corda.getSubType("issuer.USD")))) val notaryNode = notary.get() val aliceNode = alice.get() From 4bd38d381a34322392f626e4f7f3277531d3b54f Mon Sep 17 00:00:00 2001 From: Andrzej Cichocki Date: Wed, 31 May 2017 17:12:25 +0100 Subject: [PATCH 024/126] Fix tests that check ports are bound/unbound (#756) * Specifically, DriverTests and WebserverDriverTests * RPCDriver.startRpcBroker now waits for port to be unbound, as was probably intended * Explicitly drop network map future while ensuring the error is logged --- .gitignore | 2 +- core/src/main/kotlin/net/corda/core/Utils.kt | 1 + .../test/kotlin/net/corda/core/UtilsTest.kt | 23 ++++++++++++++++++- .../kotlin/net/corda/node/driver/Driver.kt | 20 +++++++++++----- .../kotlin/net/corda/testing/RPCDriver.kt | 2 +- .../net/corda/testing/node/NodeBasedTest.kt | 6 ++--- 6 files changed, 42 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index 2460963d3b..c5ea620339 100644 --- a/.gitignore +++ b/.gitignore @@ -84,7 +84,7 @@ crashlytics-build.properties docs/virtualenv/ # bft-smart -config/currentView +**/config/currentView # vim *.swp diff --git a/core/src/main/kotlin/net/corda/core/Utils.kt b/core/src/main/kotlin/net/corda/core/Utils.kt index 7922150905..b2b17a7e33 100644 --- a/core/src/main/kotlin/net/corda/core/Utils.kt +++ b/core/src/main/kotlin/net/corda/core/Utils.kt @@ -106,6 +106,7 @@ fun ListenableFuture.failure(executor: Executor, body: (Throwable) -> Uni infix fun ListenableFuture.then(body: () -> Unit): ListenableFuture = apply { then(RunOnCallerThread, body) } infix fun ListenableFuture.success(body: (T) -> Unit): ListenableFuture = apply { success(RunOnCallerThread, body) } infix fun ListenableFuture.failure(body: (Throwable) -> Unit): ListenableFuture = apply { failure(RunOnCallerThread, body) } +fun ListenableFuture.andForget(log: Logger) = failure(RunOnCallerThread) { log.error("Background task failed:", it) } @Suppress("UNCHECKED_CAST") // We need the awkward cast because otherwise F cannot be nullable, even though it's safe. infix fun ListenableFuture.map(mapper: (F) -> T): ListenableFuture = Futures.transform(this, { (mapper as (F?) -> T)(it) }) infix fun ListenableFuture.flatMap(mapper: (F) -> ListenableFuture): ListenableFuture = Futures.transformAsync(this) { mapper(it!!) } diff --git a/core/src/test/kotlin/net/corda/core/UtilsTest.kt b/core/src/test/kotlin/net/corda/core/UtilsTest.kt index 7988d7eadc..d785102d07 100644 --- a/core/src/test/kotlin/net/corda/core/UtilsTest.kt +++ b/core/src/test/kotlin/net/corda/core/UtilsTest.kt @@ -1,10 +1,18 @@ package net.corda.core +import com.google.common.util.concurrent.MoreExecutors +import com.nhaarman.mockito_kotlin.mock +import com.nhaarman.mockito_kotlin.same +import com.nhaarman.mockito_kotlin.verify import org.assertj.core.api.Assertions.* import org.junit.Test +import org.mockito.ArgumentMatchers.anyString +import org.slf4j.Logger import rx.subjects.PublishSubject import java.util.* import java.util.concurrent.CancellationException +import java.util.concurrent.Executors +import java.util.concurrent.TimeUnit class UtilsTest { @Test @@ -57,4 +65,17 @@ class UtilsTest { future.get() } } -} \ No newline at end of file + + @Test + fun `andForget works`() { + val log = mock() + val throwable = Exception("Boom") + val executor = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor()) + executor.submit { throw throwable }.andForget(log) + executor.shutdown() + while (!executor.awaitTermination(1, TimeUnit.SECONDS)) { + // Do nothing. + } + verify(log).error(anyString(), same(throwable)) + } +} diff --git a/node/src/main/kotlin/net/corda/node/driver/Driver.kt b/node/src/main/kotlin/net/corda/node/driver/Driver.kt index 237ee6e7e6..954d5b8590 100644 --- a/node/src/main/kotlin/net/corda/node/driver/Driver.kt +++ b/node/src/main/kotlin/net/corda/node/driver/Driver.kt @@ -261,7 +261,11 @@ class ListenProcessDeathException(message: String) : Exception(message) /** * @throws ListenProcessDeathException if [listenProcess] dies before the check succeeds, i.e. the check can't succeed as intended. */ -fun addressMustBeBound(executorService: ScheduledExecutorService, hostAndPort: HostAndPort, listenProcess: Process): ListenableFuture { +fun addressMustBeBound(executorService: ScheduledExecutorService, hostAndPort: HostAndPort, listenProcess: Process) { + addressMustBeBoundFuture(executorService, hostAndPort, listenProcess).getOrThrow() +} + +fun addressMustBeBoundFuture(executorService: ScheduledExecutorService, hostAndPort: HostAndPort, listenProcess: Process): ListenableFuture { return poll(executorService, "address $hostAndPort to bind") { if (!listenProcess.isAlive) { throw ListenProcessDeathException("The process that was expected to listen on $hostAndPort has died with status: ${listenProcess.exitValue()}") @@ -275,7 +279,11 @@ fun addressMustBeBound(executorService: ScheduledExecutorService, hostAndPort: H } } -fun addressMustNotBeBound(executorService: ScheduledExecutorService, hostAndPort: HostAndPort): ListenableFuture { +fun addressMustNotBeBound(executorService: ScheduledExecutorService, hostAndPort: HostAndPort) { + addressMustNotBeBoundFuture(executorService, hostAndPort).getOrThrow() +} + +fun addressMustNotBeBoundFuture(executorService: ScheduledExecutorService, hostAndPort: HostAndPort): ListenableFuture { return poll(executorService, "address $hostAndPort to unbind") { try { Socket(hostAndPort.host, hostAndPort.port).close() @@ -608,7 +616,7 @@ class DriverDSL( ) _shutdownManager = ShutdownManager(executorService) if (networkMapStartStrategy.startDedicated) { - startDedicatedNetworkMapService() + startDedicatedNetworkMapService().andForget(log) // Allow it to start concurrently with other nodes. } } @@ -634,7 +642,7 @@ class DriverDSL( log.info("Starting network-map-service") val startNode = startNode(executorService, config.parseAs(), config, quasarJarPath, debugPort, systemProperties) registerProcess(startNode) - return startNode.flatMap { addressMustBeBound(executorService, dedicatedNetworkMapAddress, it) } + return startNode.flatMap { addressMustBeBoundFuture(executorService, dedicatedNetworkMapAddress, it) } } override fun pollUntilNonNull(pollName: String, pollInterval: Duration, warnCount: Int, check: () -> A?): ListenableFuture { @@ -693,7 +701,7 @@ class DriverDSL( errorLogPath = nodeConf.baseDirectory / LOGS_DIRECTORY_NAME / "error.log", workingDirectory = nodeConf.baseDirectory ) - }.flatMap { process -> addressMustBeBound(executorService, nodeConf.p2pAddress, process).map { process } } + }.flatMap { process -> addressMustBeBoundFuture(executorService, nodeConf.p2pAddress, process).map { process } } } private fun startWebserver( @@ -713,7 +721,7 @@ class DriverDSL( ), errorLogPath = Paths.get("error.$className.log") ) - }.flatMap { process -> addressMustBeBound(executorService, handle.webAddress, process).map { process } } + }.flatMap { process -> addressMustBeBoundFuture(executorService, handle.webAddress, process).map { process } } } } } diff --git a/test-utils/src/main/kotlin/net/corda/testing/RPCDriver.kt b/test-utils/src/main/kotlin/net/corda/testing/RPCDriver.kt index 5bc7af456e..bbba3de89b 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/RPCDriver.kt +++ b/test-utils/src/main/kotlin/net/corda/testing/RPCDriver.kt @@ -419,7 +419,7 @@ data class RPCDriverDSL( server.start() driverDSL.shutdownManager.registerShutdown { server.stop() - addressMustNotBeBound(driverDSL.executorService, hostAndPort).get() + addressMustNotBeBound(driverDSL.executorService, hostAndPort) } RpcBrokerHandle( hostAndPort = hostAndPort, diff --git a/test-utils/src/main/kotlin/net/corda/testing/node/NodeBasedTest.kt b/test-utils/src/main/kotlin/net/corda/testing/node/NodeBasedTest.kt index 47afafc3dc..39da9a3a81 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/node/NodeBasedTest.kt +++ b/test-utils/src/main/kotlin/net/corda/testing/node/NodeBasedTest.kt @@ -11,7 +11,7 @@ import net.corda.core.node.services.ServiceType import net.corda.core.utilities.DUMMY_CA import net.corda.core.utilities.DUMMY_MAP import net.corda.core.utilities.WHITESPACE -import net.corda.node.driver.addressMustNotBeBound +import net.corda.node.driver.addressMustNotBeBoundFuture import net.corda.node.internal.Node import net.corda.node.services.config.ConfigHelper import net.corda.node.services.config.FullNodeConfiguration @@ -62,8 +62,8 @@ abstract class NodeBasedTest { // Wait until ports are released val portNotBoundChecks = nodes.flatMap { listOf( - it.configuration.p2pAddress.let { addressMustNotBeBound(shutdownExecutor, it) }, - it.configuration.rpcAddress?.let { addressMustNotBeBound(shutdownExecutor, it) } + it.configuration.p2pAddress.let { addressMustNotBeBoundFuture(shutdownExecutor, it) }, + it.configuration.rpcAddress?.let { addressMustNotBeBoundFuture(shutdownExecutor, it) } ) }.filterNotNull() nodes.clear() From d3f027cea8999cadea925c574a64a293e9b17d28 Mon Sep 17 00:00:00 2001 From: Rick Parker Date: Wed, 31 May 2017 18:33:57 +0100 Subject: [PATCH 025/126] Custom serialiser support for AMQP (#741) --- core/build.gradle | 2 +- .../net/corda/core/flows/FlowException.kt | 11 +- .../amqp/AMQPPrimitiveSerializer.kt | 4 +- .../core/serialization/amqp/AMQPSerializer.kt | 4 +- .../serialization/amqp/ArraySerializer.kt | 16 +-- .../amqp/CollectionSerializer.kt | 33 +++-- .../serialization/amqp/CustomSerializer.kt | 105 +++++++++++++++ .../amqp/DeserializationInput.kt | 17 +-- .../amqp/DeserializedParameterizedType.kt | 2 +- .../core/serialization/amqp/MapSerializer.kt | 23 ++-- .../serialization/amqp/ObjectSerializer.kt | 24 ++-- .../serialization/amqp/PropertySerializer.kt | 24 +++- .../corda/core/serialization/amqp/Schema.kt | 28 ++-- .../serialization/amqp/SerializationHelper.kt | 29 ++-- .../serialization/amqp/SerializationOutput.kt | 12 +- .../serialization/amqp/SerializerFactory.kt | 101 ++++++++++---- .../amqp/custom/PublicKeySerializer.kt | 24 ++++ .../amqp/custom/ThrowableSerializer.kt | 81 ++++++++++++ .../corda/core/utilities/CordaException.kt | 103 +++++++++++++++ .../amqp/SerializationOutputTests.kt | 125 +++++++++++++++++- .../kotlin/net/corda/nodeapi/RPCStructures.kt | 4 +- node/build.gradle | 5 +- 22 files changed, 647 insertions(+), 130 deletions(-) create mode 100644 core/src/main/kotlin/net/corda/core/serialization/amqp/CustomSerializer.kt create mode 100644 core/src/main/kotlin/net/corda/core/serialization/amqp/custom/PublicKeySerializer.kt create mode 100644 core/src/main/kotlin/net/corda/core/serialization/amqp/custom/ThrowableSerializer.kt create mode 100644 core/src/main/kotlin/net/corda/core/utilities/CordaException.kt diff --git a/core/build.gradle b/core/build.gradle index f0029a6672..131f8acf86 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -76,7 +76,7 @@ dependencies { compile "io.requery:requery-kotlin:$requery_version" // For AMQP serialisation. - compile "org.apache.qpid:proton-j:0.18.0" + compile "org.apache.qpid:proton-j:0.19.0" } configurations { diff --git a/core/src/main/kotlin/net/corda/core/flows/FlowException.kt b/core/src/main/kotlin/net/corda/core/flows/FlowException.kt index d1114d0946..92a8998288 100644 --- a/core/src/main/kotlin/net/corda/core/flows/FlowException.kt +++ b/core/src/main/kotlin/net/corda/core/flows/FlowException.kt @@ -1,6 +1,7 @@ package net.corda.core.flows -import net.corda.core.serialization.CordaSerializable +import net.corda.core.utilities.CordaException +import net.corda.core.utilities.CordaRuntimeException /** * Exception which can be thrown by a [FlowLogic] at any point in its logic to unexpectedly bring it to a permanent end. @@ -11,8 +12,7 @@ import net.corda.core.serialization.CordaSerializable * [FlowException] (or a subclass) can be a valid expected response from a flow, particularly ones which act as a service. * It is recommended a [FlowLogic] document the [FlowException] types it can throw. */ -@CordaSerializable -open class FlowException(override val message: String?, override val cause: Throwable?) : Exception() { +open class FlowException(message: String?, cause: Throwable?) : CordaException(message, cause) { constructor(message: String?) : this(message, null) constructor(cause: Throwable?) : this(cause?.toString(), cause) constructor() : this(null, null) @@ -23,5 +23,6 @@ open class FlowException(override val message: String?, override val cause: Thro * that we were not expecting), or the other side had an internal error, or the other side terminated when we * were waiting for a response. */ -@CordaSerializable -class FlowSessionException(message: String) : RuntimeException(message) +class FlowSessionException(message: String?, cause: Throwable?) : CordaRuntimeException(message, cause) { + constructor(msg: String) : this(msg, null) +} \ No newline at end of file diff --git a/core/src/main/kotlin/net/corda/core/serialization/amqp/AMQPPrimitiveSerializer.kt b/core/src/main/kotlin/net/corda/core/serialization/amqp/AMQPPrimitiveSerializer.kt index 2935b19cb9..40f586a88e 100644 --- a/core/src/main/kotlin/net/corda/core/serialization/amqp/AMQPPrimitiveSerializer.kt +++ b/core/src/main/kotlin/net/corda/core/serialization/amqp/AMQPPrimitiveSerializer.kt @@ -7,7 +7,7 @@ import java.lang.reflect.Type /** * Serializer / deserializer for native AMQP types (Int, Float, String etc). */ -class AMQPPrimitiveSerializer(clazz: Class<*>) : AMQPSerializer { +class AMQPPrimitiveSerializer(clazz: Class<*>) : AMQPSerializer { override val typeDescriptor: String = SerializerFactory.primitiveTypeName(Primitives.wrap(clazz))!! override val type: Type = clazz @@ -19,5 +19,5 @@ class AMQPPrimitiveSerializer(clazz: Class<*>) : AMQPSerializer { data.putObject(obj) } - override fun readObject(obj: Any, envelope: Envelope, input: DeserializationInput): Any = obj + override fun readObject(obj: Any, schema: Schema, input: DeserializationInput): Any = obj } \ No newline at end of file diff --git a/core/src/main/kotlin/net/corda/core/serialization/amqp/AMQPSerializer.kt b/core/src/main/kotlin/net/corda/core/serialization/amqp/AMQPSerializer.kt index 20465bb9cb..b2917c39cd 100644 --- a/core/src/main/kotlin/net/corda/core/serialization/amqp/AMQPSerializer.kt +++ b/core/src/main/kotlin/net/corda/core/serialization/amqp/AMQPSerializer.kt @@ -6,7 +6,7 @@ import java.lang.reflect.Type /** * Implemented to serialize and deserialize different types of objects to/from AMQP. */ -interface AMQPSerializer { +interface AMQPSerializer { /** * The JVM type this can serialize and deserialize. */ @@ -34,5 +34,5 @@ interface AMQPSerializer { /** * Read the given object from the input. The envelope is provided in case the schema is required. */ - fun readObject(obj: Any, envelope: Envelope, input: DeserializationInput): Any + fun readObject(obj: Any, schema: Schema, input: DeserializationInput): T } \ No newline at end of file diff --git a/core/src/main/kotlin/net/corda/core/serialization/amqp/ArraySerializer.kt b/core/src/main/kotlin/net/corda/core/serialization/amqp/ArraySerializer.kt index 2b1c6f5c55..0cf705e16d 100644 --- a/core/src/main/kotlin/net/corda/core/serialization/amqp/ArraySerializer.kt +++ b/core/src/main/kotlin/net/corda/core/serialization/amqp/ArraySerializer.kt @@ -9,14 +9,12 @@ import java.lang.reflect.Type /** * Serialization / deserialization of arrays. */ -class ArraySerializer(override val type: Type) : AMQPSerializer { - private val typeName = type.typeName +class ArraySerializer(override val type: Type, factory: SerializerFactory) : AMQPSerializer { + override val typeDescriptor = "$DESCRIPTOR_DOMAIN:${fingerprintForType(type, factory)}" - override val typeDescriptor = "$DESCRIPTOR_DOMAIN:${fingerprintForType(type)}" + internal val elementType: Type = makeElementType() - private val elementType: Type = makeElementType() - - private val typeNotation: TypeNotation = RestrictedType(typeName, null, emptyList(), "list", Descriptor(typeDescriptor, null), emptyList()) + private val typeNotation: TypeNotation = RestrictedType(type.typeName, null, emptyList(), "list", Descriptor(typeDescriptor, null), emptyList()) private fun makeElementType(): Type { return (type as? Class<*>)?.componentType ?: (type as GenericArrayType).genericComponentType @@ -39,8 +37,10 @@ class ArraySerializer(override val type: Type) : AMQPSerializer { } } - override fun readObject(obj: Any, envelope: Envelope, input: DeserializationInput): Any { - return (obj as List<*>).map { input.readObjectOrNull(it, envelope, elementType) }.toArrayOfType(elementType) + override fun readObject(obj: Any, schema: Schema, input: DeserializationInput): Any { + if (obj is List<*>) { + return obj.map { input.readObjectOrNull(it, schema, elementType) }.toArrayOfType(elementType) + } else throw NotSerializableException("Expected a List but found $obj") } private fun List.toArrayOfType(type: Type): Any { diff --git a/core/src/main/kotlin/net/corda/core/serialization/amqp/CollectionSerializer.kt b/core/src/main/kotlin/net/corda/core/serialization/amqp/CollectionSerializer.kt index 3e2d74002c..0f4421de6c 100644 --- a/core/src/main/kotlin/net/corda/core/serialization/amqp/CollectionSerializer.kt +++ b/core/src/main/kotlin/net/corda/core/serialization/amqp/CollectionSerializer.kt @@ -12,28 +12,27 @@ import kotlin.collections.Set /** * Serialization / deserialization of predefined set of supported [Collection] types covering mostly [List]s and [Set]s. */ -class CollectionSerializer(val declaredType: ParameterizedType) : AMQPSerializer { +class CollectionSerializer(val declaredType: ParameterizedType, factory: SerializerFactory) : AMQPSerializer { override val type: Type = declaredType as? DeserializedParameterizedType ?: DeserializedParameterizedType.make(declaredType.toString()) - private val typeName = declaredType.toString() - override val typeDescriptor = "$DESCRIPTOR_DOMAIN:${fingerprintForType(type)}" + override val typeDescriptor = "$DESCRIPTOR_DOMAIN:${fingerprintForType(type, factory)}" companion object { - private val supportedTypes: Map>, (Collection<*>) -> Collection<*>> = mapOf( - Collection::class.java to { coll -> coll }, - List::class.java to { coll -> coll }, - Set::class.java to { coll -> Collections.unmodifiableSet(LinkedHashSet(coll)) }, - SortedSet::class.java to { coll -> Collections.unmodifiableSortedSet(TreeSet(coll)) }, - NavigableSet::class.java to { coll -> Collections.unmodifiableNavigableSet(TreeSet(coll)) } + private val supportedTypes: Map>, (List<*>) -> Collection<*>> = mapOf( + Collection::class.java to { list -> Collections.unmodifiableCollection(list) }, + List::class.java to { list -> Collections.unmodifiableList(list) }, + Set::class.java to { list -> Collections.unmodifiableSet(LinkedHashSet(list)) }, + SortedSet::class.java to { list -> Collections.unmodifiableSortedSet(TreeSet(list)) }, + NavigableSet::class.java to { list -> Collections.unmodifiableNavigableSet(TreeSet(list)) } ) + + private fun findConcreteType(clazz: Class<*>): (List<*>) -> Collection<*> { + return supportedTypes[clazz] ?: throw NotSerializableException("Unsupported collection type $clazz.") + } } - private val concreteBuilder: (Collection<*>) -> Collection<*> = findConcreteType(declaredType.rawType as Class<*>) + private val concreteBuilder: (List<*>) -> Collection<*> = findConcreteType(declaredType.rawType as Class<*>) - private fun findConcreteType(clazz: Class<*>): (Collection<*>) -> Collection<*> { - return supportedTypes[clazz] ?: throw NotSerializableException("Unsupported map type $clazz.") - } - - private val typeNotation: TypeNotation = RestrictedType(typeName, null, emptyList(), "list", Descriptor(typeDescriptor, null), emptyList()) + private val typeNotation: TypeNotation = RestrictedType(declaredType.toString(), null, emptyList(), "list", Descriptor(typeDescriptor, null), emptyList()) override fun writeClassInfo(output: SerializationOutput) { if (output.writeTypeNotations(typeNotation)) { @@ -52,8 +51,8 @@ class CollectionSerializer(val declaredType: ParameterizedType) : AMQPSerializer } } - override fun readObject(obj: Any, envelope: Envelope, input: DeserializationInput): Any { + override fun readObject(obj: Any, schema: Schema, input: DeserializationInput): Any { // TODO: Can we verify the entries in the list? - return concreteBuilder((obj as List<*>).map { input.readObjectOrNull(it, envelope, declaredType.actualTypeArguments[0]) }) + return concreteBuilder((obj as List<*>).map { input.readObjectOrNull(it, schema, declaredType.actualTypeArguments[0]) }) } } \ No newline at end of file diff --git a/core/src/main/kotlin/net/corda/core/serialization/amqp/CustomSerializer.kt b/core/src/main/kotlin/net/corda/core/serialization/amqp/CustomSerializer.kt new file mode 100644 index 0000000000..e88230de3d --- /dev/null +++ b/core/src/main/kotlin/net/corda/core/serialization/amqp/CustomSerializer.kt @@ -0,0 +1,105 @@ +package net.corda.core.serialization.amqp + +import org.apache.qpid.proton.codec.Data +import java.lang.reflect.Type + +/** + * Base class for serializers of core platform types that do not conform to the usual serialization rules and thus + * cannot be automatically serialized. + */ +abstract class CustomSerializer : AMQPSerializer { + /** + * This is a collection of custom serializers that this custom serializer depends on. e.g. for proxy objects + * that refer to arrays of types etc. + */ + abstract val additionalSerializers: Iterable> + + abstract fun isSerializerFor(clazz: Class<*>): Boolean + protected abstract val descriptor: Descriptor + /** + * This exists purely for documentation and cross-platform purposes. It is not used by our serialization / deserialization + * code path. + */ + abstract val schemaForDocumentation: Schema + + override fun writeObject(obj: Any, data: Data, type: Type, output: SerializationOutput) { + data.withDescribed(descriptor) { + @Suppress("UNCHECKED_CAST") + writeDescribedObject(obj as T, data, type, output) + } + } + + abstract fun writeDescribedObject(obj: T, data: Data, type: Type, output: SerializationOutput) + + /** + * Additional base features for a custom serializer that is a particular class. + */ + abstract class Is(protected val clazz: Class) : CustomSerializer() { + override fun isSerializerFor(clazz: Class<*>): Boolean = clazz == this.clazz + override val type: Type get() = clazz + override val typeDescriptor: String = "$DESCRIPTOR_DOMAIN:${clazz.name}" + override fun writeClassInfo(output: SerializationOutput) {} + override val descriptor: Descriptor = Descriptor(typeDescriptor) + } + + /** + * Additional base features for a custom serializer for all implementations of a particular interface or super class. + */ + abstract class Implements(protected val clazz: Class) : CustomSerializer() { + override fun isSerializerFor(clazz: Class<*>): Boolean = this.clazz.isAssignableFrom(clazz) + override val type: Type get() = clazz + override val typeDescriptor: String = "$DESCRIPTOR_DOMAIN:${clazz.name}" + override fun writeClassInfo(output: SerializationOutput) {} + override val descriptor: Descriptor = Descriptor(typeDescriptor) + } + + /** + * Addition base features over and above [Implements] or [Is] custom serializer for when the serialize form should be + * the serialized form of a proxy class, and the object can be re-created from that proxy on deserialization. + * + * The proxy class must use only types which are either native AMQP or other types for which there are pre-registered + * custom serializers. + */ + abstract class Proxy(protected val clazz: Class, + protected val proxyClass: Class

, + protected val factory: SerializerFactory, + val withInheritance: Boolean = true) : CustomSerializer() { + override fun isSerializerFor(clazz: Class<*>): Boolean = if (withInheritance) this.clazz.isAssignableFrom(clazz) else this.clazz == clazz + override val type: Type get() = clazz + override val typeDescriptor: String = "$DESCRIPTOR_DOMAIN:${clazz.name}" + override fun writeClassInfo(output: SerializationOutput) {} + override val descriptor: Descriptor = Descriptor(typeDescriptor) + + private val proxySerializer: ObjectSerializer by lazy { ObjectSerializer(proxyClass, factory) } + + override val schemaForDocumentation: Schema by lazy { + val typeNotations = mutableSetOf(CompositeType(type.typeName, null, emptyList(), descriptor, (proxySerializer.typeNotation as CompositeType).fields)) + for (additional in additionalSerializers) { + typeNotations.addAll(additional.schemaForDocumentation.types) + } + Schema(typeNotations.toList()) + } + + /** + * Implement these two methods. + */ + protected abstract fun toProxy(obj: T): P + + protected abstract fun fromProxy(proxy: P): T + + override fun writeDescribedObject(obj: T, data: Data, type: Type, output: SerializationOutput) { + val proxy = toProxy(obj) + data.withList { + for (property in proxySerializer.propertySerializers) { + property.writeProperty(proxy, this, output) + } + } + } + + override fun readObject(obj: Any, schema: Schema, input: DeserializationInput): T { + @Suppress("UNCHECKED_CAST") + val proxy = proxySerializer.readObject(obj, schema, input) as P + return fromProxy(proxy) + } + } +} diff --git a/core/src/main/kotlin/net/corda/core/serialization/amqp/DeserializationInput.kt b/core/src/main/kotlin/net/corda/core/serialization/amqp/DeserializationInput.kt index b47d75b8bc..ccbe1fac20 100644 --- a/core/src/main/kotlin/net/corda/core/serialization/amqp/DeserializationInput.kt +++ b/core/src/main/kotlin/net/corda/core/serialization/amqp/DeserializationInput.kt @@ -15,7 +15,7 @@ import java.util.* * @param serializerFactory This is the factory for [AMQPSerializer] instances and can be shared across multiple * instances and threads. */ -class DeserializationInput(private val serializerFactory: SerializerFactory = SerializerFactory()) { +class DeserializationInput(internal val serializerFactory: SerializerFactory = SerializerFactory()) { // TODO: we're not supporting object refs yet private val objectHistory: MutableList = ArrayList() @@ -41,7 +41,7 @@ class DeserializationInput(private val serializerFactory: SerializerFactory = Se } val envelope = Envelope.get(data) // Now pick out the obj and schema from the envelope. - return clazz.cast(readObjectOrNull(envelope.obj, envelope, clazz)) + return clazz.cast(readObjectOrNull(envelope.obj, envelope.schema, clazz)) } catch(nse: NotSerializableException) { throw nse } catch(t: Throwable) { @@ -51,20 +51,21 @@ class DeserializationInput(private val serializerFactory: SerializerFactory = Se } } - internal fun readObjectOrNull(obj: Any?, envelope: Envelope, type: Type): Any? { + internal fun readObjectOrNull(obj: Any?, schema: Schema, type: Type): Any? { if (obj == null) { return null } else { - return readObject(obj, envelope, type) + return readObject(obj, schema, type) } } - internal fun readObject(obj: Any, envelope: Envelope, type: Type): Any { + internal fun readObject(obj: Any, schema: Schema, type: Type): Any { if (obj is DescribedType) { // Look up serializer in factory by descriptor - val serializer = serializerFactory.get(obj.descriptor, envelope) - if (serializer.type != type && !serializer.type.isSubClassOf(type)) throw NotSerializableException("Described type with descriptor ${obj.descriptor} was expected to be of type $type") - return serializer.readObject(obj.described, envelope, this) + val serializer = serializerFactory.get(obj.descriptor, schema) + if (serializer.type != type && !serializer.type.isSubClassOf(type)) + throw NotSerializableException("Described type with descriptor ${obj.descriptor} was expected to be of type $type") + return serializer.readObject(obj.described, schema, this) } else { return obj } diff --git a/core/src/main/kotlin/net/corda/core/serialization/amqp/DeserializedParameterizedType.kt b/core/src/main/kotlin/net/corda/core/serialization/amqp/DeserializedParameterizedType.kt index 2cd0ae1298..9a0809d18d 100644 --- a/core/src/main/kotlin/net/corda/core/serialization/amqp/DeserializedParameterizedType.kt +++ b/core/src/main/kotlin/net/corda/core/serialization/amqp/DeserializedParameterizedType.kt @@ -119,7 +119,7 @@ class DeserializedParameterizedType(private val rawType: Class<*>, private val p private fun makeType(typeName: String, cl: ClassLoader): Type { // Not generic - return if (typeName == "*") SerializerFactory.AnyType else Class.forName(typeName, false, cl) + return if (typeName == "?") SerializerFactory.AnyType else Class.forName(typeName, false, cl) } private fun makeParameterizedType(rawTypeName: String, args: MutableList, cl: ClassLoader): Type { diff --git a/core/src/main/kotlin/net/corda/core/serialization/amqp/MapSerializer.kt b/core/src/main/kotlin/net/corda/core/serialization/amqp/MapSerializer.kt index 2ea61c6598..7991648f1a 100644 --- a/core/src/main/kotlin/net/corda/core/serialization/amqp/MapSerializer.kt +++ b/core/src/main/kotlin/net/corda/core/serialization/amqp/MapSerializer.kt @@ -13,10 +13,9 @@ import kotlin.collections.map /** * Serialization / deserialization of certain supported [Map] types. */ -class MapSerializer(val declaredType: ParameterizedType) : AMQPSerializer { +class MapSerializer(val declaredType: ParameterizedType, factory: SerializerFactory) : AMQPSerializer { override val type: Type = declaredType as? DeserializedParameterizedType ?: DeserializedParameterizedType.make(declaredType.toString()) - private val typeName = declaredType.toString() - override val typeDescriptor = "$DESCRIPTOR_DOMAIN:${fingerprintForType(type)}" + override val typeDescriptor = "$DESCRIPTOR_DOMAIN:${fingerprintForType(type, factory)}" companion object { private val supportedTypes: Map>, (Map<*, *>) -> Map<*, *>> = mapOf( @@ -24,15 +23,15 @@ class MapSerializer(val declaredType: ParameterizedType) : AMQPSerializer { SortedMap::class.java to { map -> Collections.unmodifiableSortedMap(TreeMap(map)) }, NavigableMap::class.java to { map -> Collections.unmodifiableNavigableMap(TreeMap(map)) } ) + + private fun findConcreteType(clazz: Class<*>): (Map<*, *>) -> Map<*, *> { + return supportedTypes[clazz] ?: throw NotSerializableException("Unsupported map type $clazz.") + } } private val concreteBuilder: (Map<*, *>) -> Map<*, *> = findConcreteType(declaredType.rawType as Class<*>) - private fun findConcreteType(clazz: Class<*>): (Map<*, *>) -> Map<*, *> { - return supportedTypes[clazz] ?: throw NotSerializableException("Unsupported map type $clazz.") - } - - private val typeNotation: TypeNotation = RestrictedType(typeName, null, emptyList(), "map", Descriptor(typeDescriptor, null), emptyList()) + private val typeNotation: TypeNotation = RestrictedType(declaredType.toString(), null, emptyList(), "map", Descriptor(typeDescriptor, null), emptyList()) override fun writeClassInfo(output: SerializationOutput) { if (output.writeTypeNotations(typeNotation)) { @@ -56,11 +55,13 @@ class MapSerializer(val declaredType: ParameterizedType) : AMQPSerializer { } } - override fun readObject(obj: Any, envelope: Envelope, input: DeserializationInput): Any { + override fun readObject(obj: Any, schema: Schema, input: DeserializationInput): Any { // TODO: General generics question. Do we need to validate that entries in Maps and Collections match the generic type? Is it a security hole? - val entries: Iterable> = (obj as Map<*, *>).map { readEntry(envelope, input, it) } + val entries: Iterable> = (obj as Map<*, *>).map { readEntry(schema, input, it) } return concreteBuilder(entries.toMap()) } - private fun readEntry(envelope: Envelope, input: DeserializationInput, entry: Map.Entry) = input.readObjectOrNull(entry.key, envelope, declaredType.actualTypeArguments[0]) to input.readObjectOrNull(entry.value, envelope, declaredType.actualTypeArguments[1]) + private fun readEntry(schema: Schema, input: DeserializationInput, entry: Map.Entry) = + input.readObjectOrNull(entry.key, schema, declaredType.actualTypeArguments[0]) to + input.readObjectOrNull(entry.value, schema, declaredType.actualTypeArguments[1]) } \ No newline at end of file diff --git a/core/src/main/kotlin/net/corda/core/serialization/amqp/ObjectSerializer.kt b/core/src/main/kotlin/net/corda/core/serialization/amqp/ObjectSerializer.kt index 2ccfad81d6..130d50d7a3 100644 --- a/core/src/main/kotlin/net/corda/core/serialization/amqp/ObjectSerializer.kt +++ b/core/src/main/kotlin/net/corda/core/serialization/amqp/ObjectSerializer.kt @@ -10,26 +10,30 @@ import kotlin.reflect.jvm.javaConstructor /** * Responsible for serializing and deserializing a regular object instance via a series of properties (matched with a constructor). */ -class ObjectSerializer(val clazz: Class<*>) : AMQPSerializer { +class ObjectSerializer(val clazz: Class<*>, factory: SerializerFactory) : AMQPSerializer { override val type: Type get() = clazz private val javaConstructor: Constructor? - private val propertySerializers: Collection + internal val propertySerializers: Collection init { val kotlinConstructor = constructorForDeserialization(clazz) javaConstructor = kotlinConstructor?.javaConstructor - propertySerializers = propertiesForSerialization(kotlinConstructor, clazz) + propertySerializers = propertiesForSerialization(kotlinConstructor, clazz, factory) } private val typeName = clazz.name - override val typeDescriptor = "$DESCRIPTOR_DOMAIN:${fingerprintForType(type)}" + override val typeDescriptor = "$DESCRIPTOR_DOMAIN:${fingerprintForType(type, factory)}" private val interfaces = interfacesForSerialization(clazz) // TODO maybe this proves too much and we need annotations to restrict. - private val typeNotation: TypeNotation = CompositeType(typeName, null, generateProvides(), Descriptor(typeDescriptor, null), generateFields()) + internal val typeNotation: TypeNotation = CompositeType(typeName, null, generateProvides(), Descriptor(typeDescriptor, null), generateFields()) override fun writeClassInfo(output: SerializationOutput) { - output.writeTypeNotations(typeNotation) - for (iface in interfaces) { - output.requireSerializer(iface) + if (output.writeTypeNotations(typeNotation)) { + for (iface in interfaces) { + output.requireSerializer(iface) + } + for (property in propertySerializers) { + property.writeClassInfo(output) + } } } @@ -45,13 +49,13 @@ class ObjectSerializer(val clazz: Class<*>) : AMQPSerializer { } } - override fun readObject(obj: Any, envelope: Envelope, input: DeserializationInput): Any { + override fun readObject(obj: Any, schema: Schema, input: DeserializationInput): Any { if (obj is UnsignedInteger) { // TODO: Object refs TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } else if (obj is List<*>) { if (obj.size > propertySerializers.size) throw NotSerializableException("Too many properties in described type $typeName") - val params = obj.zip(propertySerializers).map { it.second.readProperty(it.first, envelope, input) } + val params = obj.zip(propertySerializers).map { it.second.readProperty(it.first, schema, input) } return construct(params) } else throw NotSerializableException("Body of described type is unexpected $obj") } diff --git a/core/src/main/kotlin/net/corda/core/serialization/amqp/PropertySerializer.kt b/core/src/main/kotlin/net/corda/core/serialization/amqp/PropertySerializer.kt index 50cb6c5581..6e26441633 100644 --- a/core/src/main/kotlin/net/corda/core/serialization/amqp/PropertySerializer.kt +++ b/core/src/main/kotlin/net/corda/core/serialization/amqp/PropertySerializer.kt @@ -9,8 +9,9 @@ import kotlin.reflect.jvm.javaGetter * Base class for serialization of a property of an object. */ sealed class PropertySerializer(val name: String, val readMethod: Method) { + abstract fun writeClassInfo(output: SerializationOutput) abstract fun writeProperty(obj: Any?, data: Data, output: SerializationOutput) - abstract fun readProperty(obj: Any?, envelope: Envelope, input: DeserializationInput): Any? + abstract fun readProperty(obj: Any?, schema: Schema, input: DeserializationInput): Any? val type: String = generateType() val requires: List = generateRequires() @@ -53,13 +54,13 @@ sealed class PropertySerializer(val name: String, val readMethod: Method) { } companion object { - fun make(name: String, readMethod: Method): PropertySerializer { + fun make(name: String, readMethod: Method, factory: SerializerFactory): PropertySerializer { val type = readMethod.genericReturnType if (SerializerFactory.isPrimitive(type)) { // This is a little inefficient for performance since it does a runtime check of type. We could do build time check with lots of subclasses here. return AMQPPrimitivePropertySerializer(name, readMethod) } else { - return DescribedTypePropertySerializer(name, readMethod) + return DescribedTypePropertySerializer(name, readMethod) { factory.get(null, type) } } } } @@ -67,9 +68,16 @@ sealed class PropertySerializer(val name: String, val readMethod: Method) { /** * A property serializer for a complex type (another object). */ - class DescribedTypePropertySerializer(name: String, readMethod: Method) : PropertySerializer(name, readMethod) { - override fun readProperty(obj: Any?, envelope: Envelope, input: DeserializationInput): Any? { - return input.readObjectOrNull(obj, envelope, readMethod.genericReturnType) + class DescribedTypePropertySerializer(name: String, readMethod: Method, private val lazyTypeSerializer: () -> AMQPSerializer) : PropertySerializer(name, readMethod) { + // This is lazy so we don't get an infinite loop when a method returns an instance of the class. + private val typeSerializer: AMQPSerializer by lazy { lazyTypeSerializer() } + + override fun writeClassInfo(output: SerializationOutput) { + typeSerializer.writeClassInfo(output) + } + + override fun readProperty(obj: Any?, schema: Schema, input: DeserializationInput): Any? { + return input.readObjectOrNull(obj, schema, readMethod.genericReturnType) } override fun writeProperty(obj: Any?, data: Data, output: SerializationOutput) { @@ -81,7 +89,9 @@ sealed class PropertySerializer(val name: String, val readMethod: Method) { * A property serializer for an AMQP primitive type (Int, String, etc). */ class AMQPPrimitivePropertySerializer(name: String, readMethod: Method) : PropertySerializer(name, readMethod) { - override fun readProperty(obj: Any?, envelope: Envelope, input: DeserializationInput): Any? { + override fun writeClassInfo(output: SerializationOutput) {} + + override fun readProperty(obj: Any?, schema: Schema, input: DeserializationInput): Any? { return obj } diff --git a/core/src/main/kotlin/net/corda/core/serialization/amqp/Schema.kt b/core/src/main/kotlin/net/corda/core/serialization/amqp/Schema.kt index 64a28a7aae..5c627cc943 100644 --- a/core/src/main/kotlin/net/corda/core/serialization/amqp/Schema.kt +++ b/core/src/main/kotlin/net/corda/core/serialization/amqp/Schema.kt @@ -87,7 +87,7 @@ data class Schema(val types: List) : DescribedType { override fun toString(): String = types.joinToString("\n") } -data class Descriptor(val name: String?, val code: UnsignedLong?) : DescribedType { +data class Descriptor(val name: String?, val code: UnsignedLong? = null) : DescribedType { companion object : DescribedTypeConstructor { val DESCRIPTOR = UnsignedLong(3L or DESCRIPTOR_TOP_32BITS) @@ -320,9 +320,9 @@ private val ANY_TYPE_HASH: String = "Any type = true" * different. */ // TODO: write tests -internal fun fingerprintForType(type: Type): String = Base58.encode(fingerprintForType(type, HashSet(), Hashing.murmur3_128().newHasher()).hash().asBytes()) +internal fun fingerprintForType(type: Type, factory: SerializerFactory): String = Base58.encode(fingerprintForType(type, HashSet(), Hashing.murmur3_128().newHasher(), factory).hash().asBytes()) -private fun fingerprintForType(type: Type, alreadySeen: MutableSet, hasher: Hasher): Hasher { +private fun fingerprintForType(type: Type, alreadySeen: MutableSet, hasher: Hasher, factory: SerializerFactory): Hasher { return if (type in alreadySeen) { hasher.putUnencodedChars(ALREADY_SEEN_HASH) } else { @@ -331,25 +331,31 @@ private fun fingerprintForType(type: Type, alreadySeen: MutableSet, hasher hasher.putUnencodedChars(ANY_TYPE_HASH) } else if (type is Class<*>) { if (type.isArray) { - fingerprintForType(type.componentType, alreadySeen, hasher).putUnencodedChars(ARRAY_HASH) + fingerprintForType(type.componentType, alreadySeen, hasher, factory).putUnencodedChars(ARRAY_HASH) } else if (SerializerFactory.isPrimitive(type)) { hasher.putUnencodedChars(type.name) } else if (Collection::class.java.isAssignableFrom(type) || Map::class.java.isAssignableFrom(type)) { hasher.putUnencodedChars(type.name) } else { - // Hash the class + properties + interfaces - propertiesForSerialization(constructorForDeserialization(type), type).fold(hasher.putUnencodedChars(type.name)) { orig, param -> - fingerprintForType(param.readMethod.genericReturnType, alreadySeen, orig).putUnencodedChars(param.name).putUnencodedChars(if (param.mandatory) NOT_NULLABLE_HASH else NULLABLE_HASH) + // Need to check if a custom serializer is applicable + val customSerializer = factory.findCustomSerializer(type) + if (customSerializer == null) { + // Hash the class + properties + interfaces + propertiesForSerialization(constructorForDeserialization(type), type, factory).fold(hasher.putUnencodedChars(type.name)) { orig, param -> + fingerprintForType(param.readMethod.genericReturnType, alreadySeen, orig, factory).putUnencodedChars(param.name).putUnencodedChars(if (param.mandatory) NOT_NULLABLE_HASH else NULLABLE_HASH) + } + interfacesForSerialization(type).map { fingerprintForType(it, alreadySeen, hasher, factory) } + hasher + } else { + hasher.putUnencodedChars(customSerializer.typeDescriptor) } - interfacesForSerialization(type).map { fingerprintForType(it, alreadySeen, hasher) } - hasher } } else if (type is ParameterizedType) { // Hash the rawType + params - type.actualTypeArguments.fold(fingerprintForType(type.rawType, alreadySeen, hasher)) { orig, paramType -> fingerprintForType(paramType, alreadySeen, orig) } + type.actualTypeArguments.fold(fingerprintForType(type.rawType, alreadySeen, hasher, factory)) { orig, paramType -> fingerprintForType(paramType, alreadySeen, orig, factory) } } else if (type is GenericArrayType) { // Hash the element type + some array hash - fingerprintForType(type.genericComponentType, alreadySeen, hasher).putUnencodedChars(ARRAY_HASH) + fingerprintForType(type.genericComponentType, alreadySeen, hasher, factory).putUnencodedChars(ARRAY_HASH) } else { throw NotSerializableException("Don't know how to hash $type") } diff --git a/core/src/main/kotlin/net/corda/core/serialization/amqp/SerializationHelper.kt b/core/src/main/kotlin/net/corda/core/serialization/amqp/SerializationHelper.kt index 107769cde7..85082544a4 100644 --- a/core/src/main/kotlin/net/corda/core/serialization/amqp/SerializationHelper.kt +++ b/core/src/main/kotlin/net/corda/core/serialization/amqp/SerializationHelper.kt @@ -1,14 +1,16 @@ package net.corda.core.serialization.amqp +import com.google.common.reflect.TypeToken import org.apache.qpid.proton.codec.Data import java.beans.Introspector -import java.beans.PropertyDescriptor import java.io.NotSerializableException +import java.lang.reflect.Method import java.lang.reflect.Modifier import java.lang.reflect.ParameterizedType import java.lang.reflect.Type import kotlin.reflect.KClass import kotlin.reflect.KFunction +import kotlin.reflect.KParameter import kotlin.reflect.full.findAnnotation import kotlin.reflect.full.primaryConstructor import kotlin.reflect.jvm.javaType @@ -58,24 +60,26 @@ internal fun constructorForDeserialization(clazz: Class): KFunction * Note, you will need any Java classes to be compiled with the `-parameters` option to ensure constructor parameters have * names accessible via reflection. */ -internal fun propertiesForSerialization(kotlinConstructor: KFunction?, clazz: Class<*>): Collection { - return if (kotlinConstructor != null) propertiesForSerialization(kotlinConstructor) else propertiesForSerialization(clazz) +internal fun propertiesForSerialization(kotlinConstructor: KFunction?, clazz: Class<*>, factory: SerializerFactory): Collection { + return if (kotlinConstructor != null) propertiesForSerialization(kotlinConstructor, factory) else propertiesForSerialization(clazz, factory) } private fun isConcrete(clazz: Class<*>): Boolean = !(clazz.isInterface || Modifier.isAbstract(clazz.modifiers)) -private fun propertiesForSerialization(kotlinConstructor: KFunction): Collection { +private fun propertiesForSerialization(kotlinConstructor: KFunction, factory: SerializerFactory): Collection { val clazz = (kotlinConstructor.returnType.classifier as KClass<*>).javaObjectType // Kotlin reflection doesn't work with Java getters the way you might expect, so we drop back to good ol' beans. - val properties: Map = Introspector.getBeanInfo(clazz).propertyDescriptors.filter { it.name != "class" }.groupBy { it.name }.mapValues { it.value[0] } + val properties = Introspector.getBeanInfo(clazz).propertyDescriptors.filter { it.name != "class" }.groupBy { it.name }.mapValues { it.value[0] } val rc: MutableList = ArrayList(kotlinConstructor.parameters.size) for (param in kotlinConstructor.parameters) { val name = param.name ?: throw NotSerializableException("Constructor parameter of $clazz has no name.") - val matchingProperty = properties[name] ?: throw NotSerializableException("No property matching constructor parameter named $name of $clazz. If using Java, check that you have the -parameters option specified in the Java compiler.") + val matchingProperty = properties[name] ?: throw NotSerializableException("No property matching constructor parameter named $name of $clazz." + + " If using Java, check that you have the -parameters option specified in the Java compiler.") // Check that the method has a getter in java. - val getter = matchingProperty.readMethod ?: throw NotSerializableException("Property has no getter method for $name of $clazz. If using Java and the parameter name looks anonymous, check that you have the -parameters option specified in the Java compiler.") - if (getter.genericReturnType == param.type.javaType) { - rc += PropertySerializer.make(name, getter) + val getter = matchingProperty.readMethod ?: throw NotSerializableException("Property has no getter method for $name of $clazz." + + " If using Java and the parameter name looks anonymous, check that you have the -parameters option specified in the Java compiler.") + if (constructorParamTakesReturnTypeOfGetter(getter, param)) { + rc += PropertySerializer.make(name, getter, factory) } else { throw NotSerializableException("Property type ${getter.genericReturnType} for $name of $clazz differs from constructor parameter type ${param.type.javaType}") } @@ -83,14 +87,16 @@ private fun propertiesForSerialization(kotlinConstructor: KFunction return rc } -private fun propertiesForSerialization(clazz: Class<*>): Collection { +private fun constructorParamTakesReturnTypeOfGetter(getter: Method, param: KParameter): Boolean = TypeToken.of(param.type.javaType).isSupertypeOf(getter.genericReturnType) + +private fun propertiesForSerialization(clazz: Class<*>, factory: SerializerFactory): Collection { // Kotlin reflection doesn't work with Java getters the way you might expect, so we drop back to good ol' beans. val properties = Introspector.getBeanInfo(clazz).propertyDescriptors.filter { it.name != "class" }.sortedBy { it.name } val rc: MutableList = ArrayList(properties.size) for (property in properties) { // Check that the method has a getter in java. val getter = property.readMethod ?: throw NotSerializableException("Property has no getter method for ${property.name} of $clazz.") - rc += PropertySerializer.make(property.name, getter) + rc += PropertySerializer.make(property.name, getter, factory) } return rc } @@ -104,6 +110,7 @@ internal fun interfacesForSerialization(clazz: Class<*>): List { private fun exploreType(type: Type?, interfaces: MutableSet) { val clazz = (type as? Class<*>) ?: (type as? ParameterizedType)?.rawType as? Class<*> if (clazz != null) { + if (clazz.isInterface) interfaces += clazz for (newInterface in clazz.genericInterfaces) { if (newInterface !in interfaces) { interfaces += newInterface diff --git a/core/src/main/kotlin/net/corda/core/serialization/amqp/SerializationOutput.kt b/core/src/main/kotlin/net/corda/core/serialization/amqp/SerializationOutput.kt index f440d62c2a..3cbfad41ba 100644 --- a/core/src/main/kotlin/net/corda/core/serialization/amqp/SerializationOutput.kt +++ b/core/src/main/kotlin/net/corda/core/serialization/amqp/SerializationOutput.kt @@ -14,10 +14,10 @@ import kotlin.collections.LinkedHashSet * @param serializerFactory This is the factory for [AMQPSerializer] instances and can be shared across multiple * instances and threads. */ -class SerializationOutput(private val serializerFactory: SerializerFactory = SerializerFactory()) { +open class SerializationOutput(internal val serializerFactory: SerializerFactory = SerializerFactory()) { // TODO: we're not supporting object refs yet private val objectHistory: MutableMap = IdentityHashMap() - private val serializerHistory: MutableSet = LinkedHashSet() + private val serializerHistory: MutableSet> = LinkedHashSet() private val schemaHistory: MutableSet = LinkedHashSet() /** @@ -64,19 +64,21 @@ class SerializationOutput(private val serializerFactory: SerializerFactory = Ser internal fun writeObject(obj: Any, data: Data, type: Type) { val serializer = serializerFactory.get(obj.javaClass, type) if (serializer !in serializerHistory) { + serializerHistory.add(serializer) serializer.writeClassInfo(this) } serializer.writeObject(obj, data, type, this) } - internal fun writeTypeNotations(vararg typeNotation: TypeNotation): Boolean { + open internal fun writeTypeNotations(vararg typeNotation: TypeNotation): Boolean { return schemaHistory.addAll(typeNotation) } - internal fun requireSerializer(type: Type) { - if (type != SerializerFactory.AnyType) { + open internal fun requireSerializer(type: Type) { + if (type != SerializerFactory.AnyType && type != Object::class.java) { val serializer = serializerFactory.get(null, type) if (serializer !in serializerHistory) { + serializerHistory.add(serializer) serializer.writeClassInfo(this) } } diff --git a/core/src/main/kotlin/net/corda/core/serialization/amqp/SerializerFactory.kt b/core/src/main/kotlin/net/corda/core/serialization/amqp/SerializerFactory.kt index 1456c9a7ca..207f0979df 100644 --- a/core/src/main/kotlin/net/corda/core/serialization/amqp/SerializerFactory.kt +++ b/core/src/main/kotlin/net/corda/core/serialization/amqp/SerializerFactory.kt @@ -10,18 +10,19 @@ import java.io.NotSerializableException import java.lang.reflect.GenericArrayType import java.lang.reflect.ParameterizedType import java.lang.reflect.Type +import java.lang.reflect.WildcardType import java.util.* import java.util.concurrent.ConcurrentHashMap +import java.util.concurrent.CopyOnWriteArrayList import javax.annotation.concurrent.ThreadSafe /** * Factory of serializers designed to be shared across threads and invocations. */ +// TODO: enums // TODO: object references // TODO: class references? (e.g. cheat with repeated descriptors using a long encoding, like object ref proposal) // TODO: Inner classes etc -// TODO: support for custom serialisation of core types (of e.g. PublicKey, Throwables) -// TODO: exclude schemas for core types that don't need custom serializers that everyone already knows the schema for. // TODO: support for intern-ing of deserialized objects for some core types (e.g. PublicKey) for memory efficiency // TODO: maybe support for caching of serialized form of some core types for performance // TODO: profile for performance in general @@ -30,10 +31,13 @@ import javax.annotation.concurrent.ThreadSafe // TODO: incorporate the class carpenter for classes not on the classpath. // TODO: apply class loader logic and an "app context" throughout this code. // TODO: schema evolution solution when the fingerprints do not line up. +// TODO: allow definition of well known types that are left out of the schema. +// TODO: automatically support byte[] without having to wrap in [Binary]. @ThreadSafe class SerializerFactory(val whitelist: ClassWhitelist = AllWhitelist) { - private val serializersByType = ConcurrentHashMap() - private val serializersByDescriptor = ConcurrentHashMap() + private val serializersByType = ConcurrentHashMap>() + private val serializersByDescriptor = ConcurrentHashMap>() + private val customSerializers = CopyOnWriteArrayList>() /** * Look up, and manufacture if necessary, a serializer for the given type. @@ -42,7 +46,7 @@ class SerializerFactory(val whitelist: ClassWhitelist = AllWhitelist) { * restricted type processing). */ @Throws(NotSerializableException::class) - fun get(actualType: Class<*>?, declaredType: Type): AMQPSerializer { + fun get(actualType: Class<*>?, declaredType: Type): AMQPSerializer { if (declaredType is ParameterizedType) { return serializersByType.computeIfAbsent(declaredType) { // We allow only Collection and Map. @@ -50,7 +54,7 @@ class SerializerFactory(val whitelist: ClassWhitelist = AllWhitelist) { if (rawType is Class<*>) { checkParameterisedTypesConcrete(declaredType.actualTypeArguments) if (Collection::class.java.isAssignableFrom(rawType)) { - CollectionSerializer(declaredType) + CollectionSerializer(declaredType, this) } else if (Map::class.java.isAssignableFrom(rawType)) { makeMapSerializer(declaredType) } else { @@ -63,27 +67,44 @@ class SerializerFactory(val whitelist: ClassWhitelist = AllWhitelist) { } else if (declaredType is Class<*>) { // Simple classes allowed if (Collection::class.java.isAssignableFrom(declaredType)) { - return serializersByType.computeIfAbsent(declaredType) { CollectionSerializer(DeserializedParameterizedType(declaredType, arrayOf(AnyType), null)) } + return serializersByType.computeIfAbsent(declaredType) { CollectionSerializer(DeserializedParameterizedType(declaredType, arrayOf(AnyType), null), this) } } else if (Map::class.java.isAssignableFrom(declaredType)) { return serializersByType.computeIfAbsent(declaredType) { makeMapSerializer(DeserializedParameterizedType(declaredType, arrayOf(AnyType, AnyType), null)) } } else { return makeClassSerializer(actualType ?: declaredType) } } else if (declaredType is GenericArrayType) { - return serializersByType.computeIfAbsent(declaredType) { ArraySerializer(declaredType) } + return serializersByType.computeIfAbsent(declaredType) { ArraySerializer(declaredType, this) } } else { throw NotSerializableException("Declared types of $declaredType are not supported.") } } + /** + * Lookup and manufacture a serializer for the given AMQP type descriptor, assuming we also have the necessary types + * contained in the [Schema]. + */ @Throws(NotSerializableException::class) - fun get(typeDescriptor: Any, envelope: Envelope): AMQPSerializer { + fun get(typeDescriptor: Any, schema: Schema): AMQPSerializer { return serializersByDescriptor[typeDescriptor] ?: { - processSchema(envelope.schema) + processSchema(schema) serializersByDescriptor[typeDescriptor] ?: throw NotSerializableException("Could not find type matching descriptor $typeDescriptor.") }() } + /** + * TODO: Add docs + */ + fun register(customSerializer: CustomSerializer) { + if (!serializersByDescriptor.containsKey(customSerializer.typeDescriptor)) { + customSerializers += customSerializer + serializersByDescriptor[customSerializer.typeDescriptor] = customSerializer + for (additional in customSerializer.additionalSerializers) { + register(additional) + } + } + } + private fun processSchema(schema: Schema) { for (typeNotation in schema.types) { processSchemaEntry(typeNotation) @@ -99,7 +120,14 @@ class SerializerFactory(val whitelist: ClassWhitelist = AllWhitelist) { private fun restrictedTypeForName(name: String): Type { return if (name.endsWith("[]")) { - DeserializedGenericArrayType(restrictedTypeForName(name.substring(0, name.lastIndex - 1))) + val elementType = restrictedTypeForName(name.substring(0, name.lastIndex - 1)) + if (elementType is ParameterizedType || elementType is GenericArrayType) { + DeserializedGenericArrayType(elementType) + } else if (elementType is Class<*>) { + java.lang.reflect.Array.newInstance(elementType, 0).javaClass + } else { + throw NotSerializableException("Not able to deserialize array type: $name") + } } else { DeserializedParameterizedType.make(name) } @@ -134,32 +162,52 @@ class SerializerFactory(val whitelist: ClassWhitelist = AllWhitelist) { } } - private fun makeClassSerializer(clazz: Class<*>): AMQPSerializer { + private fun makeClassSerializer(clazz: Class<*>): AMQPSerializer { return serializersByType.computeIfAbsent(clazz) { - if (clazz.isArray) { - whitelisted(clazz.componentType) - ArraySerializer(clazz) - } else if (isPrimitive(clazz)) { + if (isPrimitive(clazz)) { AMQPPrimitiveSerializer(clazz) } else { - whitelisted(clazz) - ObjectSerializer(clazz) + findCustomSerializer(clazz) ?: { + if (clazz.isArray) { + whitelisted(clazz.componentType) + ArraySerializer(clazz, this) + } else { + whitelisted(clazz) + ObjectSerializer(clazz, this) + } + }() } } } + internal fun findCustomSerializer(clazz: Class<*>): AMQPSerializer? { + for (customSerializer in customSerializers) { + if (customSerializer.isSerializerFor(clazz)) { + return customSerializer + } + } + return null + } + private fun whitelisted(clazz: Class<*>): Boolean { - if (whitelist.hasListed(clazz) || clazz.isAnnotationPresent(CordaSerializable::class.java)) { + if (whitelist.hasListed(clazz) || hasAnnotationInHierarchy(clazz)) { return true } else { throw NotSerializableException("Class $clazz is not on the whitelist or annotated with @CordaSerializable.") } } - private fun makeMapSerializer(declaredType: ParameterizedType): AMQPSerializer { + // Recursively check the class, interfaces and superclasses for our annotation. + internal fun hasAnnotationInHierarchy(type: Class<*>): Boolean { + return type.isAnnotationPresent(CordaSerializable::class.java) || + type.interfaces.any { it.isAnnotationPresent(CordaSerializable::class.java) || hasAnnotationInHierarchy(it) } + || (type.superclass != null && hasAnnotationInHierarchy(type.superclass)) + } + + private fun makeMapSerializer(declaredType: ParameterizedType): AMQPSerializer { val rawType = declaredType.rawType as Class<*> rawType.checkNotUnorderedHashMap() - return MapSerializer(declaredType) + return MapSerializer(declaredType, this) } companion object { @@ -185,12 +233,17 @@ class SerializerFactory(val whitelist: ClassWhitelist = AllWhitelist) { Char::class.java to "char", Date::class.java to "timestamp", UUID::class.java to "uuid", - ByteArray::class.java to "binary", + Binary::class.java to "binary", String::class.java to "string", Symbol::class.java to "symbol") } - object AnyType : Type { - override fun toString(): String = "*" + object AnyType : WildcardType { + override fun getUpperBounds(): Array = arrayOf(Object::class.java) + + override fun getLowerBounds(): Array = emptyArray() + + override fun toString(): String = "?" } } + diff --git a/core/src/main/kotlin/net/corda/core/serialization/amqp/custom/PublicKeySerializer.kt b/core/src/main/kotlin/net/corda/core/serialization/amqp/custom/PublicKeySerializer.kt new file mode 100644 index 0000000000..46536a1bed --- /dev/null +++ b/core/src/main/kotlin/net/corda/core/serialization/amqp/custom/PublicKeySerializer.kt @@ -0,0 +1,24 @@ +package net.corda.core.serialization.amqp.custom + +import net.corda.core.crypto.Crypto +import net.corda.core.serialization.amqp.* +import org.apache.qpid.proton.amqp.Binary +import org.apache.qpid.proton.codec.Data +import java.lang.reflect.Type +import java.security.PublicKey + +class PublicKeySerializer : CustomSerializer.Implements(PublicKey::class.java) { + override val additionalSerializers: Iterable> = emptyList() + + override val schemaForDocumentation = Schema(listOf(RestrictedType(type.toString(), "", listOf(type.toString()), SerializerFactory.primitiveTypeName(Binary::class.java)!!, descriptor, emptyList()))) + + override fun writeDescribedObject(obj: PublicKey, data: Data, type: Type, output: SerializationOutput) { + // TODO: Instead of encoding to the default X509 format, we could have a custom per key type (space-efficient) serialiser. + output.writeObject(Binary(obj.encoded), data, clazz) + } + + override fun readObject(obj: Any, schema: Schema, input: DeserializationInput): PublicKey { + val A = input.readObject(obj, schema, ByteArray::class.java) as Binary + return Crypto.decodePublicKey(A.array) + } +} \ No newline at end of file diff --git a/core/src/main/kotlin/net/corda/core/serialization/amqp/custom/ThrowableSerializer.kt b/core/src/main/kotlin/net/corda/core/serialization/amqp/custom/ThrowableSerializer.kt new file mode 100644 index 0000000000..ed267ed44d --- /dev/null +++ b/core/src/main/kotlin/net/corda/core/serialization/amqp/custom/ThrowableSerializer.kt @@ -0,0 +1,81 @@ +package net.corda.core.serialization.amqp.custom + +import net.corda.core.serialization.amqp.CustomSerializer +import net.corda.core.serialization.amqp.SerializerFactory +import net.corda.core.serialization.amqp.constructorForDeserialization +import net.corda.core.serialization.amqp.propertiesForSerialization +import net.corda.core.utilities.CordaRuntimeException +import net.corda.core.utilities.CordaThrowable +import java.io.NotSerializableException + +class ThrowableSerializer(factory: SerializerFactory) : CustomSerializer.Proxy(Throwable::class.java, ThrowableProxy::class.java, factory) { + override val additionalSerializers: Iterable> = listOf(StackTraceElementSerializer(factory)) + + override fun toProxy(obj: Throwable): ThrowableProxy { + val extraProperties: MutableMap = LinkedHashMap() + val message = if (obj is CordaThrowable) { + // Try and find a constructor + try { + val constructor = constructorForDeserialization(obj.javaClass) + val props = propertiesForSerialization(constructor, obj.javaClass, factory) + for (prop in props) { + extraProperties[prop.name] = prop.readMethod.invoke(obj) + } + } catch(e: NotSerializableException) { + } + obj.originalMessage + } else { + obj.message + } + return ThrowableProxy(obj.javaClass.name, message, obj.stackTrace, obj.cause, obj.suppressed, extraProperties) + } + + override fun fromProxy(proxy: ThrowableProxy): Throwable { + try { + // TODO: This will need reworking when we have multiple class loaders + val clazz = Class.forName(proxy.exceptionClass, false, this.javaClass.classLoader) + // If it is CordaException or CordaRuntimeException, we can seek any constructor and then set the properties + // Otherwise we just make a CordaRuntimeException + if (CordaThrowable::class.java.isAssignableFrom(clazz) && Throwable::class.java.isAssignableFrom(clazz)) { + val constructor = constructorForDeserialization(clazz)!! + val throwable = constructor.callBy(constructor.parameters.map { it to proxy.additionalProperties[it.name] }.toMap()) + (throwable as CordaThrowable).apply { + if (this.javaClass.name != proxy.exceptionClass) this.originalExceptionClassName = proxy.exceptionClass + this.setMessage(proxy.message) + this.setCause(proxy.cause) + this.addSuppressed(proxy.suppressed) + } + return (throwable as Throwable).apply { + this.stackTrace = proxy.stackTrace + } + } + } catch (e: Exception) { + // If attempts to rebuild the exact exception fail, we fall through and build a runtime exception. + } + // If the criteria are not met or we experience an exception constructing the exception, we fall back to our own unchecked exception. + return CordaRuntimeException(proxy.exceptionClass).apply { + this.setMessage(proxy.message) + this.setCause(proxy.cause) + this.stackTrace = proxy.stackTrace + this.addSuppressed(proxy.suppressed) + } + } + + class ThrowableProxy( + val exceptionClass: String, + val message: String?, + val stackTrace: Array, + val cause: Throwable?, + val suppressed: Array, + val additionalProperties: Map) +} + +class StackTraceElementSerializer(factory: SerializerFactory) : CustomSerializer.Proxy(StackTraceElement::class.java, StackTraceElementProxy::class.java, factory) { + override val additionalSerializers: Iterable> = emptyList() + + override fun toProxy(obj: StackTraceElement): StackTraceElementProxy = StackTraceElementProxy(obj.className, obj.methodName, obj.fileName, obj.lineNumber) + + override fun fromProxy(proxy: StackTraceElementProxy): StackTraceElement = StackTraceElement(proxy.declaringClass, proxy.methodName, proxy.fileName, proxy.lineNumber) + + data class StackTraceElementProxy(val declaringClass: String, val methodName: String, val fileName: String?, val lineNumber: Int) +} \ No newline at end of file diff --git a/core/src/main/kotlin/net/corda/core/utilities/CordaException.kt b/core/src/main/kotlin/net/corda/core/utilities/CordaException.kt new file mode 100644 index 0000000000..907bbee408 --- /dev/null +++ b/core/src/main/kotlin/net/corda/core/utilities/CordaException.kt @@ -0,0 +1,103 @@ +package net.corda.core.utilities + +import net.corda.core.serialization.CordaSerializable +import java.util.* + +@CordaSerializable +interface CordaThrowable { + var originalExceptionClassName: String? + val originalMessage: String? + fun setMessage(message: String?) + fun setCause(cause: Throwable?) + fun addSuppressed(suppressed: Array) +} + +open class CordaException internal constructor(override var originalExceptionClassName: String? = null, + private var _message: String? = null, + private var _cause: Throwable? = null) : Exception(null, null, true, true), CordaThrowable { + + constructor(message: String?, + cause: Throwable?) : this(null, message, cause) + + override val message: String? + get() = if (originalExceptionClassName == null) originalMessage else { + if (originalMessage == null) "$originalExceptionClassName" else "$originalExceptionClassName: $originalMessage" + } + + override val cause: Throwable? + get() = _cause ?: super.cause + + override fun setMessage(message: String?) { + _message = message + } + + override fun setCause(cause: Throwable?) { + _cause = cause + } + + override fun addSuppressed(suppressed: Array) { + for (suppress in suppressed) { + addSuppressed(suppress) + } + } + + override val originalMessage: String? + get() = _message + + override fun hashCode(): Int { + return Arrays.deepHashCode(stackTrace) xor Objects.hash(originalExceptionClassName, originalMessage) + } + + override fun equals(other: Any?): Boolean { + return other is CordaException && + originalExceptionClassName == other.originalExceptionClassName && + message == other.message && + cause == other.cause && + Arrays.equals(stackTrace, other.stackTrace) && + Arrays.equals(suppressed, other.suppressed) + } +} + +open class CordaRuntimeException internal constructor(override var originalExceptionClassName: String?, + private var _message: String? = null, + private var _cause: Throwable? = null) : RuntimeException(null, null, true, true), CordaThrowable { + constructor(message: String?, cause: Throwable?) : this(null, message, cause) + + override val message: String? + get() = if (originalExceptionClassName == null) originalMessage else { + if (originalMessage == null) "$originalExceptionClassName" else "$originalExceptionClassName: $originalMessage" + } + + override val cause: Throwable? + get() = _cause ?: super.cause + + override fun setMessage(message: String?) { + _message = message + } + + override fun setCause(cause: Throwable?) { + _cause = cause + } + + override fun addSuppressed(suppressed: Array) { + for (suppress in suppressed) { + addSuppressed(suppress) + } + } + + override val originalMessage: String? + get() = _message + + override fun hashCode(): Int { + return Arrays.deepHashCode(stackTrace) xor Objects.hash(originalExceptionClassName, originalMessage) + } + + override fun equals(other: Any?): Boolean { + return other is CordaRuntimeException && + originalExceptionClassName == other.originalExceptionClassName && + message == other.message && + cause == other.cause && + Arrays.equals(stackTrace, other.stackTrace) && + Arrays.equals(suppressed, other.suppressed) + } +} \ No newline at end of file diff --git a/core/src/test/kotlin/net/corda/core/serialization/amqp/SerializationOutputTests.kt b/core/src/test/kotlin/net/corda/core/serialization/amqp/SerializationOutputTests.kt index d76708db57..5896a3c292 100644 --- a/core/src/test/kotlin/net/corda/core/serialization/amqp/SerializationOutputTests.kt +++ b/core/src/test/kotlin/net/corda/core/serialization/amqp/SerializationOutputTests.kt @@ -1,10 +1,14 @@ package net.corda.core.serialization.amqp +import net.corda.core.flows.FlowException import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.EmptyWhitelist +import net.corda.nodeapi.RPCException +import net.corda.testing.MEGA_CORP_PUBKEY import org.apache.qpid.proton.codec.DecoderImpl import org.apache.qpid.proton.codec.EncoderImpl import org.junit.Test +import java.io.IOException import java.io.NotSerializableException import java.nio.ByteBuffer import java.util.* @@ -74,7 +78,14 @@ class SerializationOutputTests { override fun hashCode(): Int = ginger } - private fun serdes(obj: Any, factory: SerializerFactory = SerializerFactory()): Any { + @CordaSerializable + interface AnnotatedInterface + + data class InheritAnnotation(val foo: String) : AnnotatedInterface + + data class PolymorphicProperty(val foo: FooInterface?) + + private fun serdes(obj: Any, factory: SerializerFactory = SerializerFactory(), freshDeserializationFactory: SerializerFactory = SerializerFactory(), expectedEqual: Boolean = true): Any { val ser = SerializationOutput(factory) val bytes = ser.serialize(obj) @@ -93,15 +104,16 @@ class SerializationOutputTests { val result = decoder.readObject() as Envelope assertNotNull(result) - val des = DeserializationInput() + val des = DeserializationInput(freshDeserializationFactory) val desObj = des.deserialize(bytes) - assertTrue(Objects.deepEquals(obj, desObj)) + assertTrue(Objects.deepEquals(obj, desObj) == expectedEqual) // Now repeat with a re-used factory val ser2 = SerializationOutput(factory) val des2 = DeserializationInput(factory) val desObj2 = des2.deserialize(ser2.serialize(obj)) - assertTrue(Objects.deepEquals(obj, desObj2)) + assertTrue(Objects.deepEquals(obj, desObj2) == expectedEqual) + assertTrue(Objects.deepEquals(desObj, desObj2)) // TODO: add some schema assertions to check correctly formed. return desObj2 @@ -230,4 +242,109 @@ class SerializationOutputTests { val obj = MismatchType(456) serdes(obj) } + + @Test + fun `test custom serializers on public key`() { + val factory = SerializerFactory() + factory.register(net.corda.core.serialization.amqp.custom.PublicKeySerializer()) + val factory2 = SerializerFactory() + factory2.register(net.corda.core.serialization.amqp.custom.PublicKeySerializer()) + val obj = MEGA_CORP_PUBKEY + serdes(obj, factory, factory2) + } + + @Test + fun `test annotation is inherited`() { + val obj = InheritAnnotation("blah") + serdes(obj, SerializerFactory(EmptyWhitelist)) + } + + @Test + fun `test throwables serialize`() { + val factory = SerializerFactory() + factory.register(net.corda.core.serialization.amqp.custom.ThrowableSerializer(factory)) + + val factory2 = SerializerFactory() + factory2.register(net.corda.core.serialization.amqp.custom.ThrowableSerializer(factory2)) + + val obj = IllegalAccessException("message").fillInStackTrace() + serdes(obj, factory, factory2, false) + } + + @Test + fun `test complex throwables serialize`() { + val factory = SerializerFactory() + factory.register(net.corda.core.serialization.amqp.custom.ThrowableSerializer(factory)) + + val factory2 = SerializerFactory() + factory2.register(net.corda.core.serialization.amqp.custom.ThrowableSerializer(factory2)) + + try { + try { + throw IOException("Layer 1") + } catch(t: Throwable) { + throw IllegalStateException("Layer 2", t) + } + } catch(t: Throwable) { + serdes(t, factory, factory2, false) + } + } + + @Test + fun `test suppressed throwables serialize`() { + val factory = SerializerFactory() + factory.register(net.corda.core.serialization.amqp.custom.ThrowableSerializer(factory)) + + val factory2 = SerializerFactory() + factory2.register(net.corda.core.serialization.amqp.custom.ThrowableSerializer(factory2)) + + try { + try { + throw IOException("Layer 1") + } catch(t: Throwable) { + val e = IllegalStateException("Layer 2") + e.addSuppressed(t) + throw e + } + } catch(t: Throwable) { + serdes(t, factory, factory2, false) + } + } + + @Test + fun `test flow corda exception subclasses serialize`() { + val factory = SerializerFactory() + factory.register(net.corda.core.serialization.amqp.custom.ThrowableSerializer(factory)) + + val factory2 = SerializerFactory() + factory2.register(net.corda.core.serialization.amqp.custom.ThrowableSerializer(factory2)) + + val obj = FlowException("message").fillInStackTrace() + serdes(obj, factory, factory2) + } + + @Test + fun `test RPC corda exception subclasses serialize`() { + val factory = SerializerFactory() + factory.register(net.corda.core.serialization.amqp.custom.ThrowableSerializer(factory)) + + val factory2 = SerializerFactory() + factory2.register(net.corda.core.serialization.amqp.custom.ThrowableSerializer(factory2)) + + val obj = RPCException("message").fillInStackTrace() + serdes(obj, factory, factory2) + } + + @Test + fun `test polymorphic property`() { + val obj = PolymorphicProperty(FooImplements("Ginger", 12)) + serdes(obj) + } + + @Test + fun `test null polymorphic property`() { + val obj = PolymorphicProperty(null) + serdes(obj) + } + } \ No newline at end of file diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/RPCStructures.kt b/node-api/src/main/kotlin/net/corda/nodeapi/RPCStructures.kt index 16be6048b5..e5f279c692 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/RPCStructures.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/RPCStructures.kt @@ -9,6 +9,7 @@ import net.corda.core.requireExternal import net.corda.core.serialization.* import net.corda.core.toFuture import net.corda.core.toObservable +import net.corda.core.utilities.CordaRuntimeException import net.corda.nodeapi.config.OldConfig import rx.Observable import java.io.InputStream @@ -35,8 +36,7 @@ annotation class RPCSinceVersion(val version: Int) * Thrown to indicate a fatal error in the RPC system itself, as opposed to an error generated by the invoked * method. */ -@CordaSerializable -open class RPCException(msg: String, cause: Throwable?) : RuntimeException(msg, cause) { +open class RPCException(message: String?, cause: Throwable?) : CordaRuntimeException(message, cause) { constructor(msg: String) : this(msg, null) } diff --git a/node/build.gradle b/node/build.gradle index 5676649bce..1de49eee07 100644 --- a/node/build.gradle +++ b/node/build.gradle @@ -83,7 +83,10 @@ dependencies { // Artemis: for reliable p2p message queues. compile "org.apache.activemq:artemis-server:${artemis_version}" compile "org.apache.activemq:artemis-core-client:${artemis_version}" - runtime "org.apache.activemq:artemis-amqp-protocol:${artemis_version}" + runtime ("org.apache.activemq:artemis-amqp-protocol:${artemis_version}") { + // Gains our proton-j version from core module. + exclude group: 'org.apache.qpid', module: 'proton-j' + } // JAnsi: for drawing things to the terminal in nicely coloured ways. compile "org.fusesource.jansi:jansi:$jansi_version" From 53e8fe23d719259cc8e71836031ed625ea639705 Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Wed, 31 May 2017 21:05:41 +0100 Subject: [PATCH 026/126] Fix docs build by replacing an expression which crashes Dokka with an older more verbose notation. --- node/src/main/kotlin/net/corda/node/Corda.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/node/src/main/kotlin/net/corda/node/Corda.kt b/node/src/main/kotlin/net/corda/node/Corda.kt index f293552a3c..40991b33d0 100644 --- a/node/src/main/kotlin/net/corda/node/Corda.kt +++ b/node/src/main/kotlin/net/corda/node/Corda.kt @@ -104,7 +104,9 @@ fun main(args: Array) { println("Unable to load the configuration file: ${e.rootCause.message}") exitProcess(2) } - SerialFilter.install(if (conf.bftReplicaId != null) ::bftSMaRtSerialFilter else ::defaultSerialFilter) + // TODO: Replace with "::funcName" notation when Dokka is upgraded to not crash when analysing the notation + val filterFunc = if (conf.bftReplicaId != null) { it: Class<*> -> bftSMaRtSerialFilter(it) } else { it: Class<*> -> defaultSerialFilter(it) } + SerialFilter.install(filterFunc) if (cmdlineOptions.isRegistration) { println() println("******************************************************************") From f646936ab8beef1a6af64ea7a7ddf8dda5adde8d Mon Sep 17 00:00:00 2001 From: Joel Dudley Date: Thu, 1 Jun 2017 11:08:39 +0100 Subject: [PATCH 027/126] Updates TwoPartyTradeFlow to use the CollectSignaturesFlow. --- .../net/corda/flows/CollectSignaturesFlow.kt | 1 - docs/source/flow-state-machines.rst | 382 +++++++++--------- .../net/corda/flows/TwoPartyTradeFlow.kt | 94 ++--- .../node/messaging/TwoPartyTradeFlowTests.kt | 4 +- 4 files changed, 236 insertions(+), 245 deletions(-) diff --git a/core/src/main/kotlin/net/corda/flows/CollectSignaturesFlow.kt b/core/src/main/kotlin/net/corda/flows/CollectSignaturesFlow.kt index 64280d1c8c..8258f68f49 100644 --- a/core/src/main/kotlin/net/corda/flows/CollectSignaturesFlow.kt +++ b/core/src/main/kotlin/net/corda/flows/CollectSignaturesFlow.kt @@ -61,7 +61,6 @@ import java.security.PublicKey * @param partiallySignedTx Transaction to collect the remaining signatures for */ // TODO: AbstractStateReplacementFlow needs updating to use this flow. -// TODO: TwoPartyTradeFlow needs updating to use this flow. // TODO: Update this flow to handle randomly generated keys when that works is complete. class CollectSignaturesFlow(val partiallySignedTx: SignedTransaction, override val progressTracker: ProgressTracker = tracker()): FlowLogic() { diff --git a/docs/source/flow-state-machines.rst b/docs/source/flow-state-machines.rst index fa75f50f8c..2e467cadba 100644 --- a/docs/source/flow-state-machines.rst +++ b/docs/source/flow-state-machines.rst @@ -89,9 +89,10 @@ Our flow has two parties (B and S for buyer and seller) and will proceed as foll 2. B sends to S a ``SignedTransaction`` that includes the state as input, B's cash as input, the state with the new owner key as output, and any change cash as output. It contains a single signature from B but isn't valid because it lacks a signature from S authorising movement of the asset. -3. S signs it and *finalises* the transaction. This means sending it to the notary, which checks the transaction for - validity, recording the transaction in the local vault, and then sending it back to B who also checks it and commits - the transaction to their local vault. +3. S signs the transaction and sends it back to B. +4. B *finalises* the transaction by sending it to the notary who checks the transaction for validity, + recording the transaction in B's local vault, and then sending it on to S who also checks it and commits + the transaction to S's local vault. You can find the implementation of this flow in the file ``finance/src/main/kotlin/net/corda/flows/TwoPartyTradeFlow.kt``. @@ -124,9 +125,6 @@ each side. val sellerOwnerKey: PublicKey ) - data class SignaturesFromSeller(val sellerSig: DigitalSignature.WithKey, - val notarySig: DigitalSignature.LegallyIdentifiable) - open class Seller(val otherParty: Party, val notaryNode: NodeInfo, val assetToSell: StateAndRef, @@ -156,8 +154,8 @@ simply flow messages or exceptions. The other two represent the buyer and seller Going through the data needed to become a seller, we have: - ``otherParty: Party`` - the party with which you are trading. -- ``notaryNode: NodeInfo`` - the entry in the network map for the chosen notary. See ":doc:`key-concepts-consensus-notaries`" for more - information on notaries. +- ``notaryNode: NodeInfo`` - the entry in the network map for the chosen notary. See + ":doc:`key-concepts-consensus-notaries`" for more information on notaries. - ``assetToSell: StateAndRef`` - a pointer to the ledger entry that represents the thing being sold. - ``price: Amount`` - the agreed on price that the asset is being sold for (without an issuer constraint). - ``myKey: PublicKey`` - the PublicKey part of the node's internal KeyPair that controls the asset being sold. @@ -243,87 +241,111 @@ Let's implement the ``Seller.call`` method. This will be run when the flow is in :end-before: DOCEND 4 :dedent: 4 -Here we see the outline of the procedure. We receive a proposed trade transaction from the buyer and check that it's -valid. The buyer has already attached their signature before sending it. Then we calculate and attach our own signature -so that the transaction is now signed by both the buyer and the seller. We then *finalise* this transaction by sending -it to a notary to assert (with another signature) that the timestamp in the transaction (if any) is valid and there are no -double spends. Finally, after the finalisation process is complete, we retrieve the now fully signed transaction from -local storage. It will have the same ID as the one we started with but more signatures. +We start by sending information about the asset we wish to sell to the buyer. We fill out the initial flow message with +the trade info, and then call ``send``. which takes two arguments: -Let's fill out the ``receiveAndCheckProposedTransaction()`` method. +- The party we wish to send the message to. +- The payload being sent. + +``send`` will serialise the payload and send it to the other party automatically. + +Next, we call a *subflow* called ``SignTransactionFlow`` (see :ref:`subflows`). ``SignTransactionFlow`` automates the +process of: + +* Receiving a proposed trade transaction from the buyer, with the buyer's signature attached. +* Checking that the proposed transaction is valid. +* Calculating and attaching our own signature so that the transaction is now signed by both the buyer and the seller. +* Sending the transaction back to the buyer. + +The transaction then needs to be finalized. This is the the process of sending the transaction to a notary to assert +(with another signature) that the timestamp in the transaction (if any) is valid and there are no double spends. +In this flow, finalization is handled by the buyer, so we just wait for the signed transaction to appear in our +transaction storage. It will have the same ID as the one we started with but more signatures. + +Implementing the buyer +---------------------- + +OK, let's do the same for the buyer side: .. container:: codeset .. literalinclude:: ../../finance/src/main/kotlin/net/corda/flows/TwoPartyTradeFlow.kt - :language: kotlin - :start-after: DOCSTART 5 - :end-before: DOCEND 5 - :dedent: 4 + :language: kotlin + :start-after: DOCSTART 1 + :end-before: DOCEND 1 + :dedent: 4 -Let's break this down. We fill out the initial flow message with the trade info, and then call ``sendAndReceive``. -This function takes a few arguments: +This code is longer but no more complicated. Here are some things to pay attention to: -- The party on the other side. -- The thing to send. It'll be serialised and sent automatically. -- Finally a type argument, which is the kind of object we're expecting to receive from the other side. If we get - back something else an exception is thrown. +1. We do some sanity checking on the proposed trade transaction received from the seller to ensure we're being offered + what we expected to be offered. +2. We create a cash spend using ``VaultService.generateSpend``. You can read the vault documentation to learn more about this. +3. We access the *service hub* as needed to access things that are transient and may change or be recreated + whilst a flow is suspended, such as the wallet or the network map. +4. We call ``CollectSignaturesFlow`` as a subflow to send the unfinished, still-invalid transaction to the seller so + they can sign it and send it back to us. +5. Last, we call ``FinalityFlow`` as a subflow to finalize the transaction. -Once ``sendAndReceive`` is called, the call method will be suspended into a continuation and saved to persistent -storage. If the node crashes or is restarted, the flow will effectively continue as if nothing had happened. Your -code may remain blocked inside such a call for seconds, minutes, hours or even days in the case of a flow that -needs human interaction! +As you can see, the flow logic is straightforward and does not contain any callbacks or network glue code, despite +the fact that it takes minimal resources and can survive node restarts. -.. note:: There are a couple of rules you need to bear in mind when writing a class that will be used as a continuation. - The first is that anything on the stack when the function is suspended will be stored into the heap and kept alive by - the garbage collector. So try to avoid keeping enormous data structures alive unless you really have to. You can - always use private methods to keep the stack uncluttered with temporary variables, or to avoid objects that - Kryo is not able to serialise correctly. +Flow sessions +------------- - The second is that as well as being kept on the heap, objects reachable from the stack will be serialised. The state - of the function call may be resurrected much later! Kryo doesn't require objects be marked as serialisable, but even so, - doing things like creating threads from inside these calls would be a bad idea. They should only contain business - logic and only do I/O via the methods exposed by the flow framework. +It will be useful to describe how flows communicate with each other. A node may have many flows running at the same +time, and perhaps communicating with the same counterparty node but for different purposes. Therefore flows need a +way to segregate communication channels so that concurrent conversations between flows on the same set of nodes do +not interfere with each other. - It's OK to keep references around to many large internal node services though: these will be serialised using a - special token that's recognised by the platform, and wired up to the right instance when the continuation is - loaded off disk again. +To achieve this the flow framework initiates a new flow session each time a flow starts communicating with a ``Party`` +for the first time. A session is simply a pair of IDs, one for each side, to allow the node to route received messages to +the correct flow. If the other side accepts the session request then subsequent sends and receives to that same ``Party`` +will use the same session. A session ends when either flow ends, whether as expected or pre-maturely. If a flow ends +pre-maturely then the other side will be notified of that and they will also end, as the whole point of flows is a known +sequence of message transfers. Flows end pre-maturely due to exceptions, and as described above, if that exception is +``FlowException`` or a sub-type then it will propagate to the other side. Any other exception will not propagate. -The buyer is supposed to send us a transaction with all the right inputs/outputs/commands in response to the opening -message, with their cash put into the transaction and their signature on it authorising the movement of the cash. +Taking a step back, we mentioned that the other side has to accept the session request for there to be a communication +channel. A node accepts a session request if it has registered the flow type (the fully-qualified class name) that is +making the request - each session initiation includes the initiating flow type. The registration is done by a CorDapp +which has made available the particular flow communication, using ``PluginServiceHub.registerServiceFlow``. This method +specifies a flow factory for generating the counter-flow to any given initiating flow. If this registration doesn't exist +then no further communication takes place and the initiating flow ends with an exception. -You get back a simple wrapper class, ``UntrustworthyData``, which is just a marker class that reminds -us that the data came from a potentially malicious external source and may have been tampered with or be unexpected in -other ways. It doesn't add any functionality, but acts as a reminder to "scrub" the data before use. +Going back to our buyer and seller flows, we need a way to initiate communication between the two. This is typically done +with one side started manually using the ``startFlowDynamic`` RPC and this initiates the counter-flow on the other side. +In this case it doesn't matter which flow is the initiator and which is the initiated. If we choose the seller side as +the initiator then the buyer side would need to register their flow, perhaps with something like: -Our "scrubbing" has three parts: +.. container:: codeset -1. Check that the expected signatures are present and correct. At this point we expect our own signature to be missing, - because of course we didn't sign it yet, and also the signature of the notary because that must always come last. -2. We resolve the transaction, which we will cover below. -3. We verify that the transaction is paying us the demanded price. + .. sourcecode:: kotlin -Exception handling ------------------- + class TwoPartyTradeFlowPlugin : CordaPluginRegistry() { + override val servicePlugins = listOf(Function(TwoPartyTradeFlowService::Service)) + } -Flows can throw exceptions to prematurely terminate their execution. The flow framework gives special treatment to -``FlowException`` and its subtypes. These exceptions are treated as error responses of the flow and are propagated -to all counterparties it is communicating with. The receiving flows will throw the same exception the next time they do -a ``receive`` or ``sendAndReceive`` and thus end the flow session. If the receiver was invoked via ``subFlow`` (details below) -then the exception can be caught there enabling re-invocation of the sub-flow. + object TwoPartyTradeFlowService { + class Service(services: PluginServiceHub) { + init { + services.registerServiceFlow(TwoPartyTradeFlow.Seller::class.java) { + TwoPartyTradeFlow.Buyer( + it, + notary = services.networkMapCache.notaryNodes[0].notaryIdentity, + acceptablePrice = TODO(), + typeToBuy = TODO()) + } + } + } + } -If the exception thrown by the erroring flow is not a ``FlowException`` it will still terminate but will not propagate to -the other counterparties. Instead they will be informed the flow has terminated and will themselves be terminated with a -generic exception. +This is telling the buyer node to fire up an instance of ``TwoPartyTradeFlow.Buyer`` (the code in the lambda) when +they receive a message from the initiating seller side of the flow (``TwoPartyTradeFlow.Seller::class.java``). -.. note:: A future version will extend this to give the node administrator more control on what to do with such erroring - flows. +.. _subflows: -Throwing a ``FlowException`` enables a flow to reject a piece of data it has received back to the sender. This is typically -done in the ``unwrap`` method of the received ``UntrustworthyData``. In the above example the seller checks the price -and throws ``FlowException`` if it's invalid. It's then up to the buyer to either try again with a better price or give up. - -Sub-flows and finalisation --------------------------- +Sub-flows +--------- Flows can be composed via nesting. Invoking a sub-flow looks similar to an ordinary function call: @@ -345,130 +367,124 @@ Flows can be composed via nesting. Invoking a sub-flow looks similar to an ordin subFlow(new FinalityFlow(unnotarisedTransaction)) } -In this code snippet we are using the ``FinalityFlow`` to finish off the transaction. It will: +Let's take a look at the three subflows we invoke in this flow. + +FinalityFlow +^^^^^^^^^^^^ +On the buyer side, we use ``FinalityFlow`` to finalise the transaction. It will: * Send the transaction to the chosen notary and, if necessary, satisfy the notary that the transaction is valid. * Record the transaction in the local vault, if it is relevant (i.e. involves the owner of the node). * Send the fully signed transaction to the other participants for recording as well. -We simply create the flow object via its constructor, and then pass it to the ``subFlow`` method which -returns the result of the flow's execution directly. Behind the scenes all this is doing is wiring up progress -tracking (discussed more below) and then running the objects ``call`` method. Because the sub-flow might suspend, -we must mark the method that invokes it as suspendable. - -Going back to the previous code snippet, we use a sub-flow called ``ResolveTransactionsFlow``. This is -responsible for downloading and checking all the dependencies of a transaction, which in Corda are always retrievable -from the party that sent you a transaction that uses them. This flow returns a list of ``LedgerTransaction`` -objects, but we don't need them here so we just ignore the return value. - -.. note:: Transaction dependency resolution assumes that the peer you got the transaction from has all of the - dependencies itself. It must do, otherwise it could not have convinced itself that the dependencies were themselves - valid. It's important to realise that requesting only the transactions we require is a privacy leak, because if - we don't download a transaction from the peer, they know we must have already seen it before. Fixing this privacy - leak will come later. - -After the dependencies, we check the proposed trading transaction for validity by running the contracts for that as -well (but having handled the fact that some signatures are missing ourselves). - .. warning:: If the seller stops before sending the finalised transaction to the buyer, the seller is left with a valid transaction but the buyer isn't, so they can't spend the asset they just purchased! This sort of thing is not always a risk (as the seller may not gain anything from that sort of behaviour except a lawsuit), but if it is, a future version of the platform will allow you to ask the notary to send you the transaction as well, in case your counterparty does not. This is not the default because it reveals more private info to the notary. -Implementing the buyer ----------------------- +We simply create the flow object via its constructor, and then pass it to the ``subFlow`` method which +returns the result of the flow's execution directly. Behind the scenes all this is doing is wiring up progress +tracking (discussed more below) and then running the object's ``call`` method. Because the sub-flow might suspend, +we must mark the method that invokes it as suspendable. -OK, let's do the same for the buyer side: +Within FinalityFlow, we use a further sub-flow called ``ResolveTransactionsFlow``. This is responsible for downloading +and checking all the dependencies of a transaction, which in Corda are always retrievable from the party that sent you a +transaction that uses them. This flow returns a list of ``LedgerTransaction`` objects. + +.. note:: Transaction dependency resolution assumes that the peer you got the transaction from has all of the + dependencies itself. It must do, otherwise it could not have convinced itself that the dependencies were themselves + valid. It's important to realise that requesting only the transactions we require is a privacy leak, because if + we don't download a transaction from the peer, they know we must have already seen it before. Fixing this privacy + leak will come later. + +CollectSignaturesFlow/SignTransactionFlow +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +We also invoke two other subflows: + +* ``CollectSignaturesFlow``, on the buyer side +* ``SignTransactionFlow``, on the seller side + +These flows communicate to gather all the required signatures for the proposed transaction. ``CollectSignaturesFlow`` +will: + +* Verify any signatures collected on the transaction so far +* Verify the transaction itself +* Send the transaction to the remaining required signers and receive back their signatures +* Verify the collected signatures + +``SignTransactionFlow`` responds by: + +* Receiving the partially-signed transaction off the wire +* Verifying the existing signatures +* Resolving the transaction's dependencies +* Verifying the transaction itself +* Running any custom validation logic +* Sending their signature back to the buyer +* Waiting for the transaction to be recorded in their vault + +We cannot instantiate ``SignTransactionFlow`` itself, as it's an abstract class. Instead, we need to subclass it and +override ``checkTransaction()`` to add our own custom validation logic: .. container:: codeset .. literalinclude:: ../../finance/src/main/kotlin/net/corda/flows/TwoPartyTradeFlow.kt - :language: kotlin - :start-after: DOCSTART 1 - :end-before: DOCEND 1 - :dedent: 4 + :language: kotlin + :start-after: DOCSTART 5 + :end-before: DOCEND 5 + :dedent: 12 -This code is longer but no more complicated. Here are some things to pay attention to: +In this case, our custom validation logic ensures that the amount of cash outputs in the transaction equals the +price of the asset. -1. We do some sanity checking on the received message to ensure we're being offered what we expected to be offered. -2. We create a cash spend using ``VaultService.generateSpend``. You can read the vault documentation to learn more about this. -3. We access the *service hub* when we need it to access things that are transient and may change or be recreated - whilst a flow is suspended, things like the wallet or the network map. -4. We send the unfinished, invalid transaction to the seller so they can sign it and finalise it. -5. Finally, we wait for the finished transaction to arrive in our local storage and vault. +Persisting flows +---------------- -As you can see, the flow logic is straightforward and does not contain any callbacks or network glue code, despite -the fact that it takes minimal resources and can survive node restarts. +If you look at the code for ``FinalityFlow``, ``CollectSignaturesFlow`` and ``SignTransactionFlow``, you'll see calls +to both ``receive`` and ``sendAndReceive``. Once either of these methods is called, the ``call`` method will be +suspended into a continuation and saved to persistent storage. If the node crashes or is restarted, the flow will +effectively continue as if nothing had happened. Your code may remain blocked inside such a call for seconds, +minutes, hours or even days in the case of a flow that needs human interaction! -Flow sessions -------------- +.. note:: There are a couple of rules you need to bear in mind when writing a class that will be used as a continuation. + The first is that anything on the stack when the function is suspended will be stored into the heap and kept alive by + the garbage collector. So try to avoid keeping enormous data structures alive unless you really have to. You can + always use private methods to keep the stack uncluttered with temporary variables, or to avoid objects that + Kryo is not able to serialise correctly. -Before going any further it will be useful to describe how flows communicate with each other. A node may have many flows -running at the same time, and perhaps communicating with the same counterparty node but for different purposes. Therefore -flows need a way to segregate communication channels so that concurrent conversations between flows on the same set of nodes -do not interfere with each other. + The second is that as well as being kept on the heap, objects reachable from the stack will be serialised. The state + of the function call may be resurrected much later! Kryo doesn't require objects be marked as serialisable, but even so, + doing things like creating threads from inside these calls would be a bad idea. They should only contain business + logic and only do I/O via the methods exposed by the flow framework. -To achieve this the flow framework initiates a new flow session each time a flow starts communicating with a ``Party`` -for the first time. A session is simply a pair of IDs, one for each side, to allow the node to route received messages to -the correct flow. If the other side accepts the session request then subsequent sends and receives to that same ``Party`` -will use the same session. A session ends when either flow ends, whether as expected or pre-maturely. If a flow ends -pre-maturely then the other side will be notified of that and they will also end, as the whole point of flows is a known -sequence of message transfers. Flows end pre-maturely due to exceptions, and as described above, if that exception is -``FlowException`` or a sub-type then it will propagate to the other side. Any other exception will not propagate. + It's OK to keep references around to many large internal node services though: these will be serialised using a + special token that's recognised by the platform, and wired up to the right instance when the continuation is + loaded off disk again. -Taking a step back, we mentioned that the other side has to accept the session request for there to be a communication -channel. A node accepts a session request if it has registered the flow type (the fully-qualified class name) that is -making the request - each session initiation includes the initiating flow type. This registration is done automatically -by the node at startup by searching for flows which are annotated with ``@InitiatedBy``. This annotation points to the -flow that is doing the initiating, and this flow must be annotated with ``@InitiatingFlow``. The ``InitiatedBy`` flow -must have a constructor which takes in a single parameter of type ``Party`` - this is the initiating party. +``receive`` and ``sendAndReceive`` return a simple wrapper class, ``UntrustworthyData``, which is +just a marker class that reminds us that the data came from a potentially malicious external source and may have been +tampered with or be unexpected in other ways. It doesn't add any functionality, but acts as a reminder to "scrub" +the data before use. -Going back to our buyer and seller flows, we need a way to initiate communication between the two. This is typically done -with one side started manually using the ``startFlowDynamic`` RPC and this initiates the flow on the other side. In our -case it doesn't matter which flow is the initiator and which is the initiated, which is why neither ``Buyer`` nor ``Seller`` -are annotated with ``InitiatedBy`` or ``InitiatingFlow``. If we, for example, choose the seller side as the initiator then -we need to create a simple seller starter flow that has the annotation we need: +Exception handling +------------------ -.. container:: codeset +Flows can throw exceptions to prematurely terminate their execution. The flow framework gives special treatment to +``FlowException`` and its subtypes. These exceptions are treated as error responses of the flow and are propagated +to all counterparties it is communicating with. The receiving flows will throw the same exception the next time they do +a ``receive`` or ``sendAndReceive`` and thus end the flow session. If the receiver was invoked via ``subFlow`` (details below) +then the exception can be caught there enabling re-invocation of the sub-flow. - .. sourcecode:: kotlin +If the exception thrown by the erroring flow is not a ``FlowException`` it will still terminate but will not propagate to +the other counterparties. Instead they will be informed the flow has terminated and will themselves be terminated with a +generic exception. - @InitiatingFlow - class SellerInitiator(val buyer: Party, - val notary: NodeInfo, - val assetToSell: StateAndRef, - val price: Amount) : FlowLogic() { - @Suspendable - override fun call(): SignedTransaction { - send(buyer, Pair(notary.notaryIdentity, price)) - return subFlow(Seller( - buyer, - notary, - assetToSell, - price, - serviceHub.legalIdentityKey)) - } - } +.. note:: A future version will extend this to give the node administrator more control on what to do with such erroring +flows. -The buyer side would look something like this. Notice the constructor takes in a single ``Party`` object which represents -the seller. - -.. container:: codeset - - .. sourcecode:: kotlin - - @InitiatedBy(SellerInitiator::class) - class BuyerAcceptor(val seller: Party) : FlowLogic() { - @Suspendable - override fun call() { - val (notary, price) = receive>>(seller).unwrap { - require(serviceHub.networkMapCache.isNotary(it.first)) { "${it.first} is not a notary" } - it - } - subFlow(Buyer(seller, notary, price, CommercialPaper.State::class.java)) - } - } +Throwing a ``FlowException`` enables a flow to reject a piece of data it has received back to the sender. This is typically +done in the ``unwrap`` method of the received ``UntrustworthyData``. In the above example the seller checks the price +and throws ``FlowException`` if it's invalid. It's then up to the buyer to either try again with a better price or give up. .. _progress-tracking: @@ -497,22 +513,28 @@ A flow might declare some steps with code inside the flow class like this: .. sourcecode:: java private final ProgressTracker progressTracker = new ProgressTracker( - CONSTRUCTING_OFFER, - SENDING_OFFER_AND_RECEIVING_PARTIAL_TRANSACTION, - VERIFYING + RECEIVING, + VERIFYING, + SIGNING, + COLLECTING_SIGNATURES, + RECORDING ); - private static final ProgressTracker.Step CONSTRUCTING_OFFER = new ProgressTracker.Step( - "Constructing proposed purchase order."); - private static final ProgressTracker.Step SENDING_OFFER_AND_RECEIVING_PARTIAL_TRANSACTION = new ProgressTracker.Step( - "Sending purchase order to seller for review, and receiving partially signed transaction from seller in return."); + private static final ProgressTracker.Step RECEIVING = new ProgressTracker.Step( + "Waiting for seller trading info"); private static final ProgressTracker.Step VERIFYING = new ProgressTracker.Step( - "Verifying signatures and contract constraints."); + "Verifying seller assets"); + private static final ProgressTracker.Step SIGNING = new ProgressTracker.Step( + "Generating and signing transaction proposal"); + private static final ProgressTracker.Step COLLECTING_SIGNATURES = new ProgressTracker.Step( + "Collecting signatures from other parties"); + private static final ProgressTracker.Step RECORDING = new ProgressTracker.Step( + "Recording completed transaction"); -Each step exposes a label. By default labels are fixed, but by subclassing ``RelabelableStep`` -you can make a step that can update its label on the fly. That's useful for steps that want to expose non-structured -progress information like the current file being downloaded. By defining your own step types, you can export progress -in a way that's both human readable and machine readable. +Each step exposes a label. By default labels are fixed, but by subclassing ``RelabelableStep`` you can make a step +that can update its label on the fly. That's useful for steps that want to expose non-structured progress information +like the current file being downloaded. By defining your own step types, you can export progress in a way that's both +human readable and machine readable. Progress trackers are hierarchical. Each step can be the parent for another tracker. By altering the ``ProgressTracker.childrenFor`` map, a tree of steps can be created. It's allowed to alter the hierarchy @@ -531,9 +553,9 @@ steps by overriding the ``Step`` class like this: .. sourcecode:: java - private static final ProgressTracker.Step COMMITTING = new ProgressTracker.Step("Committing to the ledger.") { + private static final ProgressTracker.Step VERIFYING_AND_SIGNING = new ProgressTracker.Step("Verifying and signing transaction proposal") { @Nullable @Override public ProgressTracker childProgressTracker() { - return FinalityFlow.Companion.tracker(); + return SignTransactionFlow.Companion.tracker(); } }; @@ -591,4 +613,4 @@ the features we have planned: * Being able to interact with people, either via some sort of external ticketing system, or email, or a custom UI. For example to implement human transaction authorisations. * A standard library of flows that can be easily sub-classed by local developers in order to integrate internal - reporting logic, or anything else that might be required as part of a communications lifecycle. + reporting logic, or anything else that might be required as part of a communications lifecycle. \ No newline at end of file diff --git a/finance/src/main/kotlin/net/corda/flows/TwoPartyTradeFlow.kt b/finance/src/main/kotlin/net/corda/flows/TwoPartyTradeFlow.kt index 210cc9b46f..9e46dc7f88 100644 --- a/finance/src/main/kotlin/net/corda/flows/TwoPartyTradeFlow.kt +++ b/finance/src/main/kotlin/net/corda/flows/TwoPartyTradeFlow.kt @@ -3,7 +3,6 @@ package net.corda.flows import co.paralleluniverse.fibers.Suspendable import net.corda.contracts.asset.sumCashBy import net.corda.core.contracts.* -import net.corda.core.crypto.DigitalSignature import net.corda.core.flows.FlowException import net.corda.core.flows.FlowLogic import net.corda.core.identity.AnonymousParty @@ -13,9 +12,7 @@ import net.corda.core.seconds import net.corda.core.serialization.CordaSerializable import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.TransactionBuilder -import net.corda.core.transactions.WireTransaction import net.corda.core.utilities.ProgressTracker -import net.corda.core.utilities.trace import net.corda.core.utilities.unwrap import java.security.PublicKey import java.util.* @@ -36,8 +33,6 @@ import java.util.* * that represents an atomic asset swap. * * Note that it's the *seller* who initiates contact with the buyer, not vice-versa as you might imagine. - * - * TODO: Refactor this using the [CollectSignaturesFlow]. Note. It requires a large docsite update! */ object TwoPartyTradeFlow { // TODO: Common elements in multi-party transaction consensus and signing should be refactored into a superclass of this @@ -57,10 +52,6 @@ object TwoPartyTradeFlow { val sellerOwnerKey: PublicKey ) - @CordaSerializable - data class SignaturesFromSeller(val sellerSig: DigitalSignature.WithKey, - val notarySig: DigitalSignature.WithKey) - open class Seller(val otherParty: PartyAndCertificate, val notaryNode: NodeInfo, val assetToSell: StateAndRef, @@ -70,62 +61,42 @@ object TwoPartyTradeFlow { companion object { object AWAITING_PROPOSAL : ProgressTracker.Step("Awaiting transaction proposal") - object VERIFYING : ProgressTracker.Step("Verifying transaction proposal") - object SIGNING : ProgressTracker.Step("Signing transaction") // DOCSTART 3 - object COMMITTING : ProgressTracker.Step("Committing transaction to the ledger") { - override fun childProgressTracker() = FinalityFlow.tracker() + object VERIFYING_AND_SIGNING : ProgressTracker.Step("Verifying and signing transaction proposal") { + override fun childProgressTracker() = SignTransactionFlow.tracker() } - // DOCEND 3 - object SENDING_FINAL_TX : ProgressTracker.Step("Sending final transaction to buyer") - fun tracker() = ProgressTracker(AWAITING_PROPOSAL, VERIFYING, SIGNING, COMMITTING, SENDING_FINAL_TX) + fun tracker() = ProgressTracker(AWAITING_PROPOSAL, VERIFYING_AND_SIGNING) } // DOCSTART 4 @Suspendable override fun call(): SignedTransaction { - val partialSTX: SignedTransaction = receiveAndCheckProposedTransaction() - val ourSignature = calculateOurSignature(partialSTX) - val unnotarisedSTX: SignedTransaction = partialSTX + ourSignature - val finishedSTX = subFlow(FinalityFlow(unnotarisedSTX)).single() - return finishedSTX - } - // DOCEND 4 - - // DOCSTART 5 - @Suspendable - private fun receiveAndCheckProposedTransaction(): SignedTransaction { progressTracker.currentStep = AWAITING_PROPOSAL - // Make the first message we'll send to kick off the flow. val hello = SellerTradeInfo(assetToSell, price, myKey) // What we get back from the other side is a transaction that *might* be valid and acceptable to us, // but we must check it out thoroughly before we sign! - val untrustedSTX = sendAndReceive(otherParty, hello) + send(otherParty, hello) - progressTracker.currentStep = VERIFYING - return untrustedSTX.unwrap { - // Check that the tx proposed by the buyer is valid. - val wtx: WireTransaction = it.verifySignatures(myKey, notaryNode.notaryIdentity.owningKey) - logger.trace { "Received partially signed transaction: ${it.id}" } - - // Download and check all the things that this transaction depends on and verify it is contract-valid, - // even though it is missing signatures. - subFlow(ResolveTransactionsFlow(wtx, otherParty)) - - if (wtx.outputs.map { it.data }.sumCashBy(AnonymousParty(myKey)).withoutIssuer() != price) - throw FlowException("Transaction is not sending us the right amount of cash") - - it + // Verify and sign the transaction. + progressTracker.currentStep = VERIFYING_AND_SIGNING + // DOCSTART 5 + val signTransactionFlow = object : SignTransactionFlow(otherParty, VERIFYING_AND_SIGNING.childProgressTracker()) { + override fun checkTransaction(stx: SignedTransaction) { + if (stx.tx.outputs.map { it.data }.sumCashBy(AnonymousParty(myKey)).withoutIssuer() != price) + throw FlowException("Transaction is not sending us the right amount of cash") + } } + return subFlow(signTransactionFlow) + // DOCEND 5 } - // DOCEND 5 + // DOCEND 4 // Following comment moved here so that it doesn't appear in the docsite: - // There are all sorts of funny games a malicious secondary might play with it sends maybeSTX (in - // receiveAndCheckProposedTransaction), we should fix them: + // There are all sorts of funny games a malicious secondary might play with it sends maybeSTX, + // we should fix them: // // - This tx may attempt to send some assets we aren't intending to sell to the secondary, if // we're reusing keys! So don't reuse keys! @@ -134,11 +105,6 @@ object TwoPartyTradeFlow { // // but the goal of this code is not to be fully secure (yet), but rather, just to find good ways to // express flow state machines on top of the messaging layer. - - open fun calculateOurSignature(partialTX: SignedTransaction): DigitalSignature.WithKey { - progressTracker.currentStep = SIGNING - return serviceHub.createSignature(partialTX, myKey) - } } open class Buyer(val otherParty: PartyAndCertificate, @@ -149,10 +115,15 @@ object TwoPartyTradeFlow { object RECEIVING : ProgressTracker.Step("Waiting for seller trading info") object VERIFYING : ProgressTracker.Step("Verifying seller assets") object SIGNING : ProgressTracker.Step("Generating and signing transaction proposal") - object SENDING_SIGNATURES : ProgressTracker.Step("Sending signatures to the seller") - object WAITING_FOR_TX : ProgressTracker.Step("Waiting for the transaction to finalise.") + object COLLECTING_SIGNATURES : ProgressTracker.Step("Collecting signatures from other parties") { + override fun childProgressTracker() = CollectSignaturesFlow.tracker() + } + object RECORDING : ProgressTracker.Step("Recording completed transaction") { + // TODO: Currently triggers a race condition on Team City. See https://github.com/corda/corda/issues/733. + // override fun childProgressTracker() = FinalityFlow.tracker() + } - override val progressTracker = ProgressTracker(RECEIVING, VERIFYING, SIGNING, SENDING_SIGNATURES, WAITING_FOR_TX) + override val progressTracker = ProgressTracker(RECEIVING, VERIFYING, SIGNING, COLLECTING_SIGNATURES, RECORDING) // DOCEND 2 // DOCSTART 1 @@ -165,16 +136,16 @@ object TwoPartyTradeFlow { // Put together a proposed transaction that performs the trade, and sign it. progressTracker.currentStep = SIGNING val (ptx, cashSigningPubKeys) = assembleSharedTX(tradeRequest) - val stx = signWithOurKeys(cashSigningPubKeys, ptx) + val partSignedTx = signWithOurKeys(cashSigningPubKeys, ptx) // Send the signed transaction to the seller, who must then sign it themselves and commit // it to the ledger by sending it to the notary. - progressTracker.currentStep = SENDING_SIGNATURES - send(otherParty, stx) + progressTracker.currentStep = COLLECTING_SIGNATURES + val twiceSignedTx = subFlow(CollectSignaturesFlow(partSignedTx, COLLECTING_SIGNATURES.childProgressTracker())) - // Wait for the finished, notarised transaction to arrive in our transaction store. - progressTracker.currentStep = WAITING_FOR_TX - return waitForLedgerCommit(stx.id) + // Notarise and record the transaction. + progressTracker.currentStep = RECORDING + return subFlow(FinalityFlow(twiceSignedTx, setOf(otherParty, serviceHub.myInfo.legalIdentity))).single() } @Suspendable @@ -186,7 +157,6 @@ object TwoPartyTradeFlow { // What is the seller trying to sell us? val asset = it.assetForSale.state.data val assetTypeName = asset.javaClass.name - logger.trace { "Got trade request for a $assetTypeName: ${it.assetForSale}" } if (it.price > acceptablePrice) throw UnacceptablePriceException(it.price) @@ -233,4 +203,4 @@ object TwoPartyTradeFlow { } // DOCEND 1 } -} +} \ No newline at end of file diff --git a/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt b/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt index d1e235ca06..5f4be70568 100644 --- a/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt +++ b/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt @@ -308,7 +308,7 @@ class TwoPartyTradeFlowTests { attachment(ByteArrayInputStream(stream.toByteArray())) } - val extraKey = bobNode.keyManagement.freshKey() + val extraKey = bobNode.keyManagement.keys.single() val bobsFakeCash = fillUpForBuyer(false, AnonymousParty(extraKey), DUMMY_CASH_ISSUER.party, notaryNode.info.notaryIdentity).second @@ -407,7 +407,7 @@ class TwoPartyTradeFlowTests { attachment(ByteArrayInputStream(stream.toByteArray())) } - val bobsKey = bobNode.keyManagement.freshKey() + val bobsKey = bobNode.keyManagement.keys.single() val bobsFakeCash = fillUpForBuyer(false, AnonymousParty(bobsKey), DUMMY_CASH_ISSUER.party, notaryNode.info.notaryIdentity).second From 81d32fd6a7d95d2004967796e5ea7e37d5b7b80c Mon Sep 17 00:00:00 2001 From: Andrius Dagys Date: Wed, 24 May 2017 15:41:30 +0100 Subject: [PATCH 028/126] Upgrade Artemis to 2.1.0 --- build.gradle | 2 +- node/src/main/kotlin/net/corda/node/internal/Node.kt | 3 ++- .../corda/node/services/messaging/ArtemisMessagingServer.kt | 4 ++-- .../net/corda/node/services/messaging/NodeMessagingClient.kt | 3 ++- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index 2622190ceb..f9c7222c4c 100644 --- a/build.gradle +++ b/build.gradle @@ -22,7 +22,7 @@ buildscript { ext.capsule_version = '1.0.1' ext.asm_version = '0.5.3' - ext.artemis_version = '1.5.3' + ext.artemis_version = '2.1.0' ext.jackson_version = '2.8.5' ext.jetty_version = '9.3.9.v20160517' ext.jersey_version = '2.25' diff --git a/node/src/main/kotlin/net/corda/node/internal/Node.kt b/node/src/main/kotlin/net/corda/node/internal/Node.kt index 4a195ff3c2..defa3c73e1 100644 --- a/node/src/main/kotlin/net/corda/node/internal/Node.kt +++ b/node/src/main/kotlin/net/corda/node/internal/Node.kt @@ -41,6 +41,7 @@ import net.corda.nodeapi.ArtemisMessagingComponent.NetworkMapAddress import net.corda.nodeapi.ArtemisTcpTransport import net.corda.nodeapi.ConnectionDirection import org.apache.activemq.artemis.api.core.ActiveMQNotConnectedException +import org.apache.activemq.artemis.api.core.RoutingType import org.apache.activemq.artemis.api.core.client.ActiveMQClient import org.apache.activemq.artemis.api.core.client.ClientMessage import org.bouncycastle.asn1.x500.X500Name @@ -208,7 +209,7 @@ class Node(override val configuration: FullNodeConfiguration, session.start() val queueName = "$IP_REQUEST_PREFIX$requestId" - session.createQueue(queueName, queueName, false) + session.createQueue(queueName, RoutingType.MULTICAST, queueName, false) val consumer = session.createConsumer(queueName) val artemisMessage: ClientMessage = consumer.receive(10.seconds.toMillis()) ?: diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingServer.kt b/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingServer.kt index 391d88046d..a5257bbd1e 100644 --- a/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingServer.kt +++ b/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingServer.kt @@ -30,12 +30,12 @@ import org.apache.activemq.artemis.core.config.Configuration import org.apache.activemq.artemis.core.config.CoreQueueConfiguration import org.apache.activemq.artemis.core.config.impl.ConfigurationImpl import org.apache.activemq.artemis.core.config.impl.SecurityConfiguration +import org.apache.activemq.artemis.core.message.impl.CoreMessage import org.apache.activemq.artemis.core.remoting.impl.netty.* import org.apache.activemq.artemis.core.security.Role import org.apache.activemq.artemis.core.server.ActiveMQServer import org.apache.activemq.artemis.core.server.impl.ActiveMQServerImpl import org.apache.activemq.artemis.core.server.impl.RoutingContextImpl -import org.apache.activemq.artemis.core.server.impl.ServerMessageImpl import org.apache.activemq.artemis.core.settings.impl.AddressFullMessagePolicy import org.apache.activemq.artemis.core.settings.impl.AddressSettings import org.apache.activemq.artemis.spi.core.remoting.* @@ -446,7 +446,7 @@ class ArtemisMessagingServer(override val config: NodeConfiguration, } fun sendResponse(remoteAddress: String?) { - val responseMessage = ServerMessageImpl(random63BitValue(), 0).apply { + val responseMessage = CoreMessage(random63BitValue(), 0).apply { putStringProperty(ipDetectResponseProperty, remoteAddress) } val routingContext = RoutingContextImpl(null) diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/NodeMessagingClient.kt b/node/src/main/kotlin/net/corda/node/services/messaging/NodeMessagingClient.kt index 19e1802dc4..56d56b8746 100644 --- a/node/src/main/kotlin/net/corda/node/services/messaging/NodeMessagingClient.kt +++ b/node/src/main/kotlin/net/corda/node/services/messaging/NodeMessagingClient.kt @@ -32,6 +32,7 @@ import net.corda.nodeapi.VerifierApi.VERIFICATION_REQUESTS_QUEUE_NAME import net.corda.nodeapi.VerifierApi.VERIFICATION_RESPONSES_QUEUE_NAME_PREFIX import org.apache.activemq.artemis.api.core.ActiveMQObjectClosedException import org.apache.activemq.artemis.api.core.Message.* +import org.apache.activemq.artemis.api.core.RoutingType import org.apache.activemq.artemis.api.core.SimpleString import org.apache.activemq.artemis.api.core.client.* import org.apache.activemq.artemis.api.core.client.ActiveMQClient.DEFAULT_ACK_BATCH_SIZE @@ -513,7 +514,7 @@ class NodeMessagingClient(override val config: NodeConfiguration, val queueQuery = session!!.queueQuery(SimpleString(queueName)) if (!queueQuery.isExists) { log.info("Create fresh queue $queueName bound on same address") - session!!.createQueue(queueName, queueName, true) + session!!.createQueue(queueName, RoutingType.MULTICAST, queueName, true) } } } From ecf85c74488a380a5fcca21c517fbae4d2ffc6ae Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Thu, 1 Jun 2017 13:31:35 +0100 Subject: [PATCH 029/126] Fixed noderunner issues on Windows by fixing a windows specific path quoting issue. --- .../kotlin/net/corda/plugins/NodeRunner.kt | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/gradle-plugins/cordformation/src/noderunner/kotlin/net/corda/plugins/NodeRunner.kt b/gradle-plugins/cordformation/src/noderunner/kotlin/net/corda/plugins/NodeRunner.kt index 0107b26e8b..e8f39c7f8c 100644 --- a/gradle-plugins/cordformation/src/noderunner/kotlin/net/corda/plugins/NodeRunner.kt +++ b/gradle-plugins/cordformation/src/noderunner/kotlin/net/corda/plugins/NodeRunner.kt @@ -3,6 +3,7 @@ package net.corda.plugins import java.awt.GraphicsEnvironment import java.io.File import java.nio.file.Files +import java.nio.file.Path import java.util.* private val HEADLESS_FLAG = "--headless" @@ -64,16 +65,24 @@ private object WebJarType : JarType("corda-webserver.jar") { private abstract class JavaCommand(jarName: String, internal val dir: File, debugPort: Int?, internal val nodeName: String, init: MutableList.() -> Unit, args: List) { internal val command: List = mutableListOf().apply { - add(File(File(System.getProperty("java.home"), "bin"), "java").path) + add(javaPath) add("-Dname=$nodeName") null != debugPort && add("-Dcapsule.jvm.args=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=$debugPort") - add("-jar"); add(jarName) + add("-jar") + add(jarName) init() addAll(args) } internal abstract fun processBuilder(): ProcessBuilder internal fun start() = processBuilder().directory(dir).start() + + private val javaPath: String by lazy { + val path = File(File(System.getProperty("java.home"), "bin"), "java").path + // Replace below is to fix an issue with spaces in paths on Windows. + // Quoting the entire path does not work, only the space or directory within the path. + if(os == OS.WINDOWS) path.replace(" ", "\" \"") else path + } } private class HeadlessJavaCommand(jarName: String, dir: File, debugPort: Int?, args: List) : JavaCommand(jarName, dir, debugPort, dir.name, { add("--no-local-shell") }, args) { From 1932a24fa64f5b7bce62bf66ed358a32e4eb5879 Mon Sep 17 00:00:00 2001 From: Chris Rankin Date: Thu, 1 Jun 2017 15:43:57 +0100 Subject: [PATCH 030/126] Upgrade to Netty 4.1.9 for Artemis 2.1.0 (#779) --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index f9c7222c4c..8dcb442789 100644 --- a/build.gradle +++ b/build.gradle @@ -34,7 +34,7 @@ buildscript { ext.guava_version = constants.getProperty("guavaVersion") ext.quickcheck_version = '0.7' ext.okhttp_version = '3.5.0' - ext.netty_version = '4.1.5.Final' + ext.netty_version = '4.1.9.Final' ext.typesafe_config_version = constants.getProperty("typesafeConfigVersion") ext.fileupload_version = '1.3.2' ext.junit_version = '4.12' From 4ae8356f35e4db1c531ddd07088a7def416678d8 Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Thu, 1 Jun 2017 15:46:32 +0100 Subject: [PATCH 031/126] Reordered a lazy eval to avoid an NPE --- constants.properties | 2 +- .../kotlin/net/corda/plugins/NodeRunner.kt | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/constants.properties b/constants.properties index 29575b5763..975d27b7a1 100644 --- a/constants.properties +++ b/constants.properties @@ -1,4 +1,4 @@ -gradlePluginsVersion=0.12.2 +gradlePluginsVersion=0.12.3 kotlinVersion=1.1.2 guavaVersion=21.0 bouncycastleVersion=1.56 diff --git a/gradle-plugins/cordformation/src/noderunner/kotlin/net/corda/plugins/NodeRunner.kt b/gradle-plugins/cordformation/src/noderunner/kotlin/net/corda/plugins/NodeRunner.kt index e8f39c7f8c..bc2d9181a0 100644 --- a/gradle-plugins/cordformation/src/noderunner/kotlin/net/corda/plugins/NodeRunner.kt +++ b/gradle-plugins/cordformation/src/noderunner/kotlin/net/corda/plugins/NodeRunner.kt @@ -64,6 +64,13 @@ private object WebJarType : JarType("corda-webserver.jar") { } private abstract class JavaCommand(jarName: String, internal val dir: File, debugPort: Int?, internal val nodeName: String, init: MutableList.() -> Unit, args: List) { + private val javaPath: String by lazy { + val path = File(File(System.getProperty("java.home"), "bin"), "java").path + // Replace below is to fix an issue with spaces in paths on Windows. + // Quoting the entire path does not work, only the space or directory within the path. + if(os == OS.WINDOWS) path.replace(" ", "\" \"") else path + } + internal val command: List = mutableListOf().apply { add(javaPath) add("-Dname=$nodeName") @@ -76,13 +83,6 @@ private abstract class JavaCommand(jarName: String, internal val dir: File, debu internal abstract fun processBuilder(): ProcessBuilder internal fun start() = processBuilder().directory(dir).start() - - private val javaPath: String by lazy { - val path = File(File(System.getProperty("java.home"), "bin"), "java").path - // Replace below is to fix an issue with spaces in paths on Windows. - // Quoting the entire path does not work, only the space or directory within the path. - if(os == OS.WINDOWS) path.replace(" ", "\" \"") else path - } } private class HeadlessJavaCommand(jarName: String, dir: File, debugPort: Int?, args: List) : JavaCommand(jarName, dir, debugPort, dir.name, { add("--no-local-shell") }, args) { From 964dbcd9a95fb49696e784d8696bee2369ccd639 Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Thu, 1 Jun 2017 17:05:16 +0100 Subject: [PATCH 032/126] Fixed java path for both headless and windowed mode. --- .../kotlin/net/corda/plugins/NodeRunner.kt | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/gradle-plugins/cordformation/src/noderunner/kotlin/net/corda/plugins/NodeRunner.kt b/gradle-plugins/cordformation/src/noderunner/kotlin/net/corda/plugins/NodeRunner.kt index bc2d9181a0..4a9711572e 100644 --- a/gradle-plugins/cordformation/src/noderunner/kotlin/net/corda/plugins/NodeRunner.kt +++ b/gradle-plugins/cordformation/src/noderunner/kotlin/net/corda/plugins/NodeRunner.kt @@ -64,15 +64,8 @@ private object WebJarType : JarType("corda-webserver.jar") { } private abstract class JavaCommand(jarName: String, internal val dir: File, debugPort: Int?, internal val nodeName: String, init: MutableList.() -> Unit, args: List) { - private val javaPath: String by lazy { - val path = File(File(System.getProperty("java.home"), "bin"), "java").path - // Replace below is to fix an issue with spaces in paths on Windows. - // Quoting the entire path does not work, only the space or directory within the path. - if(os == OS.WINDOWS) path.replace(" ", "\" \"") else path - } - internal val command: List = mutableListOf().apply { - add(javaPath) + add(getJavaPath()) add("-Dname=$nodeName") null != debugPort && add("-Dcapsule.jvm.args=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=$debugPort") add("-jar") @@ -83,10 +76,12 @@ private abstract class JavaCommand(jarName: String, internal val dir: File, debu internal abstract fun processBuilder(): ProcessBuilder internal fun start() = processBuilder().directory(dir).start() + internal abstract fun getJavaPath(): String } private class HeadlessJavaCommand(jarName: String, dir: File, debugPort: Int?, args: List) : JavaCommand(jarName, dir, debugPort, dir.name, { add("--no-local-shell") }, args) { override fun processBuilder() = ProcessBuilder(command).redirectError(File("error.$nodeName.log")).inheritIO() + override fun getJavaPath() = File(File(System.getProperty("java.home"), "bin"), "java").path } private class TerminalWindowJavaCommand(jarName: String, dir: File, debugPort: Int?, args: List) : JavaCommand(jarName, dir, debugPort, "${dir.name}-$jarName", {}, args) { @@ -114,6 +109,12 @@ end tell""") }) private fun unixCommand() = command.map(::quotedFormOf).joinToString(" ") + override fun getJavaPath(): String { + val path = File(File(System.getProperty("java.home"), "bin"), "java").path + // Replace below is to fix an issue with spaces in paths on Windows. + // Quoting the entire path does not work, only the space or directory within the path. + return if(os == OS.WINDOWS) path.replace(" ", "\" \"") else path + } } private fun quotedFormOf(text: String) = "'${text.replace("'", "'\\''")}'" // Suitable for UNIX shells. From 73666dbc7db77ae8cf6311c95f1d99bad3cb8208 Mon Sep 17 00:00:00 2001 From: Mike Hearn Date: Thu, 1 Jun 2017 18:34:06 +0200 Subject: [PATCH 033/126] Minor: Modernise startup messages --- node/src/main/kotlin/net/corda/node/Corda.kt | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/node/src/main/kotlin/net/corda/node/Corda.kt b/node/src/main/kotlin/net/corda/node/Corda.kt index 40991b33d0..3072840ba2 100644 --- a/node/src/main/kotlin/net/corda/node/Corda.kt +++ b/node/src/main/kotlin/net/corda/node/Corda.kt @@ -228,7 +228,7 @@ private fun printPluginsAndServices(node: Node) { private fun messageOfTheDay(): Pair { val messages = arrayListOf( "The only distributed ledger that pays\nhomage to Pac Man in its logo.", - "You know, I was a banker once ...\nbut I lost interest. ${Emoji.bagOfCash}", + "You know, I was a banker\nonce ... but I lost interest. ${Emoji.bagOfCash}", "It's not who you know, it's who you know\nknows what you know you know.", "It runs on the JVM because QuickBasic\nis apparently not 'professional' enough.", "\"It's OK computer, I go to sleep after\ntwenty minutes of inactivity too!\"", @@ -240,12 +240,11 @@ private fun messageOfTheDay(): Pair { "There was an earthquake in California,\na local bank went into de-fault.", "I asked for insurance if the nearby\nvolcano erupted. They said I'd be covered.", "I had an account with a bank in the\nNorth Pole, but they froze all my assets ${Emoji.santaClaus}", - "Check your contracts carefully. The\nfine print is usually a clause for suspicion ${Emoji.santaClaus}", + "Check your contracts carefully. The fine print\nis usually a clause for suspicion ${Emoji.santaClaus}", "Some bankers are generous ...\nto a vault! ${Emoji.bagOfCash} ${Emoji.coolGuy}", "What you can buy for a dollar these\ndays is absolute non-cents! ${Emoji.bagOfCash}", - "Old bankers never die, they just\n... pass the buck", - "My wife made me into millionaire.\nI was a multi-millionaire before we met.", - "I won $3M on the lottery so I donated\na quarter of it to charity. Now I have $2,999,999.75.", + "Old bankers never die, they\njust... pass the buck", + "I won $3M on the lottery so I donated a quarter\nof it to charity. Now I have $2,999,999.75.", "There are two rules for financial success:\n1) Don't tell everything you know.", "Top tip: never say \"oops\", instead\nalways say \"Ah, Interesting!\"", "Computers are useless. They can only\ngive you answers. -- Picasso" From 20b806cb623911adff3e8eef6ea62b726a666e98 Mon Sep 17 00:00:00 2001 From: Chris Rankin Date: Thu, 1 Jun 2017 17:57:38 +0100 Subject: [PATCH 034/126] Make RPC client reaper threads into daemons so that they don't block JVM shutdown. (#781) --- .../net/corda/client/rpc/internal/RPCClientProxyHandler.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClientProxyHandler.kt b/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClientProxyHandler.kt index 2fde6fcaaf..86dcf7a7d1 100644 --- a/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClientProxyHandler.kt +++ b/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClientProxyHandler.kt @@ -157,7 +157,7 @@ class RPCClientProxyHandler( lifeCycle.requireState(State.UNSTARTED) reaperExecutor = Executors.newScheduledThreadPool( 1, - ThreadFactoryBuilder().setNameFormat("rpc-client-reaper-%d").build() + ThreadFactoryBuilder().setNameFormat("rpc-client-reaper-%d").setDaemon(true).build() ) reaperScheduledFuture = reaperExecutor!!.scheduleAtFixedRate( this::reapObservables, From e2214c95b424977895e028b8a31f3ed52fdd7597 Mon Sep 17 00:00:00 2001 From: Ross Nicoll Date: Thu, 1 Jun 2017 18:54:44 +0100 Subject: [PATCH 035/126] Change PartyAndCertificate to an aggregate class (#778) Change PartyAndCertificate to an aggregate class instead of a subclass of Party. This reduces the changes compared to M11, as well as avoiding risk of accidental serialization of a PartyAndCertificate (which may be very large) where a Party is expected. Cleaned up initial nodes known to the identity service, in particular mock nodes now know about themselves; previously full nodes registered themselves but mock nodes did not. --- .../kotlin/net/corda/core/flows/TxKeyFlow.kt | 12 +++---- .../kotlin/net/corda/core/identity/Party.kt | 3 +- .../core/identity/PartyAndCertificate.kt | 28 ++++++++++++--- .../net/corda/core/messaging/CordaRPCOps.kt | 7 ++-- .../kotlin/net/corda/core/node/NodeInfo.kt | 20 +++++++---- .../net/corda/core/node/PluginServiceHub.kt | 3 +- .../core/node/services/IdentityService.kt | 31 +++++++++------- .../net/corda/core/node/services/PartyInfo.kt | 5 +-- .../net/corda/core/node/services/Services.kt | 1 - .../net/corda/core/utilities/TestConstants.kt | 24 +++++++------ .../flows/AbstractStateReplacementFlow.kt | 3 +- .../net/corda/flows/CollectSignaturesFlow.kt | 3 +- .../net/corda/flows/FetchAttachmentsFlow.kt | 4 +-- .../kotlin/net/corda/flows/FetchDataFlow.kt | 3 +- .../net/corda/flows/FetchTransactionsFlow.kt | 4 +-- .../net/corda/flows/NotaryChangeFlow.kt | 4 +-- .../main/kotlin/net/corda/flows/NotaryFlow.kt | 3 +- .../corda/flows/ResolveTransactionsFlow.kt | 8 ++--- .../net/corda/flows/TwoPartyDealFlow.kt | 5 ++- .../core/flows/CollectSignaturesFlowTests.kt | 5 ++- .../net/corda/core/flows/TxKeyFlowTests.kt | 13 ++++--- .../AttachmentSerializationTest.kt | 3 +- docs/source/changelog.rst | 6 ++-- .../corda/docs/FxTransactionBuildTutorial.kt | 10 +++--- .../corda/contracts/testing/VaultFiller.kt | 2 +- .../kotlin/net/corda/flows/CashExitFlow.kt | 2 +- .../kotlin/net/corda/flows/CashIssueFlow.kt | 2 +- .../kotlin/net/corda/flows/CashPaymentFlow.kt | 2 +- .../net/corda/flows/TwoPartyTradeFlow.kt | 10 +++--- .../AbstractStateReplacementFlowTest.java | 6 ++-- .../kotlin/net/corda/node/driver/Driver.kt | 5 ++- .../net/corda/node/internal/AbstractNode.kt | 17 +++------ .../node/internal/InitiatedFlowFactory.kt | 9 +++-- .../corda/node/services/CoreFlowHandlers.kt | 15 ++++---- .../identity/InMemoryIdentityService.kt | 30 ++++++++-------- .../net/corda/node/services/keys/KMSUtils.kt | 4 +-- .../network/InMemoryNetworkMapCache.kt | 2 +- .../services/network/NetworkMapService.kt | 5 ++- .../statemachine/StateMachineManager.kt | 3 +- .../BFTNonValidatingNotaryService.kt | 8 ++--- .../node/services/transactions/BFTSMaRt.kt | 8 ++--- .../transactions/NonValidatingNotaryFlow.kt | 6 ++-- .../services/transactions/NotaryService.kt | 5 ++- .../RaftNonValidatingNotaryService.kt | 4 +-- .../RaftValidatingNotaryService.kt | 4 +-- .../transactions/SimpleNotaryService.kt | 4 +-- .../transactions/ValidatingNotaryFlow.kt | 4 +-- .../transactions/ValidatingNotaryService.kt | 4 +-- .../corda/node/utilities/DatabaseSupport.kt | 7 ++-- .../utilities/ServiceIdentityGenerator.kt | 6 ++-- .../net/corda/node/InteractiveShellTest.kt | 3 +- .../node/messaging/TwoPartyTradeFlowTests.kt | 12 +++---- .../node/services/MockServiceHubInternal.kt | 1 - .../corda/node/services/NotaryChangeTests.kt | 2 +- .../network/AbstractNetworkMapServiceTest.kt | 2 +- .../network/InMemoryIdentityServiceTests.kt | 35 ++++++++++--------- .../persistence/DataVendingServiceTests.kt | 6 ++-- .../statemachine/FlowFrameworkTests.kt | 5 ++- .../NetworkisRegistrationHelperTest.kt | 2 -- .../kotlin/net/corda/irs/flows/FixingFlow.kt | 5 ++- .../net/corda/irs/simulation/IRSSimulation.kt | 5 ++- .../kotlin/net/corda/vega/api/PortfolioApi.kt | 8 ++--- .../net/corda/vega/flows/IRSTradeFlow.kt | 3 +- .../kotlin/net/corda/vega/flows/SimmFlow.kt | 4 +-- .../net/corda/vega/flows/StateRevisionFlow.kt | 3 +- .../net/corda/traderdemo/flow/BuyerFlow.kt | 4 +-- .../net/corda/traderdemo/flow/SellerFlow.kt | 5 ++- .../kotlin/net/corda/testing/CoreTestUtils.kt | 20 +++++++---- .../kotlin/net/corda/testing/node/MockNode.kt | 13 ++++--- .../net/corda/testing/node/MockServices.kt | 6 ++-- 70 files changed, 270 insertions(+), 256 deletions(-) diff --git a/core/src/main/kotlin/net/corda/core/flows/TxKeyFlow.kt b/core/src/main/kotlin/net/corda/core/flows/TxKeyFlow.kt index 571174942a..36945d0759 100644 --- a/core/src/main/kotlin/net/corda/core/flows/TxKeyFlow.kt +++ b/core/src/main/kotlin/net/corda/core/flows/TxKeyFlow.kt @@ -15,7 +15,7 @@ import java.security.cert.CertPath * This is intended for use as a subflow of another flow. */ object TxKeyFlow { - abstract class AbstractIdentityFlow(val otherSide: PartyAndCertificate, val revocationEnabled: Boolean): FlowLogic() { + abstract class AbstractIdentityFlow(val otherSide: Party, val revocationEnabled: Boolean): FlowLogic() { fun validateIdentity(untrustedIdentity: AnonymousIdentity): AnonymousIdentity { val (certPath, theirCert, txIdentity) = untrustedIdentity if (theirCert.subject == otherSide.name) { @@ -28,9 +28,9 @@ object TxKeyFlow { @StartableByRPC @InitiatingFlow - class Requester(otherSide: PartyAndCertificate, + class Requester(otherSide: Party, override val progressTracker: ProgressTracker) : AbstractIdentityFlow>(otherSide, false) { - constructor(otherSide: PartyAndCertificate) : this(otherSide, tracker()) + constructor(otherSide: Party) : this(otherSide, tracker()) companion object { object AWAITING_KEY : ProgressTracker.Step("Awaiting key") @@ -40,7 +40,7 @@ object TxKeyFlow { @Suspendable override fun call(): Map { progressTracker.currentStep = AWAITING_KEY - val myIdentityFragment = serviceHub.keyManagementService.freshKeyAndCert(serviceHub.myInfo.legalIdentity, revocationEnabled) + val myIdentityFragment = serviceHub.keyManagementService.freshKeyAndCert(serviceHub.myInfo.legalIdentityAndCert, revocationEnabled) val myIdentity = AnonymousIdentity(myIdentityFragment) val theirIdentity = receive(otherSide).unwrap { validateIdentity(it) } send(otherSide, myIdentity) @@ -54,7 +54,7 @@ object TxKeyFlow { * counterparty and as the result from the flow. */ @InitiatedBy(Requester::class) - class Provider(otherSide: PartyAndCertificate) : AbstractIdentityFlow>(otherSide, false) { + class Provider(otherSide: Party) : AbstractIdentityFlow>(otherSide, false) { companion object { object SENDING_KEY : ProgressTracker.Step("Sending key") } @@ -65,7 +65,7 @@ object TxKeyFlow { override fun call(): Map { val revocationEnabled = false progressTracker.currentStep = SENDING_KEY - val myIdentityFragment = serviceHub.keyManagementService.freshKeyAndCert(serviceHub.myInfo.legalIdentity, revocationEnabled) + val myIdentityFragment = serviceHub.keyManagementService.freshKeyAndCert(serviceHub.myInfo.legalIdentityAndCert, revocationEnabled) val myIdentity = AnonymousIdentity(myIdentityFragment) send(otherSide, myIdentity) val theirIdentity = receive(otherSide).unwrap { validateIdentity(it) } diff --git a/core/src/main/kotlin/net/corda/core/identity/Party.kt b/core/src/main/kotlin/net/corda/core/identity/Party.kt index 45486049e8..19cda5c50e 100644 --- a/core/src/main/kotlin/net/corda/core/identity/Party.kt +++ b/core/src/main/kotlin/net/corda/core/identity/Party.kt @@ -3,6 +3,7 @@ package net.corda.core.identity import net.corda.core.contracts.PartyAndReference import net.corda.core.crypto.CertificateAndKeyPair import net.corda.core.crypto.toBase58String +import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.OpaqueBytes import org.bouncycastle.asn1.x500.X500Name import java.security.PublicKey @@ -26,7 +27,7 @@ import java.security.PublicKey * * @see CompositeKey */ -open class Party(val name: X500Name, owningKey: PublicKey) : AbstractParty(owningKey) { +class Party(val name: X500Name, owningKey: PublicKey) : AbstractParty(owningKey) { constructor(certAndKey: CertificateAndKeyPair) : this(certAndKey.certificate.subject, certAndKey.keyPair.public) override fun toString() = name.toString() override fun nameOrNull(): X500Name? = name diff --git a/core/src/main/kotlin/net/corda/core/identity/PartyAndCertificate.kt b/core/src/main/kotlin/net/corda/core/identity/PartyAndCertificate.kt index a145ce7021..12557d562e 100644 --- a/core/src/main/kotlin/net/corda/core/identity/PartyAndCertificate.kt +++ b/core/src/main/kotlin/net/corda/core/identity/PartyAndCertificate.kt @@ -1,13 +1,33 @@ package net.corda.core.identity +import net.corda.core.serialization.CordaSerializable import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.cert.X509CertificateHolder import java.security.PublicKey import java.security.cert.CertPath /** - * A full party plus the X.509 certificate and path linking the party back to a trust root. + * A full party plus the X.509 certificate and path linking the party back to a trust root. Equality of + * [PartyAndCertificate] instances is based on the party only, as certificate and path are data associated with the party, + * not part of the identifier themselves. */ -class PartyAndCertificate(name: X500Name, owningKey: PublicKey, - val certificate: X509CertificateHolder, - val certPath: CertPath) : Party(name, owningKey) \ No newline at end of file +@CordaSerializable +data class PartyAndCertificate(val party: Party, + val certificate: X509CertificateHolder, + val certPath: CertPath) { + constructor(name: X500Name, owningKey: PublicKey, certificate: X509CertificateHolder, certPath: CertPath) : this(Party(name, owningKey), certificate, certPath) + val name: X500Name + get() = party.name + val owningKey: PublicKey + get() = party.owningKey + + override fun equals(other: Any?): Boolean { + return if (other is PartyAndCertificate) + party == other.party + else + false + } + + override fun hashCode(): Int = party.hashCode() + override fun toString(): String = party.toString() +} diff --git a/core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt b/core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt index 99d53d0b7d..190f2456a0 100644 --- a/core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt +++ b/core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt @@ -11,7 +11,6 @@ import net.corda.core.flows.FlowInitiator import net.corda.core.flows.FlowLogic import net.corda.core.flows.StateMachineRunId import net.corda.core.identity.Party -import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.NodeInfo import net.corda.core.node.services.NetworkMapCache import net.corda.core.node.services.StateMachineTransactionMapping @@ -232,18 +231,18 @@ interface CordaRPCOps : RPCOps { /** * Returns the [Party] corresponding to the given key, if found. */ - fun partyFromKey(key: PublicKey): PartyAndCertificate? + fun partyFromKey(key: PublicKey): Party? /** * Returns the [Party] with the given name as it's [Party.name] */ @Deprecated("Use partyFromX500Name instead") - fun partyFromName(name: String): PartyAndCertificate? + fun partyFromName(name: String): Party? /** * Returns the [Party] with the X.500 principal as it's [Party.name] */ - fun partyFromX500Name(x500Name: X500Name): PartyAndCertificate? + fun partyFromX500Name(x500Name: X500Name): Party? /** Enumerates the class names of the flows that this node knows about. */ fun registeredFlows(): List diff --git a/core/src/main/kotlin/net/corda/core/node/NodeInfo.kt b/core/src/main/kotlin/net/corda/core/node/NodeInfo.kt index 805d5ad0a7..15f98be512 100644 --- a/core/src/main/kotlin/net/corda/core/node/NodeInfo.kt +++ b/core/src/main/kotlin/net/corda/core/node/NodeInfo.kt @@ -6,9 +6,7 @@ import net.corda.core.messaging.SingleMessageRecipient import net.corda.core.node.services.ServiceInfo import net.corda.core.node.services.ServiceType import net.corda.core.serialization.CordaSerializable -import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter -import java.security.cert.TrustAnchor -import java.security.cert.X509Certificate +import org.bouncycastle.cert.X509CertificateHolder /** * Information for an advertised service including the service specific identity information. @@ -22,14 +20,22 @@ data class ServiceEntry(val info: ServiceInfo, val identity: PartyAndCertificate */ @CordaSerializable data class NodeInfo(val address: SingleMessageRecipient, - val legalIdentity: PartyAndCertificate, + val legalIdentityAndCert: PartyAndCertificate, val platformVersion: Int, var advertisedServices: List = emptyList(), val physicalLocation: PhysicalLocation? = null) { init { - require(advertisedServices.none { it.identity == legalIdentity }) { "Service identities must be different from node legal identity" } + require(advertisedServices.none { it.identity == legalIdentityAndCert }) { "Service identities must be different from node legal identity" } } - val notaryIdentity: PartyAndCertificate get() = advertisedServices.single { it.info.type.isNotary() }.identity - fun serviceIdentities(type: ServiceType): List = advertisedServices.filter { it.info.type.isSubTypeOf(type) }.map { it.identity } + val legalIdentity: Party + get() = legalIdentityAndCert.party + val notaryIdentity: Party + get() = advertisedServices.single { it.info.type.isNotary() }.identity.party + fun serviceIdentities(type: ServiceType): List { + return advertisedServices.filter { it.info.type.isSubTypeOf(type) }.map { it.identity.party } + } + fun servideIdentitiesAndCert(type: ServiceType): List { + return advertisedServices.filter { it.info.type.isSubTypeOf(type) }.map { it.identity } + } } diff --git a/core/src/main/kotlin/net/corda/core/node/PluginServiceHub.kt b/core/src/main/kotlin/net/corda/core/node/PluginServiceHub.kt index dbb6133ce9..be193d2dfe 100644 --- a/core/src/main/kotlin/net/corda/core/node/PluginServiceHub.kt +++ b/core/src/main/kotlin/net/corda/core/node/PluginServiceHub.kt @@ -2,7 +2,6 @@ package net.corda.core.node import net.corda.core.flows.FlowLogic import net.corda.core.identity.Party -import net.corda.core.identity.PartyAndCertificate /** * A service hub to be used by the [CordaPluginRegistry] @@ -10,5 +9,5 @@ import net.corda.core.identity.PartyAndCertificate interface PluginServiceHub : ServiceHub { @Deprecated("This is no longer used. Instead annotate the flows produced by your factory with @InitiatedBy and have " + "them point to the initiating flow class.", level = DeprecationLevel.ERROR) - fun registerFlowInitiator(initiatingFlowClass: Class>, serviceFlowFactory: (PartyAndCertificate) -> FlowLogic<*>) = Unit + fun registerFlowInitiator(initiatingFlowClass: Class>, serviceFlowFactory: (Party) -> FlowLogic<*>) = Unit } diff --git a/core/src/main/kotlin/net/corda/core/node/services/IdentityService.kt b/core/src/main/kotlin/net/corda/core/node/services/IdentityService.kt index 97b3529668..586ad52ce2 100644 --- a/core/src/main/kotlin/net/corda/core/node/services/IdentityService.kt +++ b/core/src/main/kotlin/net/corda/core/node/services/IdentityService.kt @@ -1,10 +1,8 @@ package net.corda.core.node.services import net.corda.core.contracts.PartyAndReference -import net.corda.core.identity.AbstractParty -import net.corda.core.identity.AnonymousParty -import net.corda.core.identity.Party -import net.corda.core.identity.PartyAndCertificate +import net.corda.core.identity.* +import net.corda.core.node.NodeInfo import org.bouncycastle.asn1.x500.X500Name import java.security.InvalidAlgorithmParameterException import java.security.PublicKey @@ -13,9 +11,9 @@ import java.security.cert.CertificateExpiredException import java.security.cert.CertificateNotYetValidException /** - * An identity service maintains an bidirectional map of [Party]s to their associated public keys and thus supports - * lookup of a party given its key. This is obviously very incomplete and does not reflect everything a real identity - * service would provide. + * An identity service maintains a directory of parties by their associated distinguished name/public keys and thus + * supports lookup of a party given its key, or name. The service also manages the certificates linking confidential + * identities back to the well known identity (i.e. the identity in the network map) of a party. */ interface IdentityService { /** @@ -37,7 +35,7 @@ interface IdentityService { * certificate chain for the anonymous party. */ @Throws(CertificateExpiredException::class, CertificateNotYetValidException::class, InvalidAlgorithmParameterException::class) - fun registerAnonymousIdentity(anonymousParty: AnonymousParty, fullParty: PartyAndCertificate, path: CertPath) + fun registerAnonymousIdentity(anonymousParty: AnonymousParty, party: Party, path: CertPath) /** * Asserts that an anonymous party maps to the given full party, by looking up the certificate chain associated with @@ -52,16 +50,23 @@ interface IdentityService { * Get all identities known to the service. This is expensive, and [partyFromKey] or [partyFromX500Name] should be * used in preference where possible. */ - fun getAllIdentities(): Iterable + fun getAllIdentities(): Iterable + + /** + * Get the certificate and path for a well known identity. + * + * @return the party and certificate, or null if unknown. + */ + fun certificateFromParty(party: Party): PartyAndCertificate? // There is no method for removing identities, as once we are made aware of a Party we want to keep track of them // indefinitely. It may be that in the long term we need to drop or archive very old Party information for space, // but for now this is not supported. - fun partyFromKey(key: PublicKey): PartyAndCertificate? + fun partyFromKey(key: PublicKey): Party? @Deprecated("Use partyFromX500Name") - fun partyFromName(name: String): PartyAndCertificate? - fun partyFromX500Name(principal: X500Name): PartyAndCertificate? + fun partyFromName(name: String): Party? + fun partyFromX500Name(principal: X500Name): Party? /** * Resolve the well known identity of a party. If the party passed in is already a well known identity @@ -69,7 +74,7 @@ interface IdentityService { * * @return the well known identity, or null if unknown. */ - fun partyFromAnonymous(party: AbstractParty): PartyAndCertificate? + fun partyFromAnonymous(party: AbstractParty): Party? /** * Resolve the well known identity of a party. If the party passed in is already a well known identity diff --git a/core/src/main/kotlin/net/corda/core/node/services/PartyInfo.kt b/core/src/main/kotlin/net/corda/core/node/services/PartyInfo.kt index e7ec60dd6f..94ff9c94c5 100644 --- a/core/src/main/kotlin/net/corda/core/node/services/PartyInfo.kt +++ b/core/src/main/kotlin/net/corda/core/node/services/PartyInfo.kt @@ -1,6 +1,7 @@ package net.corda.core.node.services import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.NodeInfo import net.corda.core.node.ServiceEntry @@ -8,10 +9,10 @@ import net.corda.core.node.ServiceEntry * Holds information about a [Party], which may refer to either a specific node or a service. */ sealed class PartyInfo { - abstract val party: Party + abstract val party: PartyAndCertificate data class Node(val node: NodeInfo) : PartyInfo() { - override val party get() = node.legalIdentity + override val party get() = node.legalIdentityAndCert } data class Service(val service: ServiceEntry) : PartyInfo() { diff --git a/core/src/main/kotlin/net/corda/core/node/services/Services.kt b/core/src/main/kotlin/net/corda/core/node/services/Services.kt index cc891304f9..b1e1b8bc7a 100644 --- a/core/src/main/kotlin/net/corda/core/node/services/Services.kt +++ b/core/src/main/kotlin/net/corda/core/node/services/Services.kt @@ -21,7 +21,6 @@ import net.corda.core.transactions.LedgerTransaction import net.corda.core.transactions.TransactionBuilder import net.corda.core.transactions.WireTransaction import org.bouncycastle.cert.X509CertificateHolder -import org.bouncycastle.operator.ContentSigner import rx.Observable import java.io.InputStream import java.security.PublicKey diff --git a/core/src/main/kotlin/net/corda/core/utilities/TestConstants.kt b/core/src/main/kotlin/net/corda/core/utilities/TestConstants.kt index ad71163702..18a24c1019 100644 --- a/core/src/main/kotlin/net/corda/core/utilities/TestConstants.kt +++ b/core/src/main/kotlin/net/corda/core/utilities/TestConstants.kt @@ -3,6 +3,7 @@ package net.corda.core.utilities import net.corda.core.crypto.* +import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate import org.bouncycastle.asn1.x500.X500Name import java.math.BigInteger @@ -21,39 +22,42 @@ val DUMMY_KEY_2: KeyPair by lazy { generateKeyPair() } val DUMMY_NOTARY_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(20)) } /** Dummy notary identity for tests and simulations */ -val DUMMY_NOTARY: PartyAndCertificate get() = getTestPartyAndCertificate(X500Name("CN=Notary Service,O=R3,OU=corda,L=Zurich,C=CH"), DUMMY_NOTARY_KEY.public) +val DUMMY_NOTARY_IDENTITY: PartyAndCertificate get() = getTestPartyAndCertificate(X500Name("CN=Notary Service,O=R3,OU=corda,L=Zurich,C=CH"), DUMMY_NOTARY_KEY.public) +val DUMMY_NOTARY: Party get() = DUMMY_NOTARY_IDENTITY.party val DUMMY_MAP_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(30)) } /** Dummy network map service identity for tests and simulations */ -val DUMMY_MAP: PartyAndCertificate get() = getTestPartyAndCertificate(X500Name("CN=Network Map Service,O=R3,OU=corda,L=Amsterdam,C=NL"), DUMMY_MAP_KEY.public) +val DUMMY_MAP: Party get() = Party(X500Name("CN=Network Map Service,O=R3,OU=corda,L=Amsterdam,C=NL"), DUMMY_MAP_KEY.public) val DUMMY_BANK_A_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(40)) } /** Dummy bank identity for tests and simulations */ -val DUMMY_BANK_A: PartyAndCertificate get() = getTestPartyAndCertificate(X500Name("CN=Bank A,O=Bank A,L=London,C=UK"), DUMMY_BANK_A_KEY.public) +val DUMMY_BANK_A: Party get() = Party(X500Name("CN=Bank A,O=Bank A,L=London,C=UK"), DUMMY_BANK_A_KEY.public) val DUMMY_BANK_B_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(50)) } /** Dummy bank identity for tests and simulations */ -val DUMMY_BANK_B: PartyAndCertificate get() = getTestPartyAndCertificate(X500Name("CN=Bank B,O=Bank B,L=New York,C=US"), DUMMY_BANK_B_KEY.public) +val DUMMY_BANK_B: Party get() = Party(X500Name("CN=Bank B,O=Bank B,L=New York,C=US"), DUMMY_BANK_B_KEY.public) val DUMMY_BANK_C_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(60)) } /** Dummy bank identity for tests and simulations */ -val DUMMY_BANK_C: PartyAndCertificate get() = getTestPartyAndCertificate(X500Name("CN=Bank C,O=Bank C,L=Tokyo,C=JP"), DUMMY_BANK_C_KEY.public) +val DUMMY_BANK_C: Party get() = Party(X500Name("CN=Bank C,O=Bank C,L=Tokyo,C=JP"), DUMMY_BANK_C_KEY.public) val ALICE_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(70)) } /** Dummy individual identity for tests and simulations */ -val ALICE: PartyAndCertificate get() = getTestPartyAndCertificate(X500Name("CN=Alice Corp,O=Alice Corp,L=London,C=UK"), ALICE_KEY.public) +val ALICE_IDENTITY: PartyAndCertificate get() = getTestPartyAndCertificate(X500Name("CN=Alice Corp,O=Alice Corp,L=London,C=UK"), ALICE_KEY.public) +val ALICE: Party get() = ALICE_IDENTITY.party val BOB_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(80)) } /** Dummy individual identity for tests and simulations */ -val BOB: PartyAndCertificate get() = getTestPartyAndCertificate(X500Name("CN=Bob Plc,O=Bob Plc,L=London,C=UK"), BOB_KEY.public) +val BOB_IDENTITY: PartyAndCertificate get() = getTestPartyAndCertificate(X500Name("CN=Bob Plc,O=Bob Plc,L=London,C=UK"), BOB_KEY.public) +val BOB: Party get() = BOB_IDENTITY.party val CHARLIE_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(90)) } /** Dummy individual identity for tests and simulations */ -val CHARLIE: PartyAndCertificate get() = getTestPartyAndCertificate(X500Name("CN=Charlie Ltd,O=Charlie Ltd,L=London,C=UK"), CHARLIE_KEY.public) +val CHARLIE: Party get() = Party(X500Name("CN=Charlie Ltd,O=Charlie Ltd,L=London,C=UK"), CHARLIE_KEY.public) val DUMMY_REGULATOR_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(100)) } /** Dummy regulator for tests and simulations */ -val DUMMY_REGULATOR: PartyAndCertificate get() = getTestPartyAndCertificate(X500Name("CN=Regulator A,OU=Corda,O=AMF,L=Paris,C=FR"), DUMMY_REGULATOR_KEY.public) +val DUMMY_REGULATOR: Party get() = Party(X500Name("CN=Regulator A,OU=Corda,O=AMF,L=Paris,C=FR"), DUMMY_REGULATOR_KEY.public) val DUMMY_CA_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(110)) } val DUMMY_CA: CertificateAndKeyPair by lazy { @@ -69,4 +73,4 @@ fun getTestPartyAndCertificate(name: X500Name, publicKey: PublicKey): PartyAndCe val cert = X509Utilities.createCertificate(CertificateType.IDENTITY, DUMMY_CA.certificate, DUMMY_CA.keyPair, name, publicKey) val certPath = X509Utilities.createCertificatePath(DUMMY_CA.certificate, cert, revocationEnabled = false) return PartyAndCertificate(name, publicKey, cert, certPath) -} \ No newline at end of file +} diff --git a/core/src/main/kotlin/net/corda/flows/AbstractStateReplacementFlow.kt b/core/src/main/kotlin/net/corda/flows/AbstractStateReplacementFlow.kt index ba2251c272..f00941e786 100644 --- a/core/src/main/kotlin/net/corda/flows/AbstractStateReplacementFlow.kt +++ b/core/src/main/kotlin/net/corda/flows/AbstractStateReplacementFlow.kt @@ -10,7 +10,6 @@ import net.corda.core.flows.FlowException import net.corda.core.flows.FlowLogic import net.corda.core.identity.AbstractParty import net.corda.core.identity.Party -import net.corda.core.identity.PartyAndCertificate import net.corda.core.serialization.CordaSerializable import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.WireTransaction @@ -120,7 +119,7 @@ abstract class AbstractStateReplacementFlow { // Type parameter should ideally be Unit but that prevents Java code from subclassing it (https://youtrack.jetbrains.com/issue/KT-15964). // We use Void? instead of Unit? as that's what you'd use in Java. - abstract class Acceptor(val otherSide: PartyAndCertificate, + abstract class Acceptor(val otherSide: Party, override val progressTracker: ProgressTracker = tracker()) : FlowLogic() { companion object { object VERIFYING : ProgressTracker.Step("Verifying state replacement proposal") diff --git a/core/src/main/kotlin/net/corda/flows/CollectSignaturesFlow.kt b/core/src/main/kotlin/net/corda/flows/CollectSignaturesFlow.kt index 8258f68f49..f6788653cf 100644 --- a/core/src/main/kotlin/net/corda/flows/CollectSignaturesFlow.kt +++ b/core/src/main/kotlin/net/corda/flows/CollectSignaturesFlow.kt @@ -7,7 +7,6 @@ import net.corda.core.crypto.toBase58String import net.corda.core.flows.FlowException import net.corda.core.flows.FlowLogic import net.corda.core.identity.Party -import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.ServiceHub import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.WireTransaction @@ -173,7 +172,7 @@ class CollectSignaturesFlow(val partiallySignedTx: SignedTransaction, * * @param otherParty The counter-party which is providing you a transaction to sign. */ -abstract class SignTransactionFlow(val otherParty: PartyAndCertificate, +abstract class SignTransactionFlow(val otherParty: Party, override val progressTracker: ProgressTracker = tracker()) : FlowLogic() { companion object { diff --git a/core/src/main/kotlin/net/corda/flows/FetchAttachmentsFlow.kt b/core/src/main/kotlin/net/corda/flows/FetchAttachmentsFlow.kt index 5ac5e6c329..3ca8c8f695 100644 --- a/core/src/main/kotlin/net/corda/flows/FetchAttachmentsFlow.kt +++ b/core/src/main/kotlin/net/corda/flows/FetchAttachmentsFlow.kt @@ -5,7 +5,7 @@ import net.corda.core.contracts.Attachment import net.corda.core.crypto.SecureHash import net.corda.core.crypto.sha256 import net.corda.core.flows.InitiatingFlow -import net.corda.core.identity.PartyAndCertificate +import net.corda.core.identity.Party import net.corda.core.serialization.SerializationToken import net.corda.core.serialization.SerializeAsToken import net.corda.core.serialization.SerializeAsTokenContext @@ -16,7 +16,7 @@ import net.corda.core.serialization.SerializeAsTokenContext */ @InitiatingFlow class FetchAttachmentsFlow(requests: Set, - otherSide: PartyAndCertificate) : FetchDataFlow(requests, otherSide) { + otherSide: Party) : FetchDataFlow(requests, otherSide) { override fun load(txid: SecureHash): Attachment? = serviceHub.storageService.attachments.openAttachment(txid) diff --git a/core/src/main/kotlin/net/corda/flows/FetchDataFlow.kt b/core/src/main/kotlin/net/corda/flows/FetchDataFlow.kt index 0603a15fb7..efbe720210 100644 --- a/core/src/main/kotlin/net/corda/flows/FetchDataFlow.kt +++ b/core/src/main/kotlin/net/corda/flows/FetchDataFlow.kt @@ -6,7 +6,6 @@ import net.corda.core.crypto.SecureHash import net.corda.core.flows.FlowException import net.corda.core.flows.FlowLogic import net.corda.core.identity.Party -import net.corda.core.identity.PartyAndCertificate import net.corda.core.serialization.CordaSerializable import net.corda.core.utilities.UntrustworthyData import net.corda.core.utilities.unwrap @@ -32,7 +31,7 @@ import java.util.* */ abstract class FetchDataFlow( protected val requests: Set, - protected val otherSide: PartyAndCertificate) : FlowLogic>() { + protected val otherSide: Party) : FlowLogic>() { @CordaSerializable class DownloadedVsRequestedDataMismatch(val requested: SecureHash, val got: SecureHash) : IllegalArgumentException() diff --git a/core/src/main/kotlin/net/corda/flows/FetchTransactionsFlow.kt b/core/src/main/kotlin/net/corda/flows/FetchTransactionsFlow.kt index e0dcb24266..6e9c1055a8 100644 --- a/core/src/main/kotlin/net/corda/flows/FetchTransactionsFlow.kt +++ b/core/src/main/kotlin/net/corda/flows/FetchTransactionsFlow.kt @@ -2,7 +2,7 @@ package net.corda.flows import net.corda.core.crypto.SecureHash import net.corda.core.flows.InitiatingFlow -import net.corda.core.identity.PartyAndCertificate +import net.corda.core.identity.Party import net.corda.core.transactions.SignedTransaction /** @@ -14,7 +14,7 @@ import net.corda.core.transactions.SignedTransaction * the database, because it's up to the caller to actually verify the transactions are valid. */ @InitiatingFlow -class FetchTransactionsFlow(requests: Set, otherSide: PartyAndCertificate) : +class FetchTransactionsFlow(requests: Set, otherSide: Party) : FetchDataFlow(requests, otherSide) { override fun load(txid: SecureHash): SignedTransaction? { diff --git a/core/src/main/kotlin/net/corda/flows/NotaryChangeFlow.kt b/core/src/main/kotlin/net/corda/flows/NotaryChangeFlow.kt index 172d2787ce..f99bcd2f3a 100644 --- a/core/src/main/kotlin/net/corda/flows/NotaryChangeFlow.kt +++ b/core/src/main/kotlin/net/corda/flows/NotaryChangeFlow.kt @@ -4,11 +4,9 @@ import net.corda.core.contracts.* import net.corda.core.flows.InitiatingFlow import net.corda.core.identity.AbstractParty import net.corda.core.identity.Party -import net.corda.core.identity.PartyAndCertificate import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.TransactionBuilder import net.corda.core.utilities.ProgressTracker -import java.security.PublicKey /** * A flow to be used for changing a state's Notary. This is required since all input states to a transaction @@ -22,7 +20,7 @@ import java.security.PublicKey @InitiatingFlow class NotaryChangeFlow( originalState: StateAndRef, - newNotary: PartyAndCertificate, + newNotary: Party, progressTracker: ProgressTracker = tracker()) : AbstractStateReplacementFlow.Instigator(originalState, newNotary, progressTracker) { diff --git a/core/src/main/kotlin/net/corda/flows/NotaryFlow.kt b/core/src/main/kotlin/net/corda/flows/NotaryFlow.kt index 999c6f688c..3c67bb35e3 100644 --- a/core/src/main/kotlin/net/corda/flows/NotaryFlow.kt +++ b/core/src/main/kotlin/net/corda/flows/NotaryFlow.kt @@ -11,7 +11,6 @@ import net.corda.core.flows.FlowException import net.corda.core.flows.FlowLogic import net.corda.core.flows.InitiatingFlow import net.corda.core.identity.Party -import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.services.TimeWindowChecker import net.corda.core.node.services.UniquenessException import net.corda.core.node.services.UniquenessProvider @@ -97,7 +96,7 @@ object NotaryFlow { * Additional transaction validation logic can be added when implementing [receiveAndVerifyTx]. */ // See AbstractStateReplacementFlow.Acceptor for why it's Void? - abstract class Service(val otherSide: PartyAndCertificate, + abstract class Service(val otherSide: Party, val timeWindowChecker: TimeWindowChecker, val uniquenessProvider: UniquenessProvider) : FlowLogic() { @Suspendable diff --git a/core/src/main/kotlin/net/corda/flows/ResolveTransactionsFlow.kt b/core/src/main/kotlin/net/corda/flows/ResolveTransactionsFlow.kt index fe17f8708e..1b6d3d4b91 100644 --- a/core/src/main/kotlin/net/corda/flows/ResolveTransactionsFlow.kt +++ b/core/src/main/kotlin/net/corda/flows/ResolveTransactionsFlow.kt @@ -5,7 +5,7 @@ import net.corda.core.checkedAdd import net.corda.core.crypto.SecureHash import net.corda.core.flows.FlowLogic import net.corda.core.getOrThrow -import net.corda.core.identity.PartyAndCertificate +import net.corda.core.identity.Party import net.corda.core.serialization.CordaSerializable import net.corda.core.transactions.LedgerTransaction import net.corda.core.transactions.SignedTransaction @@ -30,7 +30,7 @@ import java.util.* * The flow returns a list of verified [LedgerTransaction] objects, in a depth-first order. */ class ResolveTransactionsFlow(private val txHashes: Set, - private val otherSide: PartyAndCertificate) : FlowLogic>() { + private val otherSide: Party) : FlowLogic>() { companion object { private fun dependencyIDs(wtx: WireTransaction) = wtx.inputs.map { it.txhash }.toSet() @@ -82,14 +82,14 @@ class ResolveTransactionsFlow(private val txHashes: Set, /** * Resolve the full history of a transaction and verify it with its dependencies. */ - constructor(stx: SignedTransaction, otherSide: PartyAndCertificate) : this(stx.tx, otherSide) { + constructor(stx: SignedTransaction, otherSide: Party) : this(stx.tx, otherSide) { this.stx = stx } /** * Resolve the full history of a transaction and verify it with its dependencies. */ - constructor(wtx: WireTransaction, otherSide: PartyAndCertificate) : this(dependencyIDs(wtx), otherSide) { + constructor(wtx: WireTransaction, otherSide: Party) : this(dependencyIDs(wtx), otherSide) { this.wtx = wtx } diff --git a/core/src/main/kotlin/net/corda/flows/TwoPartyDealFlow.kt b/core/src/main/kotlin/net/corda/flows/TwoPartyDealFlow.kt index 5108f01b3e..45b8694c80 100644 --- a/core/src/main/kotlin/net/corda/flows/TwoPartyDealFlow.kt +++ b/core/src/main/kotlin/net/corda/flows/TwoPartyDealFlow.kt @@ -7,7 +7,6 @@ import net.corda.core.crypto.SecureHash import net.corda.core.flows.FlowLogic import net.corda.core.identity.AbstractParty import net.corda.core.identity.Party -import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.NodeInfo import net.corda.core.node.services.ServiceType import net.corda.core.seconds @@ -46,7 +45,7 @@ object TwoPartyDealFlow { abstract val payload: Any abstract val notaryNode: NodeInfo - abstract val otherParty: PartyAndCertificate + abstract val otherParty: Party abstract val myKey: PublicKey @Suspendable override fun call(): SignedTransaction { @@ -150,7 +149,7 @@ object TwoPartyDealFlow { /** * One side of the flow for inserting a pre-agreed deal. */ - open class Instigator(override val otherParty: PartyAndCertificate, + open class Instigator(override val otherParty: Party, override val payload: AutoOffer, override val myKey: PublicKey, override val progressTracker: ProgressTracker = Primary.tracker()) : Primary() { diff --git a/core/src/test/kotlin/net/corda/core/flows/CollectSignaturesFlowTests.kt b/core/src/test/kotlin/net/corda/core/flows/CollectSignaturesFlowTests.kt index 08c19b7b00..1396799b8c 100644 --- a/core/src/test/kotlin/net/corda/core/flows/CollectSignaturesFlowTests.kt +++ b/core/src/test/kotlin/net/corda/core/flows/CollectSignaturesFlowTests.kt @@ -7,7 +7,6 @@ import net.corda.core.contracts.TransactionType import net.corda.core.contracts.requireThat import net.corda.core.getOrThrow import net.corda.core.identity.Party -import net.corda.core.identity.PartyAndCertificate import net.corda.core.transactions.SignedTransaction import net.corda.core.utilities.unwrap import net.corda.flows.CollectSignaturesFlow @@ -55,7 +54,7 @@ class CollectSignaturesFlowTests { // "collectSignaturesFlow" and "SignTransactionFlow" can be used in practise. object TestFlow { @InitiatingFlow - class Initiator(val state: DummyContract.MultiOwnerState, val otherParty: PartyAndCertificate) : FlowLogic() { + class Initiator(val state: DummyContract.MultiOwnerState, val otherParty: Party) : FlowLogic() { @Suspendable override fun call(): SignedTransaction { send(otherParty, state) @@ -115,7 +114,7 @@ class CollectSignaturesFlowTests { } @InitiatedBy(TestFlowTwo.Initiator::class) - class Responder(val otherParty: PartyAndCertificate) : FlowLogic() { + class Responder(val otherParty: Party) : FlowLogic() { @Suspendable override fun call(): SignedTransaction { val flow = object : SignTransactionFlow(otherParty) { @Suspendable override fun checkTransaction(stx: SignedTransaction) = requireThat { diff --git a/core/src/test/kotlin/net/corda/core/flows/TxKeyFlowTests.kt b/core/src/test/kotlin/net/corda/core/flows/TxKeyFlowTests.kt index 6f6f49182f..7e3cf20b78 100644 --- a/core/src/test/kotlin/net/corda/core/flows/TxKeyFlowTests.kt +++ b/core/src/test/kotlin/net/corda/core/flows/TxKeyFlowTests.kt @@ -3,7 +3,6 @@ package net.corda.core.flows import net.corda.core.getOrThrow import net.corda.core.identity.AbstractParty import net.corda.core.identity.Party -import net.corda.core.identity.PartyAndCertificate import net.corda.core.utilities.ALICE import net.corda.core.utilities.BOB import net.corda.core.utilities.DUMMY_NOTARY @@ -30,12 +29,12 @@ class TxKeyFlowTests { val notaryNode = net.createNotaryNode(null, DUMMY_NOTARY.name) val aliceNode = net.createPartyNode(notaryNode.info.address, ALICE.name) val bobNode = net.createPartyNode(notaryNode.info.address, BOB.name) - val alice: PartyAndCertificate = aliceNode.services.myInfo.legalIdentity - val bob: PartyAndCertificate = bobNode.services.myInfo.legalIdentity - aliceNode.services.identityService.registerIdentity(bob) - aliceNode.services.identityService.registerIdentity(notaryNode.info.legalIdentity) - bobNode.services.identityService.registerIdentity(alice) - bobNode.services.identityService.registerIdentity(notaryNode.info.legalIdentity) + val alice: Party = aliceNode.services.myInfo.legalIdentity + val bob: Party = bobNode.services.myInfo.legalIdentity + aliceNode.services.identityService.registerIdentity(bobNode.info.legalIdentityAndCert) + aliceNode.services.identityService.registerIdentity(notaryNode.info.legalIdentityAndCert) + bobNode.services.identityService.registerIdentity(aliceNode.info.legalIdentityAndCert) + bobNode.services.identityService.registerIdentity(notaryNode.info.legalIdentityAndCert) // Run the flows bobNode.registerInitiatedFlow(TxKeyFlow.Provider::class.java) diff --git a/core/src/test/kotlin/net/corda/core/serialization/AttachmentSerializationTest.kt b/core/src/test/kotlin/net/corda/core/serialization/AttachmentSerializationTest.kt index 4eb871ad5e..2e300844c9 100644 --- a/core/src/test/kotlin/net/corda/core/serialization/AttachmentSerializationTest.kt +++ b/core/src/test/kotlin/net/corda/core/serialization/AttachmentSerializationTest.kt @@ -7,7 +7,6 @@ import net.corda.core.flows.FlowLogic import net.corda.core.flows.InitiatingFlow import net.corda.core.getOrThrow import net.corda.core.identity.Party -import net.corda.core.identity.PartyAndCertificate import net.corda.core.messaging.RPCOps import net.corda.core.messaging.SingleMessageRecipient import net.corda.core.node.services.ServiceInfo @@ -140,7 +139,7 @@ class AttachmentSerializationTest { private fun launchFlow(clientLogic: ClientLogic, rounds: Int) { server.registerFlowFactory(ClientLogic::class.java, object : InitiatedFlowFactory { - override fun createFlow(platformVersion: Int, otherParty: PartyAndCertificate, sessionInit: SessionInit): ServerLogic { + override fun createFlow(platformVersion: Int, otherParty: Party, sessionInit: SessionInit): ServerLogic { return ServerLogic(otherParty) } }, ServerLogic::class.java, track = false) diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index f3ae69dbbf..dc833934c5 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -43,9 +43,9 @@ UNRELEASED * There is a new ``AbstractParty`` superclass to ``Party``, which contains just the public key. This now replaces use of ``Party`` and ``PublicKey`` in state objects, and allows use of full or anonymised parties depending on use-case. - * A new ``PartyAndCertificate`` class has been added which contains an X.509 certificate and certificate path back - to a network trust root. This is widely used in place of ``Party`` inside Corda, with the exception of a few cases - where proof of identity is not required. + * A new ``PartyAndCertificate`` class has been added which aggregates a Party along with an X.509 certificate and + certificate path back to a network trust root. This is used where a Party and its proof of identity are required, + for example in identity registration. * Names of parties are now stored as a ``X500Name`` rather than a ``String``, to correctly enforce basic structure of the name. As a result all node legal names must now be structured as X.500 distinguished names. diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/FxTransactionBuildTutorial.kt b/docs/source/example-code/src/main/kotlin/net/corda/docs/FxTransactionBuildTutorial.kt index 6f7f9e3a24..39b61b1b09 100644 --- a/docs/source/example-code/src/main/kotlin/net/corda/docs/FxTransactionBuildTutorial.kt +++ b/docs/source/example-code/src/main/kotlin/net/corda/docs/FxTransactionBuildTutorial.kt @@ -26,8 +26,8 @@ import java.util.* @CordaSerializable private data class FxRequest(val tradeId: String, val amount: Amount>, - val owner: PartyAndCertificate, - val counterparty: PartyAndCertificate, + val owner: Party, + val counterparty: Party, val notary: Party? = null) @CordaSerializable @@ -103,8 +103,8 @@ private fun prepareOurInputsAndOutputs(serviceHub: ServiceHub, request: FxReques class ForeignExchangeFlow(val tradeId: String, val baseCurrencyAmount: Amount>, val quoteCurrencyAmount: Amount>, - val baseCurrencyBuyer: PartyAndCertificate, - val baseCurrencySeller: PartyAndCertificate) : FlowLogic() { + val baseCurrencyBuyer: Party, + val baseCurrencySeller: Party) : FlowLogic() { @Suspendable override fun call(): SecureHash { // Select correct sides of the Fx exchange to query for. @@ -208,7 +208,7 @@ class ForeignExchangeFlow(val tradeId: String, } @InitiatedBy(ForeignExchangeFlow::class) -class ForeignExchangeRemoteFlow(val source: PartyAndCertificate) : FlowLogic() { +class ForeignExchangeRemoteFlow(val source: Party) : FlowLogic() { @Suspendable override fun call() { // Initial receive from remote party diff --git a/finance/src/main/kotlin/net/corda/contracts/testing/VaultFiller.kt b/finance/src/main/kotlin/net/corda/contracts/testing/VaultFiller.kt index 926b3e7087..09ceff789c 100644 --- a/finance/src/main/kotlin/net/corda/contracts/testing/VaultFiller.kt +++ b/finance/src/main/kotlin/net/corda/contracts/testing/VaultFiller.kt @@ -99,7 +99,7 @@ fun ServiceHub.fillWithSomeTestCash(howMuch: Amount, // We will allocate one state to one transaction, for simplicities sake. val cash = Cash() val transactions: List = amounts.map { pennies -> - val issuance = TransactionType.General.Builder(null) + val issuance = TransactionType.General.Builder(null as Party?) cash.generateIssue(issuance, Amount(pennies, Issued(issuedBy.copy(reference = ref), howMuch.token)), me, outputNotary) issuance.signWith(issuerKey) diff --git a/finance/src/main/kotlin/net/corda/flows/CashExitFlow.kt b/finance/src/main/kotlin/net/corda/flows/CashExitFlow.kt index 734692f751..7ffc67220e 100644 --- a/finance/src/main/kotlin/net/corda/flows/CashExitFlow.kt +++ b/finance/src/main/kotlin/net/corda/flows/CashExitFlow.kt @@ -33,7 +33,7 @@ class CashExitFlow(val amount: Amount, val issueRef: OpaqueBytes, prog @Throws(CashException::class) override fun call(): SignedTransaction { progressTracker.currentStep = GENERATING_TX - val builder: TransactionBuilder = TransactionType.General.Builder(null) + val builder: TransactionBuilder = TransactionType.General.Builder(notary = null as Party?) val issuer = serviceHub.myInfo.legalIdentity.ref(issueRef) val exitStates = serviceHub.vaultService.unconsumedStatesForSpending(amount, setOf(issuer.party), builder.notary, builder.lockId, setOf(issuer.reference)) try { diff --git a/finance/src/main/kotlin/net/corda/flows/CashIssueFlow.kt b/finance/src/main/kotlin/net/corda/flows/CashIssueFlow.kt index d06177783f..479e1a1d6d 100644 --- a/finance/src/main/kotlin/net/corda/flows/CashIssueFlow.kt +++ b/finance/src/main/kotlin/net/corda/flows/CashIssueFlow.kt @@ -35,7 +35,7 @@ class CashIssueFlow(val amount: Amount, @Suspendable override fun call(): SignedTransaction { progressTracker.currentStep = GENERATING_TX - val builder: TransactionBuilder = TransactionType.General.Builder(notary = null) + val builder: TransactionBuilder = TransactionType.General.Builder(notary = notary) val issuer = serviceHub.myInfo.legalIdentity.ref(issueRef) // TODO: Get a transaction key, don't just re-use the owning key Cash().generateIssue(builder, amount.issuedBy(issuer), recipient, notary) diff --git a/finance/src/main/kotlin/net/corda/flows/CashPaymentFlow.kt b/finance/src/main/kotlin/net/corda/flows/CashPaymentFlow.kt index 1e274ac1bb..b7642d24c1 100644 --- a/finance/src/main/kotlin/net/corda/flows/CashPaymentFlow.kt +++ b/finance/src/main/kotlin/net/corda/flows/CashPaymentFlow.kt @@ -30,7 +30,7 @@ open class CashPaymentFlow( @Suspendable override fun call(): SignedTransaction { progressTracker.currentStep = GENERATING_TX - val builder: TransactionBuilder = TransactionType.General.Builder(null) + val builder: TransactionBuilder = TransactionType.General.Builder(null as Party?) // TODO: Have some way of restricting this to states the caller controls val (spendTX, keysForSigning) = try { serviceHub.vaultService.generateSpend( diff --git a/finance/src/main/kotlin/net/corda/flows/TwoPartyTradeFlow.kt b/finance/src/main/kotlin/net/corda/flows/TwoPartyTradeFlow.kt index 9e46dc7f88..bb7f4eda86 100644 --- a/finance/src/main/kotlin/net/corda/flows/TwoPartyTradeFlow.kt +++ b/finance/src/main/kotlin/net/corda/flows/TwoPartyTradeFlow.kt @@ -6,7 +6,7 @@ import net.corda.core.contracts.* import net.corda.core.flows.FlowException import net.corda.core.flows.FlowLogic import net.corda.core.identity.AnonymousParty -import net.corda.core.identity.PartyAndCertificate +import net.corda.core.identity.Party import net.corda.core.node.NodeInfo import net.corda.core.seconds import net.corda.core.serialization.CordaSerializable @@ -52,7 +52,7 @@ object TwoPartyTradeFlow { val sellerOwnerKey: PublicKey ) - open class Seller(val otherParty: PartyAndCertificate, + open class Seller(val otherParty: Party, val notaryNode: NodeInfo, val assetToSell: StateAndRef, val price: Amount, @@ -107,8 +107,8 @@ object TwoPartyTradeFlow { // express flow state machines on top of the messaging layer. } - open class Buyer(val otherParty: PartyAndCertificate, - val notary: PartyAndCertificate, + open class Buyer(val otherParty: Party, + val notary: Party, val acceptablePrice: Amount, val typeToBuy: Class) : FlowLogic() { // DOCSTART 2 @@ -203,4 +203,4 @@ object TwoPartyTradeFlow { } // DOCEND 1 } -} \ No newline at end of file +} diff --git a/finance/src/test/java/net/corda/flows/AbstractStateReplacementFlowTest.java b/finance/src/test/java/net/corda/flows/AbstractStateReplacementFlowTest.java index 4230b63b82..9c8d3086e3 100644 --- a/finance/src/test/java/net/corda/flows/AbstractStateReplacementFlowTest.java +++ b/finance/src/test/java/net/corda/flows/AbstractStateReplacementFlowTest.java @@ -1,7 +1,7 @@ package net.corda.flows; import net.corda.core.identity.Party; -import net.corda.core.identity.PartyAndCertificate; +import net.corda.core.identity.Party; import net.corda.core.utilities.*; import org.jetbrains.annotations.*; @@ -10,7 +10,7 @@ public class AbstractStateReplacementFlowTest { // Acceptor used to have a type parameter of Unit which prevented Java code from subclassing it (https://youtrack.jetbrains.com/issue/KT-15964). private static class TestAcceptorCanBeInheritedInJava extends AbstractStateReplacementFlow.Acceptor { - public TestAcceptorCanBeInheritedInJava(@NotNull PartyAndCertificate otherSide, @NotNull ProgressTracker progressTracker) { + public TestAcceptorCanBeInheritedInJava(@NotNull Party otherSide, @NotNull ProgressTracker progressTracker) { super(otherSide, progressTracker); } @@ -18,4 +18,4 @@ public class AbstractStateReplacementFlowTest { protected void verifyProposal(@NotNull AbstractStateReplacementFlow.Proposal proposal) { } } -} \ No newline at end of file +} diff --git a/node/src/main/kotlin/net/corda/node/driver/Driver.kt b/node/src/main/kotlin/net/corda/node/driver/Driver.kt index 954d5b8590..14f648fa36 100644 --- a/node/src/main/kotlin/net/corda/node/driver/Driver.kt +++ b/node/src/main/kotlin/net/corda/node/driver/Driver.kt @@ -14,7 +14,6 @@ import net.corda.core.crypto.X509Utilities import net.corda.core.crypto.appendToCommonName import net.corda.core.crypto.commonName import net.corda.core.identity.Party -import net.corda.core.identity.PartyAndCertificate import net.corda.core.internal.ShutdownHook import net.corda.core.internal.addShutdownHook import net.corda.core.messaging.CordaRPCOps @@ -97,7 +96,7 @@ interface DriverDSLExposedInterface : CordformContext { clusterSize: Int = 3, type: ServiceType = RaftValidatingNotaryService.type, verifierType: VerifierType = VerifierType.InMemory, - rpcUsers: List = emptyList()): Future>> + rpcUsers: List = emptyList()): Future>> /** * Starts a web server for a node @@ -562,7 +561,7 @@ class DriverDSL( type: ServiceType, verifierType: VerifierType, rpcUsers: List - ): ListenableFuture>> { + ): ListenableFuture>> { val nodeNames = (0 until clusterSize).map { DUMMY_NOTARY.name.appendToCommonName(" $it") } val paths = nodeNames.map { baseDirectory(it) } ServiceIdentityGenerator.generateToDisk(paths, DUMMY_CA, type.id, notaryName) diff --git a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt index 51d10caacb..353b15a551 100644 --- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt @@ -349,13 +349,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, } private fun > registerInitiatedFlowInternal(initiatedFlow: Class, track: Boolean): Observable { - val ctor = try { - initiatedFlow.getDeclaredConstructor(PartyAndCertificate::class.java).apply { isAccessible = true } - } catch(ex: NoSuchMethodException) { - // Fall back to a constructor that takes in a Party - // TODO: Consider removing for 1.0 release, as flows should generally take the more detailed class - initiatedFlow.getDeclaredConstructor(Party::class.java).apply { isAccessible = true } - } + val ctor = initiatedFlow.getDeclaredConstructor(Party::class.java).apply { isAccessible = true } val initiatingFlow = initiatedFlow.requireAnnotation().value.java val (version, classWithAnnotation) = initiatingFlow.flowVersionAndInitiatingClass require(classWithAnnotation == initiatingFlow) { @@ -403,7 +397,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, * @suppress */ @VisibleForTesting - fun installCoreFlow(clientFlowClass: KClass>, flowFactory: (PartyAndCertificate, Int) -> FlowLogic<*>) { + fun installCoreFlow(clientFlowClass: KClass>, flowFactory: (Party, Int) -> FlowLogic<*>) { require(clientFlowClass.java.flowVersionAndInitiatingClass.first == 1) { "${InitiatingFlow::class.java.name}.version not applicable for core flows; their version is the node's platform version" } @@ -667,13 +661,12 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, protected open fun makeIdentityService(): IdentityService { val keyStore = KeyStoreUtilities.loadKeyStore(configuration.trustStoreFile, configuration.trustStorePassword) val trustRoot = keyStore.getCertificate(X509Utilities.CORDA_ROOT_CA) as? X509Certificate - val service = InMemoryIdentityService(trustRoot = trustRoot) - service.registerIdentity(info.legalIdentity) - services.networkMapCache.partyNodes.forEach { service.registerIdentity(it.legalIdentity) } + val service = InMemoryIdentityService(setOf(info.legalIdentityAndCert), trustRoot = trustRoot) + services.networkMapCache.partyNodes.forEach { service.registerIdentity(it.legalIdentityAndCert) } netMapCache.changed.subscribe { mapChange -> // TODO how should we handle network map removal if (mapChange is MapChange.Added) { - service.registerIdentity(mapChange.node.legalIdentity) + service.registerIdentity(mapChange.node.legalIdentityAndCert) } } return service diff --git a/node/src/main/kotlin/net/corda/node/internal/InitiatedFlowFactory.kt b/node/src/main/kotlin/net/corda/node/internal/InitiatedFlowFactory.kt index 6bbe03e9bc..06a0a7cc61 100644 --- a/node/src/main/kotlin/net/corda/node/internal/InitiatedFlowFactory.kt +++ b/node/src/main/kotlin/net/corda/node/internal/InitiatedFlowFactory.kt @@ -2,20 +2,19 @@ package net.corda.node.internal import net.corda.core.flows.FlowLogic import net.corda.core.identity.Party -import net.corda.core.identity.PartyAndCertificate import net.corda.node.services.statemachine.SessionInit interface InitiatedFlowFactory> { - fun createFlow(platformVersion: Int, otherParty: PartyAndCertificate, sessionInit: SessionInit): F + fun createFlow(platformVersion: Int, otherParty: Party, sessionInit: SessionInit): F - data class Core>(val factory: (PartyAndCertificate, Int) -> F) : InitiatedFlowFactory { - override fun createFlow(platformVersion: Int, otherParty: PartyAndCertificate, sessionInit: SessionInit): F { + data class Core>(val factory: (Party, Int) -> F) : InitiatedFlowFactory { + override fun createFlow(platformVersion: Int, otherParty: Party, sessionInit: SessionInit): F { return factory(otherParty, platformVersion) } } data class CorDapp>(val version: Int, val factory: (Party) -> F) : InitiatedFlowFactory { - override fun createFlow(platformVersion: Int, otherParty: PartyAndCertificate, sessionInit: SessionInit): F { + override fun createFlow(platformVersion: Int, otherParty: Party, sessionInit: SessionInit): F { // TODO Add support for multiple versions of the same flow when CorDapps are loaded in separate class loaders if (sessionInit.flowVerison == version) return factory(otherParty) throw SessionRejectException( diff --git a/node/src/main/kotlin/net/corda/node/services/CoreFlowHandlers.kt b/node/src/main/kotlin/net/corda/node/services/CoreFlowHandlers.kt index b05cd06952..e6b8c0e6e9 100644 --- a/node/src/main/kotlin/net/corda/node/services/CoreFlowHandlers.kt +++ b/node/src/main/kotlin/net/corda/node/services/CoreFlowHandlers.kt @@ -9,7 +9,6 @@ import net.corda.core.crypto.SecureHash import net.corda.core.flows.FlowException import net.corda.core.flows.FlowLogic import net.corda.core.identity.Party -import net.corda.core.identity.PartyAndCertificate import net.corda.core.transactions.SignedTransaction import net.corda.core.utilities.unwrap import net.corda.flows.* @@ -26,20 +25,20 @@ import net.corda.flows.* * * Additionally, because nodes do not store invalid transactions, requesting such a transaction will always yield null. */ -class FetchTransactionsHandler(otherParty: PartyAndCertificate) : FetchDataHandler(otherParty) { +class FetchTransactionsHandler(otherParty: Party) : FetchDataHandler(otherParty) { override fun getData(id: SecureHash): SignedTransaction? { return serviceHub.storageService.validatedTransactions.getTransaction(id) } } // TODO: Use Artemis message streaming support here, called "large messages". This avoids the need to buffer. -class FetchAttachmentsHandler(otherParty: PartyAndCertificate) : FetchDataHandler(otherParty) { +class FetchAttachmentsHandler(otherParty: Party) : FetchDataHandler(otherParty) { override fun getData(id: SecureHash): ByteArray? { return serviceHub.storageService.attachments.openAttachment(id)?.open()?.readBytes() } } -abstract class FetchDataHandler(val otherParty: PartyAndCertificate) : FlowLogic() { +abstract class FetchDataHandler(val otherParty: Party) : FlowLogic() { @Suspendable @Throws(FetchDataFlow.HashNotFound::class) override fun call() { @@ -60,7 +59,7 @@ abstract class FetchDataHandler(val otherParty: PartyAndCertificate) : Fl // includes us in any outside that list. Potentially just if it includes any outside that list at all. // TODO: Do we want to be able to reject specific transactions on more complex rules, for example reject incoming // cash without from unknown parties? -class NotifyTransactionHandler(val otherParty: PartyAndCertificate) : FlowLogic() { +class NotifyTransactionHandler(val otherParty: Party) : FlowLogic() { @Suspendable override fun call() { val request = receive(otherParty).unwrap { it } @@ -69,7 +68,7 @@ class NotifyTransactionHandler(val otherParty: PartyAndCertificate) : FlowLogic< } } -class NotaryChangeHandler(otherSide: PartyAndCertificate) : AbstractStateReplacementFlow.Acceptor(otherSide) { +class NotaryChangeHandler(otherSide: Party) : AbstractStateReplacementFlow.Acceptor(otherSide) { /** * Check the notary change proposal. * @@ -77,7 +76,7 @@ class NotaryChangeHandler(otherSide: PartyAndCertificate) : AbstractStateReplace * and is also in a geographically convenient location we can just automatically approve the change. * TODO: In more difficult cases this should call for human attention to manually verify and approve the proposal */ - override fun verifyProposal(proposal: AbstractStateReplacementFlow.Proposal): Unit { + override fun verifyProposal(proposal: AbstractStateReplacementFlow.Proposal): Unit { val state = proposal.stateRef val proposedTx = proposal.stx.tx @@ -102,7 +101,7 @@ class NotaryChangeHandler(otherSide: PartyAndCertificate) : AbstractStateReplace } } -class ContractUpgradeHandler(otherSide: PartyAndCertificate) : AbstractStateReplacementFlow.Acceptor>>(otherSide) { +class ContractUpgradeHandler(otherSide: Party) : AbstractStateReplacementFlow.Acceptor>>(otherSide) { @Suspendable @Throws(StateReplacementException::class) override fun verifyProposal(proposal: AbstractStateReplacementFlow.Proposal>>) { diff --git a/node/src/main/kotlin/net/corda/node/services/identity/InMemoryIdentityService.kt b/node/src/main/kotlin/net/corda/node/services/identity/InMemoryIdentityService.kt index 92fbe5adb6..ad8742f9fa 100644 --- a/node/src/main/kotlin/net/corda/node/services/identity/InMemoryIdentityService.kt +++ b/node/src/main/kotlin/net/corda/node/services/identity/InMemoryIdentityService.kt @@ -4,10 +4,7 @@ import net.corda.core.contracts.PartyAndReference import net.corda.core.contracts.requireThat import net.corda.core.crypto.subject import net.corda.core.crypto.toStringShort -import net.corda.core.identity.AbstractParty -import net.corda.core.identity.AnonymousParty -import net.corda.core.identity.Party -import net.corda.core.identity.PartyAndCertificate +import net.corda.core.identity.* import net.corda.core.node.services.IdentityService import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.core.utilities.loggerFor @@ -29,7 +26,7 @@ import javax.annotation.concurrent.ThreadSafe * @param certPaths initial set of certificate paths for the service, typically only used for unit tests. */ @ThreadSafe -class InMemoryIdentityService(identities: Iterable = emptySet(), +class InMemoryIdentityService(identities: Iterable, certPaths: Map = emptyMap(), val trustRoot: X509Certificate?) : SingletonSerializeAsToken(), IdentityService { constructor(identities: Iterable = emptySet(), @@ -50,7 +47,7 @@ class InMemoryIdentityService(identities: Iterable = emptyS partyToPath.putAll(certPaths) } - // TODO: Check the validation logic + // TODO: Check the certificate validation logic @Throws(CertificateExpiredException::class, CertificateNotYetValidException::class, InvalidAlgorithmParameterException::class) override fun registerIdentity(party: PartyAndCertificate) { require(party.certPath.certificates.isNotEmpty()) { "Certificate path must contain at least one certificate" } @@ -72,20 +69,22 @@ class InMemoryIdentityService(identities: Iterable = emptyS log.trace { "Registering identity $party" } require(Arrays.equals(party.certificate.subjectPublicKeyInfo.encoded, party.owningKey.encoded)) { "Party certificate must end with party's public key" } - partyToPath[party] = party.certPath + partyToPath[party.party] = party.certPath keyToParties[party.owningKey] = party principalToParties[party.name] = party } - // We give the caller a copy of the data set to avoid any locking problems - override fun getAllIdentities(): Iterable = ArrayList(keyToParties.values) + override fun certificateFromParty(party: Party): PartyAndCertificate? = principalToParties[party.name] - override fun partyFromKey(key: PublicKey): PartyAndCertificate? = keyToParties[key] + // We give the caller a copy of the data set to avoid any locking problems + override fun getAllIdentities(): Iterable = ArrayList(keyToParties.values) + + override fun partyFromKey(key: PublicKey): Party? = keyToParties[key]?.party @Deprecated("Use partyFromX500Name") - override fun partyFromName(name: String): PartyAndCertificate? = principalToParties[X500Name(name)] - override fun partyFromX500Name(principal: X500Name): PartyAndCertificate? = principalToParties[principal] - override fun partyFromAnonymous(party: AbstractParty): PartyAndCertificate? { - return if (party is PartyAndCertificate) { + override fun partyFromName(name: String): Party? = principalToParties[X500Name(name)]?.party + override fun partyFromX500Name(principal: X500Name): Party? = principalToParties[principal]?.party + override fun partyFromAnonymous(party: AbstractParty): Party? { + return if (party is Party) { party } else { partyFromKey(party.owningKey) @@ -112,7 +111,8 @@ class InMemoryIdentityService(identities: Iterable = emptyS override fun pathForAnonymous(anonymousParty: AnonymousParty): CertPath? = partyToPath[anonymousParty] @Throws(CertificateExpiredException::class, CertificateNotYetValidException::class, InvalidAlgorithmParameterException::class) - override fun registerAnonymousIdentity(anonymousParty: AnonymousParty, fullParty: PartyAndCertificate, path: CertPath) { + override fun registerAnonymousIdentity(anonymousParty: AnonymousParty, party: Party, path: CertPath) { + val fullParty = certificateFromParty(party) ?: throw IllegalArgumentException("Unknown identity ${party.name}") require(path.certificates.isNotEmpty()) { "Certificate path must contain at least one certificate" } // Validate the chain first, before we do anything clever with it val validator = CertPathValidator.getInstance("PKIX") diff --git a/node/src/main/kotlin/net/corda/node/services/keys/KMSUtils.kt b/node/src/main/kotlin/net/corda/node/services/keys/KMSUtils.kt index 2da401e08d..35f29829be 100644 --- a/node/src/main/kotlin/net/corda/node/services/keys/KMSUtils.kt +++ b/node/src/main/kotlin/net/corda/node/services/keys/KMSUtils.kt @@ -41,7 +41,7 @@ fun freshCertificate(identityService: IdentityService, val ourCertPath = X509Utilities.createCertificatePath(issuerCertificate, ourCertificate, revocationEnabled = revocationEnabled) require(Arrays.equals(ourCertificate.subjectPublicKeyInfo.encoded, subjectPublicKey.encoded)) identityService.registerAnonymousIdentity(AnonymousParty(subjectPublicKey), - issuer, + issuer.party, ourCertPath) return Pair(issuerCertificate, ourCertPath) } @@ -50,4 +50,4 @@ fun getSigner(issuerKeyPair: KeyPair): ContentSigner { val signatureScheme = Crypto.findSignatureScheme(issuerKeyPair.private) val provider = Security.getProvider(signatureScheme.providerName) return ContentSignerBuilder.build(signatureScheme, issuerKeyPair.private, provider) -} \ No newline at end of file +} diff --git a/node/src/main/kotlin/net/corda/node/services/network/InMemoryNetworkMapCache.kt b/node/src/main/kotlin/net/corda/node/services/network/InMemoryNetworkMapCache.kt index ced6e6b972..1f996b00d9 100644 --- a/node/src/main/kotlin/net/corda/node/services/network/InMemoryNetworkMapCache.kt +++ b/node/src/main/kotlin/net/corda/node/services/network/InMemoryNetworkMapCache.kt @@ -61,7 +61,7 @@ open class InMemoryNetworkMapCache : SingletonSerializeAsToken(), NetworkMapCach } for ((_, value) in registeredNodes) { for (service in value.advertisedServices) { - if (service.identity == party) { + if (service.identity.party == party) { return PartyInfo.Service(service) } } diff --git a/node/src/main/kotlin/net/corda/node/services/network/NetworkMapService.kt b/node/src/main/kotlin/net/corda/node/services/network/NetworkMapService.kt index 6de2164a04..133b674307 100644 --- a/node/src/main/kotlin/net/corda/node/services/network/NetworkMapService.kt +++ b/node/src/main/kotlin/net/corda/node/services/network/NetworkMapService.kt @@ -5,7 +5,6 @@ import net.corda.core.ThreadBox import net.corda.core.crypto.DigitalSignature import net.corda.core.crypto.SignedData import net.corda.core.crypto.isFulfilledBy -import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate import net.corda.core.messaging.MessageRecipients import net.corda.core.messaging.SingleMessageRecipient @@ -83,7 +82,7 @@ interface NetworkMapService { @CordaSerializable data class FetchMapResponse(val nodes: List?, val version: Int) - data class QueryIdentityRequest(val identity: Party, + data class QueryIdentityRequest(val identity: PartyAndCertificate, override val replyTo: SingleMessageRecipient, override val sessionID: Long = random63BitValue()) : ServiceRequestMessage @@ -253,7 +252,7 @@ abstract class AbstractNetworkMapService(services: ServiceHubInternal, // in on different threads, there is no risk of a race condition while checking // sequence numbers. val registrationInfo = try { - nodeRegistrations.compute(node.legalIdentity) { _, existing: NodeRegistrationInfo? -> + nodeRegistrations.compute(node.legalIdentityAndCert) { _, existing: NodeRegistrationInfo? -> require(!((existing == null || existing.reg.type == REMOVE) && change.type == REMOVE)) { "Attempting to de-register unknown node" } diff --git a/node/src/main/kotlin/net/corda/node/services/statemachine/StateMachineManager.kt b/node/src/main/kotlin/net/corda/node/services/statemachine/StateMachineManager.kt index 159e833e8b..db7d34b490 100644 --- a/node/src/main/kotlin/net/corda/node/services/statemachine/StateMachineManager.kt +++ b/node/src/main/kotlin/net/corda/node/services/statemachine/StateMachineManager.kt @@ -18,7 +18,6 @@ import net.corda.core.* import net.corda.core.crypto.SecureHash import net.corda.core.flows.* import net.corda.core.identity.Party -import net.corda.core.identity.PartyAndCertificate import net.corda.core.serialization.* import net.corda.core.utilities.debug import net.corda.core.utilities.loggerFor @@ -340,7 +339,7 @@ class StateMachineManager(val serviceHub: ServiceHubInternal, waitingForResponse is WaitForLedgerCommit && message is ErrorSessionEnd } - private fun onSessionInit(sessionInit: SessionInit, receivedMessage: ReceivedMessage, sender: PartyAndCertificate) { + private fun onSessionInit(sessionInit: SessionInit, receivedMessage: ReceivedMessage, sender: Party) { logger.trace { "Received $sessionInit from $sender" } val otherPartySessionId = sessionInit.initiatorSessionId diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/BFTNonValidatingNotaryService.kt b/node/src/main/kotlin/net/corda/node/services/transactions/BFTNonValidatingNotaryService.kt index f02fd34fcc..c039689d50 100644 --- a/node/src/main/kotlin/net/corda/node/services/transactions/BFTNonValidatingNotaryService.kt +++ b/node/src/main/kotlin/net/corda/node/services/transactions/BFTNonValidatingNotaryService.kt @@ -3,7 +3,7 @@ package net.corda.node.services.transactions import co.paralleluniverse.fibers.Suspendable import net.corda.core.crypto.DigitalSignature import net.corda.core.flows.FlowLogic -import net.corda.core.identity.PartyAndCertificate +import net.corda.core.identity.Party import net.corda.core.node.services.TimeWindowChecker import net.corda.core.serialization.deserialize import net.corda.core.serialization.serialize @@ -42,11 +42,11 @@ class BFTNonValidatingNotaryService(config: BFTSMaRtConfig, private val log = loggerFor() } - override val serviceFlowFactory: (PartyAndCertificate, Int) -> FlowLogic = { otherParty, _ -> + override val serviceFlowFactory: (Party, Int) -> FlowLogic = { otherParty, _ -> ServiceFlow(otherParty, client) } - private class ServiceFlow(val otherSide: PartyAndCertificate, val client: BFTSMaRt.Client) : FlowLogic() { + private class ServiceFlow(val otherSide: Party, val client: BFTSMaRt.Client) : FlowLogic() { @Suspendable override fun call(): Void? { val stx = receive(otherSide).unwrap { it } @@ -81,7 +81,7 @@ class BFTNonValidatingNotaryService(config: BFTSMaRtConfig, return response.serialize().bytes } - fun verifyAndCommitTx(ftx: FilteredTransaction, callerIdentity: PartyAndCertificate): BFTSMaRt.ReplicaResponse { + fun verifyAndCommitTx(ftx: FilteredTransaction, callerIdentity: Party): BFTSMaRt.ReplicaResponse { return try { val id = ftx.rootHash val inputs = ftx.filteredLeaves.inputs diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/BFTSMaRt.kt b/node/src/main/kotlin/net/corda/node/services/transactions/BFTSMaRt.kt index 5596f61d6f..795a129665 100644 --- a/node/src/main/kotlin/net/corda/node/services/transactions/BFTSMaRt.kt +++ b/node/src/main/kotlin/net/corda/node/services/transactions/BFTSMaRt.kt @@ -13,7 +13,7 @@ import net.corda.core.crypto.DigitalSignature import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SignedData import net.corda.core.crypto.sign -import net.corda.core.identity.PartyAndCertificate +import net.corda.core.identity.Party import net.corda.core.node.services.TimeWindowChecker import net.corda.core.node.services.UniquenessProvider import net.corda.core.serialization.CordaSerializable @@ -51,7 +51,7 @@ import java.util.* object BFTSMaRt { /** Sent from [Client] to [Server]. */ @CordaSerializable - data class CommitRequest(val tx: Any, val callerIdentity: PartyAndCertificate) + data class CommitRequest(val tx: Any, val callerIdentity: Party) /** Sent from [Server] to [Client]. */ @CordaSerializable @@ -83,7 +83,7 @@ object BFTSMaRt { * Sends a transaction commit request to the BFT cluster. The [proxy] will deliver the request to every * replica, and block until a sufficient number of replies are received. */ - fun commitTransaction(transaction: Any, otherSide: PartyAndCertificate): ClusterResponse { + fun commitTransaction(transaction: Any, otherSide: Party): ClusterResponse { require(transaction is FilteredTransaction || transaction is SignedTransaction) { "Unsupported transaction type: ${transaction.javaClass.name}" } val request = CommitRequest(transaction, otherSide) val responseBytes = proxy.invokeOrdered(request.serialize().bytes) @@ -178,7 +178,7 @@ object BFTSMaRt { */ abstract fun executeCommand(command: ByteArray): ByteArray? - protected fun commitInputStates(states: List, txId: SecureHash, callerIdentity: PartyAndCertificate) { + protected fun commitInputStates(states: List, txId: SecureHash, callerIdentity: Party) { log.debug { "Attempting to commit inputs for transaction: $txId" } val conflicts = mutableMapOf() db.transaction { diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/NonValidatingNotaryFlow.kt b/node/src/main/kotlin/net/corda/node/services/transactions/NonValidatingNotaryFlow.kt index 942db3008f..470ad66a8e 100644 --- a/node/src/main/kotlin/net/corda/node/services/transactions/NonValidatingNotaryFlow.kt +++ b/node/src/main/kotlin/net/corda/node/services/transactions/NonValidatingNotaryFlow.kt @@ -1,7 +1,7 @@ package net.corda.node.services.transactions import co.paralleluniverse.fibers.Suspendable -import net.corda.core.identity.PartyAndCertificate +import net.corda.core.identity.Party import net.corda.core.node.services.TimeWindowChecker import net.corda.core.node.services.UniquenessProvider import net.corda.core.transactions.FilteredTransaction @@ -9,7 +9,7 @@ import net.corda.core.utilities.unwrap import net.corda.flows.NotaryFlow import net.corda.flows.TransactionParts -class NonValidatingNotaryFlow(otherSide: PartyAndCertificate, +class NonValidatingNotaryFlow(otherSide: Party, timeWindowChecker: TimeWindowChecker, uniquenessProvider: UniquenessProvider) : NotaryFlow.Service(otherSide, timeWindowChecker, uniquenessProvider) { /** @@ -28,4 +28,4 @@ class NonValidatingNotaryFlow(otherSide: PartyAndCertificate, } return TransactionParts(ftx.rootHash, ftx.filteredLeaves.inputs, ftx.filteredLeaves.timeWindow) } -} \ No newline at end of file +} diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/NotaryService.kt b/node/src/main/kotlin/net/corda/node/services/transactions/NotaryService.kt index 888026bf1a..9abef4eb50 100644 --- a/node/src/main/kotlin/net/corda/node/services/transactions/NotaryService.kt +++ b/node/src/main/kotlin/net/corda/node/services/transactions/NotaryService.kt @@ -2,15 +2,14 @@ package net.corda.node.services.transactions import net.corda.core.flows.FlowLogic import net.corda.core.identity.Party -import net.corda.core.identity.PartyAndCertificate interface NotaryService { /** * Factory for producing notary service flows which have the corresponding sends and receives as NotaryFlow.Client. - * The first parameter is the client [PartyAndCertificate] making the request and the second is the platform version + * The first parameter is the client [Party] making the request and the second is the platform version * of the client's node. Use this version parameter to provide backwards compatibility if the notary flow protocol * changes. */ - val serviceFlowFactory: (PartyAndCertificate, Int) -> FlowLogic + val serviceFlowFactory: (Party, Int) -> FlowLogic } diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/RaftNonValidatingNotaryService.kt b/node/src/main/kotlin/net/corda/node/services/transactions/RaftNonValidatingNotaryService.kt index e584dd9edb..614dfdeb36 100644 --- a/node/src/main/kotlin/net/corda/node/services/transactions/RaftNonValidatingNotaryService.kt +++ b/node/src/main/kotlin/net/corda/node/services/transactions/RaftNonValidatingNotaryService.kt @@ -1,7 +1,7 @@ package net.corda.node.services.transactions import net.corda.core.flows.FlowLogic -import net.corda.core.identity.PartyAndCertificate +import net.corda.core.identity.Party import net.corda.core.node.services.TimeWindowChecker /** A non-validating notary service operated by a group of mutually trusting parties, uses the Raft algorithm to achieve consensus. */ @@ -11,7 +11,7 @@ class RaftNonValidatingNotaryService(val timeWindowChecker: TimeWindowChecker, val type = SimpleNotaryService.type.getSubType("raft") } - override val serviceFlowFactory: (PartyAndCertificate, Int) -> FlowLogic = { otherParty, _ -> + override val serviceFlowFactory: (Party, Int) -> FlowLogic = { otherParty, _ -> NonValidatingNotaryFlow(otherParty, timeWindowChecker, uniquenessProvider) } } diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/RaftValidatingNotaryService.kt b/node/src/main/kotlin/net/corda/node/services/transactions/RaftValidatingNotaryService.kt index d78899231c..ff0217d12d 100644 --- a/node/src/main/kotlin/net/corda/node/services/transactions/RaftValidatingNotaryService.kt +++ b/node/src/main/kotlin/net/corda/node/services/transactions/RaftValidatingNotaryService.kt @@ -1,7 +1,7 @@ package net.corda.node.services.transactions import net.corda.core.flows.FlowLogic -import net.corda.core.identity.PartyAndCertificate +import net.corda.core.identity.Party import net.corda.core.node.services.TimeWindowChecker /** A validating notary service operated by a group of mutually trusting parties, uses the Raft algorithm to achieve consensus. */ @@ -11,7 +11,7 @@ class RaftValidatingNotaryService(val timeWindowChecker: TimeWindowChecker, val type = ValidatingNotaryService.type.getSubType("raft") } - override val serviceFlowFactory: (PartyAndCertificate, Int) -> FlowLogic = { otherParty, _ -> + override val serviceFlowFactory: (Party, Int) -> FlowLogic = { otherParty, _ -> ValidatingNotaryFlow(otherParty, timeWindowChecker, uniquenessProvider) } } diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/SimpleNotaryService.kt b/node/src/main/kotlin/net/corda/node/services/transactions/SimpleNotaryService.kt index 924f5f2190..5ac707bc9e 100644 --- a/node/src/main/kotlin/net/corda/node/services/transactions/SimpleNotaryService.kt +++ b/node/src/main/kotlin/net/corda/node/services/transactions/SimpleNotaryService.kt @@ -1,7 +1,7 @@ package net.corda.node.services.transactions import net.corda.core.flows.FlowLogic -import net.corda.core.identity.PartyAndCertificate +import net.corda.core.identity.Party import net.corda.core.node.services.ServiceType import net.corda.core.node.services.TimeWindowChecker import net.corda.core.node.services.UniquenessProvider @@ -13,7 +13,7 @@ class SimpleNotaryService(val timeWindowChecker: TimeWindowChecker, val type = ServiceType.notary.getSubType("simple") } - override val serviceFlowFactory: (PartyAndCertificate, Int) -> FlowLogic = { otherParty, _ -> + override val serviceFlowFactory: (Party, Int) -> FlowLogic = { otherParty, _ -> NonValidatingNotaryFlow(otherParty, timeWindowChecker, uniquenessProvider) } } diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/ValidatingNotaryFlow.kt b/node/src/main/kotlin/net/corda/node/services/transactions/ValidatingNotaryFlow.kt index 915412e2a9..d30180db05 100644 --- a/node/src/main/kotlin/net/corda/node/services/transactions/ValidatingNotaryFlow.kt +++ b/node/src/main/kotlin/net/corda/node/services/transactions/ValidatingNotaryFlow.kt @@ -2,7 +2,7 @@ package net.corda.node.services.transactions import co.paralleluniverse.fibers.Suspendable import net.corda.core.contracts.TransactionVerificationException -import net.corda.core.identity.PartyAndCertificate +import net.corda.core.identity.Party import net.corda.core.node.services.TimeWindowChecker import net.corda.core.node.services.UniquenessProvider import net.corda.core.transactions.SignedTransaction @@ -17,7 +17,7 @@ import java.security.SignatureException * has its input states "blocked" by a transaction from another party, and needs to establish whether that transaction was * indeed valid. */ -class ValidatingNotaryFlow(otherSide: PartyAndCertificate, +class ValidatingNotaryFlow(otherSide: Party, timeWindowChecker: TimeWindowChecker, uniquenessProvider: UniquenessProvider) : NotaryFlow.Service(otherSide, timeWindowChecker, uniquenessProvider) { diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/ValidatingNotaryService.kt b/node/src/main/kotlin/net/corda/node/services/transactions/ValidatingNotaryService.kt index c18b8792ff..72b819e90a 100644 --- a/node/src/main/kotlin/net/corda/node/services/transactions/ValidatingNotaryService.kt +++ b/node/src/main/kotlin/net/corda/node/services/transactions/ValidatingNotaryService.kt @@ -1,7 +1,7 @@ package net.corda.node.services.transactions import net.corda.core.flows.FlowLogic -import net.corda.core.identity.PartyAndCertificate +import net.corda.core.identity.Party import net.corda.core.node.services.ServiceType import net.corda.core.node.services.TimeWindowChecker import net.corda.core.node.services.UniquenessProvider @@ -13,7 +13,7 @@ class ValidatingNotaryService(val timeWindowChecker: TimeWindowChecker, val type = ServiceType.notary.getSubType("validating") } - override val serviceFlowFactory: (PartyAndCertificate, Int) -> FlowLogic = { otherParty, _ -> + override val serviceFlowFactory: (Party, Int) -> FlowLogic = { otherParty, _ -> ValidatingNotaryFlow(otherParty, timeWindowChecker, uniquenessProvider) } } diff --git a/node/src/main/kotlin/net/corda/node/utilities/DatabaseSupport.kt b/node/src/main/kotlin/net/corda/node/utilities/DatabaseSupport.kt index 4dd0222894..83c675a7b6 100644 --- a/node/src/main/kotlin/net/corda/node/utilities/DatabaseSupport.kt +++ b/node/src/main/kotlin/net/corda/node/utilities/DatabaseSupport.kt @@ -6,6 +6,7 @@ import com.zaxxer.hikari.HikariDataSource import net.corda.core.crypto.SecureHash import net.corda.core.crypto.parsePublicKeyBase58 import net.corda.core.crypto.toBase58String +import net.corda.core.identity.PartyAndCertificate import net.corda.node.utilities.StrandLocalTransactionManager.Boundary import org.bouncycastle.cert.X509CertificateHolder import org.h2.jdbc.JdbcBlob @@ -284,9 +285,9 @@ fun Table.secureHash(name: String) = this.registerColumn(name, Secur fun Table.party(nameColumnName: String, keyColumnName: String) = PartyColumns(this.varchar(nameColumnName, length = 255), this.publicKey(keyColumnName)) fun Table.partyAndCertificate(nameColumnName: String, - keyColumnName: String, - certificateColumnName: String, - pathColumnName: String) = PartyAndCertificateColumns(this.varchar(nameColumnName, length = 255), this.publicKey(keyColumnName), + keyColumnName: String, + certificateColumnName: String, + pathColumnName: String) = PartyAndCertificateColumns(this.varchar(nameColumnName, length = 255), this.publicKey(keyColumnName), this.certificate(certificateColumnName), this.certificatePath(pathColumnName)) fun Table.uuidString(name: String) = this.registerColumn(name, UUIDStringColumnType) fun Table.localDate(name: String) = this.registerColumn(name, LocalDateColumnType) diff --git a/node/src/main/kotlin/net/corda/node/utilities/ServiceIdentityGenerator.kt b/node/src/main/kotlin/net/corda/node/utilities/ServiceIdentityGenerator.kt index 21e535e51e..2ffb871dba 100644 --- a/node/src/main/kotlin/net/corda/node/utilities/ServiceIdentityGenerator.kt +++ b/node/src/main/kotlin/net/corda/node/utilities/ServiceIdentityGenerator.kt @@ -1,7 +1,9 @@ package net.corda.node.utilities -import net.corda.core.crypto.* -import net.corda.core.identity.Party +import net.corda.core.crypto.CertificateAndKeyPair +import net.corda.core.crypto.CompositeKey +import net.corda.core.crypto.X509Utilities +import net.corda.core.crypto.generateKeyPair import net.corda.core.identity.PartyAndCertificate import net.corda.core.serialization.serialize import net.corda.core.serialization.storageKryo diff --git a/node/src/test/kotlin/net/corda/node/InteractiveShellTest.kt b/node/src/test/kotlin/net/corda/node/InteractiveShellTest.kt index 44343cb469..e43f6c29a7 100644 --- a/node/src/test/kotlin/net/corda/node/InteractiveShellTest.kt +++ b/node/src/test/kotlin/net/corda/node/InteractiveShellTest.kt @@ -17,6 +17,7 @@ import net.corda.jackson.JacksonSupport import net.corda.node.services.identity.InMemoryIdentityService import net.corda.node.shell.InteractiveShell import net.corda.testing.MEGA_CORP +import net.corda.testing.MEGA_CORP_IDENTITY import org.junit.Test import org.slf4j.Logger import java.util.* @@ -33,7 +34,7 @@ class InteractiveShellTest { override fun call() = a } - private val ids = InMemoryIdentityService(listOf(MEGA_CORP), trustRoot = DUMMY_CA.certificate) + private val ids = InMemoryIdentityService(listOf(MEGA_CORP_IDENTITY), trustRoot = DUMMY_CA.certificate) private val om = JacksonSupport.createInMemoryMapper(ids, YAMLFactory()) private fun check(input: String, expected: String) { diff --git a/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt b/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt index 5f4be70568..e74528b80c 100644 --- a/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt +++ b/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt @@ -13,8 +13,6 @@ import net.corda.core.flows.* import net.corda.core.identity.AbstractParty import net.corda.core.identity.AnonymousParty import net.corda.core.identity.Party -import net.corda.core.identity.PartyAndCertificate -import net.corda.core.map import net.corda.core.messaging.SingleMessageRecipient import net.corda.core.node.NodeInfo import net.corda.core.node.services.* @@ -485,8 +483,8 @@ class TwoPartyTradeFlowTests { sellerNode: MockNetwork.MockNode, buyerNode: MockNetwork.MockNode, assetToSell: StateAndRef): RunResult { - sellerNode.services.identityService.registerIdentity(buyerNode.info.legalIdentity) - buyerNode.services.identityService.registerIdentity(sellerNode.info.legalIdentity) + sellerNode.services.identityService.registerIdentity(buyerNode.info.legalIdentityAndCert) + buyerNode.services.identityService.registerIdentity(sellerNode.info.legalIdentityAndCert) val buyerFlows: Observable = buyerNode.registerInitiatedFlow(BuyerAcceptor::class.java) val firstBuyerFiber = buyerFlows.toFuture().map { it.stateMachine } val seller = SellerInitiator(buyerNode.info.legalIdentity, notaryNode.info, assetToSell, 1000.DOLLARS) @@ -495,7 +493,7 @@ class TwoPartyTradeFlowTests { } @InitiatingFlow - class SellerInitiator(val buyer: PartyAndCertificate, + class SellerInitiator(val buyer: Party, val notary: NodeInfo, val assetToSell: StateAndRef, val price: Amount) : FlowLogic() { @@ -512,10 +510,10 @@ class TwoPartyTradeFlowTests { } @InitiatedBy(SellerInitiator::class) - class BuyerAcceptor(val seller: PartyAndCertificate) : FlowLogic() { + class BuyerAcceptor(val seller: Party) : FlowLogic() { @Suspendable override fun call(): SignedTransaction { - val (notary, price) = receive>>(seller).unwrap { + val (notary, price) = receive>>(seller).unwrap { require(serviceHub.networkMapCache.isNotary(it.first)) { "${it.first} is not a notary" } it } diff --git a/node/src/test/kotlin/net/corda/node/services/MockServiceHubInternal.kt b/node/src/test/kotlin/net/corda/node/services/MockServiceHubInternal.kt index 1fb1fb80d4..4b21b7fbd9 100644 --- a/node/src/test/kotlin/net/corda/node/services/MockServiceHubInternal.kt +++ b/node/src/test/kotlin/net/corda/node/services/MockServiceHubInternal.kt @@ -3,7 +3,6 @@ package net.corda.node.services import com.codahale.metrics.MetricRegistry import net.corda.core.flows.FlowInitiator import net.corda.core.flows.FlowLogic -import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.NodeInfo import net.corda.core.node.services.* import net.corda.core.serialization.SerializeAsToken diff --git a/node/src/test/kotlin/net/corda/node/services/NotaryChangeTests.kt b/node/src/test/kotlin/net/corda/node/services/NotaryChangeTests.kt index b6cd68488e..7334451db9 100644 --- a/node/src/test/kotlin/net/corda/node/services/NotaryChangeTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/NotaryChangeTests.kt @@ -77,7 +77,7 @@ class NotaryChangeTests { fun `should throw when a participant refuses to change Notary`() { val state = issueMultiPartyState(clientNodeA, clientNodeB, oldNotaryNode) val newEvilNotary = getTestPartyAndCertificate(X500Name("CN=Evil Notary,O=Evil R3,OU=corda,L=London,C=UK"), generateKeyPair().public) - val flow = NotaryChangeFlow(state, newEvilNotary) + val flow = NotaryChangeFlow(state, newEvilNotary.party) val future = clientNodeA.services.startFlow(flow) net.runNetwork() diff --git a/node/src/test/kotlin/net/corda/node/services/network/AbstractNetworkMapServiceTest.kt b/node/src/test/kotlin/net/corda/node/services/network/AbstractNetworkMapServiceTest.kt index c47e9b3b7c..0da6408897 100644 --- a/node/src/test/kotlin/net/corda/node/services/network/AbstractNetworkMapServiceTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/network/AbstractNetworkMapServiceTest.kt @@ -198,7 +198,7 @@ abstract class AbstractNetworkMapServiceTest } private fun MockNode.identityQuery(): NodeInfo? { - val request = QueryIdentityRequest(info.legalIdentity, info.address) + val request = QueryIdentityRequest(info.legalIdentityAndCert, info.address) val response = services.networkService.sendRequest(QUERY_TOPIC, request, mapServiceNode.info.address) network.runNetwork() return response.getOrThrow().node diff --git a/node/src/test/kotlin/net/corda/node/services/network/InMemoryIdentityServiceTests.kt b/node/src/test/kotlin/net/corda/node/services/network/InMemoryIdentityServiceTests.kt index 648f025869..c0fff9bbd2 100644 --- a/node/src/test/kotlin/net/corda/node/services/network/InMemoryIdentityServiceTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/network/InMemoryIdentityServiceTests.kt @@ -23,16 +23,18 @@ class InMemoryIdentityServiceTests { @Test fun `get all identities`() { val service = InMemoryIdentityService(trustRoot = DUMMY_CA.certificate) + // Nothing registered, so empty set assertNull(service.getAllIdentities().firstOrNull()) - service.registerIdentity(ALICE) + + service.registerIdentity(ALICE_IDENTITY) var expected = setOf(ALICE) - var actual = service.getAllIdentities().toHashSet() + var actual = service.getAllIdentities().map { it.party }.toHashSet() assertEquals(expected, actual) // Add a second party and check we get both back - service.registerIdentity(BOB) + service.registerIdentity(BOB_IDENTITY) expected = setOf(ALICE, BOB) - actual = service.getAllIdentities().toHashSet() + actual = service.getAllIdentities().map { it.party }.toHashSet() assertEquals(expected, actual) } @@ -40,7 +42,7 @@ class InMemoryIdentityServiceTests { fun `get identity by key`() { val service = InMemoryIdentityService(trustRoot = DUMMY_CA.certificate) assertNull(service.partyFromKey(ALICE_PUBKEY)) - service.registerIdentity(ALICE) + service.registerIdentity(ALICE_IDENTITY) assertEquals(ALICE, service.partyFromKey(ALICE_PUBKEY)) assertNull(service.partyFromKey(BOB_PUBKEY)) } @@ -58,7 +60,7 @@ class InMemoryIdentityServiceTests { .map { getTestPartyAndCertificate(X500Name("CN=$it,O=R3,OU=corda,L=London,C=UK"), generateKeyPair().public) } assertNull(service.partyFromX500Name(identities.first().name)) identities.forEach { service.registerIdentity(it) } - identities.forEach { assertEquals(it, service.partyFromX500Name(it.name)) } + identities.forEach { assertEquals(it.party, service.partyFromX500Name(it.name)) } } /** @@ -85,7 +87,6 @@ class InMemoryIdentityServiceTests { */ @Test fun `assert ownership`() { - val service = InMemoryIdentityService(trustRoot = null as X509Certificate?) val aliceRootKey = Crypto.generateKeyPair() val aliceRootCert = X509Utilities.createSelfSignedCACertificate(ALICE.name, aliceRootKey) val aliceTxKey = Crypto.generateKeyPair() @@ -93,9 +94,6 @@ class InMemoryIdentityServiceTests { val aliceCertPath = X509Utilities.createCertificatePath(aliceRootCert, aliceTxCert, revocationEnabled = false) val alice = PartyAndCertificate(ALICE.name, aliceRootKey.public, aliceRootCert, aliceCertPath) - val anonymousAlice = AnonymousParty(aliceTxKey.public) - service.registerAnonymousIdentity(anonymousAlice, alice, aliceCertPath) - val bobRootKey = Crypto.generateKeyPair() val bobRootCert = X509Utilities.createSelfSignedCACertificate(BOB.name, bobRootKey) val bobTxKey = Crypto.generateKeyPair() @@ -103,17 +101,22 @@ class InMemoryIdentityServiceTests { val bobCertPath = X509Utilities.createCertificatePath(bobRootCert, bobTxCert, revocationEnabled = false) val bob = PartyAndCertificate(BOB.name, bobRootKey.public, bobRootCert, bobCertPath) + // Now we have identities, construct the service and let it know about both + val service = InMemoryIdentityService(setOf(alice, bob), emptyMap(), null as X509Certificate?) + val anonymousAlice = AnonymousParty(aliceTxKey.public) + service.registerAnonymousIdentity(anonymousAlice, alice.party, aliceCertPath) + val anonymousBob = AnonymousParty(bobTxKey.public) - service.registerAnonymousIdentity(anonymousBob, bob, bobCertPath) + service.registerAnonymousIdentity(anonymousBob, bob.party, bobCertPath) // Verify that paths are verified - service.assertOwnership(alice, anonymousAlice) - service.assertOwnership(bob, anonymousBob) + service.assertOwnership(alice.party, anonymousAlice) + service.assertOwnership(bob.party, anonymousBob) assertFailsWith { - service.assertOwnership(alice, anonymousBob) + service.assertOwnership(alice.party, anonymousBob) } assertFailsWith { - service.assertOwnership(bob, anonymousAlice) + service.assertOwnership(bob.party, anonymousAlice) } } @@ -123,7 +126,7 @@ class InMemoryIdentityServiceTests { @Test fun `deanonymising a well known identity`() { val expected = ALICE - val actual = InMemoryIdentityService(trustRoot = null as X509Certificate?).partyFromAnonymous(expected) + val actual = InMemoryIdentityService(trustRoot = null).partyFromAnonymous(expected) assertEquals(expected, actual) } } diff --git a/node/src/test/kotlin/net/corda/node/services/persistence/DataVendingServiceTests.kt b/node/src/test/kotlin/net/corda/node/services/persistence/DataVendingServiceTests.kt index 68cba37758..95072b0a7f 100644 --- a/node/src/test/kotlin/net/corda/node/services/persistence/DataVendingServiceTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/persistence/DataVendingServiceTests.kt @@ -9,7 +9,7 @@ import net.corda.core.contracts.USD import net.corda.core.flows.FlowLogic import net.corda.core.flows.InitiatedBy import net.corda.core.flows.InitiatingFlow -import net.corda.core.identity.PartyAndCertificate +import net.corda.core.identity.Party import net.corda.core.node.services.unconsumedStates import net.corda.core.transactions.SignedTransaction import net.corda.core.utilities.DUMMY_NOTARY @@ -93,13 +93,13 @@ class DataVendingServiceTests { } @InitiatingFlow - private class NotifyTxFlow(val otherParty: PartyAndCertificate, val stx: SignedTransaction) : FlowLogic() { + private class NotifyTxFlow(val otherParty: Party, val stx: SignedTransaction) : FlowLogic() { @Suspendable override fun call() = send(otherParty, NotifyTxRequest(stx)) } @InitiatedBy(NotifyTxFlow::class) - private class InitiateNotifyTxFlow(val otherParty: PartyAndCertificate) : FlowLogic() { + private class InitiateNotifyTxFlow(val otherParty: Party) : FlowLogic() { @Suspendable override fun call() = subFlow(NotifyTransactionHandler(otherParty)) } diff --git a/node/src/test/kotlin/net/corda/node/services/statemachine/FlowFrameworkTests.kt b/node/src/test/kotlin/net/corda/node/services/statemachine/FlowFrameworkTests.kt index b2054254fd..3248cb33c5 100644 --- a/node/src/test/kotlin/net/corda/node/services/statemachine/FlowFrameworkTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/statemachine/FlowFrameworkTests.kt @@ -14,7 +14,6 @@ import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowSessionException import net.corda.core.flows.InitiatingFlow import net.corda.core.identity.Party -import net.corda.core.identity.PartyAndCertificate import net.corda.core.messaging.MessageRecipients import net.corda.core.node.services.PartyInfo import net.corda.core.node.services.ServiceInfo @@ -674,10 +673,10 @@ class FlowFrameworkTests { private inline fun > MockNode.registerFlowFactory( initiatingFlowClass: KClass>, - noinline flowFactory: (PartyAndCertificate) -> P): ListenableFuture

+ noinline flowFactory: (Party) -> P): ListenableFuture

{ val observable = registerFlowFactory(initiatingFlowClass.java, object : InitiatedFlowFactory

{ - override fun createFlow(platformVersion: Int, otherParty: PartyAndCertificate, sessionInit: SessionInit): P { + override fun createFlow(platformVersion: Int, otherParty: Party, sessionInit: SessionInit): P { return flowFactory(otherParty) } }, P::class.java, track = true) diff --git a/node/src/test/kotlin/net/corda/node/utilities/registration/NetworkisRegistrationHelperTest.kt b/node/src/test/kotlin/net/corda/node/utilities/registration/NetworkisRegistrationHelperTest.kt index c97def38ce..0ada571887 100644 --- a/node/src/test/kotlin/net/corda/node/utilities/registration/NetworkisRegistrationHelperTest.kt +++ b/node/src/test/kotlin/net/corda/node/utilities/registration/NetworkisRegistrationHelperTest.kt @@ -7,7 +7,6 @@ import net.corda.core.crypto.* import net.corda.core.exists import net.corda.core.mapToArray import net.corda.core.utilities.ALICE -import net.corda.core.utilities.getTestPartyAndCertificate import net.corda.testing.TestNodeConfiguration import net.corda.testing.getTestX509Name import org.bouncycastle.cert.X509CertificateHolder @@ -15,7 +14,6 @@ import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder -import java.security.cert.Certificate import kotlin.test.assertEquals import kotlin.test.assertFalse import kotlin.test.assertTrue diff --git a/samples/irs-demo/src/main/kotlin/net/corda/irs/flows/FixingFlow.kt b/samples/irs-demo/src/main/kotlin/net/corda/irs/flows/FixingFlow.kt index f06129d8ff..2bdaeb5d61 100644 --- a/samples/irs-demo/src/main/kotlin/net/corda/irs/flows/FixingFlow.kt +++ b/samples/irs-demo/src/main/kotlin/net/corda/irs/flows/FixingFlow.kt @@ -9,7 +9,6 @@ import net.corda.core.flows.InitiatedBy import net.corda.core.flows.InitiatingFlow import net.corda.core.flows.SchedulableFlow import net.corda.core.identity.Party -import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.NodeInfo import net.corda.core.node.services.ServiceType import net.corda.core.seconds @@ -31,7 +30,7 @@ object FixingFlow { * who does what in the flow. */ @InitiatedBy(FixingRoleDecider::class) - class Fixer(override val otherParty: PartyAndCertificate) : TwoPartyDealFlow.Secondary() { + class Fixer(override val otherParty: Party) : TwoPartyDealFlow.Secondary() { private lateinit var txState: TransactionState<*> private lateinit var deal: FixableDealState @@ -97,7 +96,7 @@ object FixingFlow { * is just the "side" of the flow run by the party with the floating leg as a way of deciding who * does what in the flow. */ - class Floater(override val otherParty: PartyAndCertificate, + class Floater(override val otherParty: Party, override val payload: FixingSession, override val progressTracker: ProgressTracker = TwoPartyDealFlow.Primary.tracker()) : TwoPartyDealFlow.Primary() { diff --git a/samples/irs-demo/src/main/kotlin/net/corda/irs/simulation/IRSSimulation.kt b/samples/irs-demo/src/main/kotlin/net/corda/irs/simulation/IRSSimulation.kt index 734e33dd51..f6ce54c884 100644 --- a/samples/irs-demo/src/main/kotlin/net/corda/irs/simulation/IRSSimulation.kt +++ b/samples/irs-demo/src/main/kotlin/net/corda/irs/simulation/IRSSimulation.kt @@ -15,7 +15,6 @@ import net.corda.core.flows.FlowStateMachine import net.corda.core.flows.InitiatedBy import net.corda.core.flows.InitiatingFlow import net.corda.core.identity.Party -import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.services.linearHeadsOfType import net.corda.core.transactions.SignedTransaction import net.corda.core.utilities.DUMMY_CA @@ -48,7 +47,7 @@ class IRSSimulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, laten override fun startMainSimulation(): ListenableFuture { val future = SettableFuture.create() - om = JacksonSupport.createInMemoryMapper(InMemoryIdentityService((banks + regulators + networkMap).map { it.info.legalIdentity }, trustRoot = DUMMY_CA.certificate)) + om = JacksonSupport.createInMemoryMapper(InMemoryIdentityService((banks + regulators + networkMap).map { it.info.legalIdentityAndCert }, trustRoot = DUMMY_CA.certificate)) startIRSDealBetween(0, 1).success { // Next iteration is a pause. @@ -131,7 +130,7 @@ class IRSSimulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, laten node2.registerInitiatedFlow(FixingFlow.Fixer::class.java) @InitiatingFlow - class StartDealFlow(val otherParty: PartyAndCertificate, + class StartDealFlow(val otherParty: Party, val payload: AutoOffer, val myKey: PublicKey) : FlowLogic() { @Suspendable diff --git a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/api/PortfolioApi.kt b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/api/PortfolioApi.kt index 97934e830a..b964678650 100644 --- a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/api/PortfolioApi.kt +++ b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/api/PortfolioApi.kt @@ -5,11 +5,11 @@ import net.corda.client.rpc.notUsed import net.corda.core.contracts.DealState import net.corda.core.contracts.StateAndRef import net.corda.core.contracts.filterStatesOfType -import net.corda.core.crypto.* +import net.corda.core.crypto.parsePublicKeyBase58 +import net.corda.core.crypto.toBase58String import net.corda.core.getOrThrow import net.corda.core.identity.AbstractParty import net.corda.core.identity.Party -import net.corda.core.identity.PartyAndCertificate import net.corda.core.messaging.CordaRPCOps import net.corda.core.messaging.startFlow import net.corda.core.utilities.DUMMY_MAP @@ -36,7 +36,7 @@ import javax.ws.rs.core.Response @Path("simmvaluationdemo") class PortfolioApi(val rpc: CordaRPCOps) { - private val ownParty: PartyAndCertificate get() = rpc.nodeIdentity().legalIdentity + private val ownParty: Party get() = rpc.nodeIdentity().legalIdentity private val portfolioUtils = PortfolioApiUtils(ownParty) private inline fun dealsWith(party: AbstractParty): List> { @@ -49,7 +49,7 @@ class PortfolioApi(val rpc: CordaRPCOps) { * DSL to get a party and then executing the passed function with the party as a parameter. * Used as such: withParty(name) { doSomethingWith(it) } */ - private fun withParty(partyName: String, func: (PartyAndCertificate) -> Response): Response { + private fun withParty(partyName: String, func: (Party) -> Response): Response { val otherParty = rpc.partyFromKey(parsePublicKeyBase58(partyName)) return if (otherParty != null) { func(otherParty) diff --git a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/IRSTradeFlow.kt b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/IRSTradeFlow.kt index 3ca522d9f1..ec39e261a0 100644 --- a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/IRSTradeFlow.kt +++ b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/IRSTradeFlow.kt @@ -6,7 +6,6 @@ import net.corda.core.flows.InitiatedBy import net.corda.core.flows.InitiatingFlow import net.corda.core.flows.StartableByRPC import net.corda.core.identity.Party -import net.corda.core.identity.PartyAndCertificate import net.corda.core.serialization.CordaSerializable import net.corda.core.transactions.SignedTransaction import net.corda.core.utilities.unwrap @@ -21,7 +20,7 @@ object IRSTradeFlow { @InitiatingFlow @StartableByRPC - class Requester(val swap: SwapData, val otherParty: PartyAndCertificate) : FlowLogic() { + class Requester(val swap: SwapData, val otherParty: Party) : FlowLogic() { @Suspendable override fun call(): SignedTransaction { require(serviceHub.networkMapCache.notaryNodes.isNotEmpty()) { "No notary nodes registered" } diff --git a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/SimmFlow.kt b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/SimmFlow.kt index ab2588c2a7..793ba74820 100644 --- a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/SimmFlow.kt +++ b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/SimmFlow.kt @@ -15,8 +15,6 @@ import net.corda.core.flows.InitiatedBy import net.corda.core.flows.InitiatingFlow import net.corda.core.flows.StartableByRPC import net.corda.core.identity.Party -import net.corda.core.identity.PartyAndCertificate -import net.corda.core.node.PluginServiceHub import net.corda.core.node.services.dealsWith import net.corda.core.serialization.CordaSerializable import net.corda.core.transactions.SignedTransaction @@ -186,7 +184,7 @@ object SimmFlow { * Receives and validates a portfolio and comes to consensus over the portfolio initial margin using SIMM. */ @InitiatedBy(Requester::class) - class Receiver(val replyToParty: PartyAndCertificate) : FlowLogic() { + class Receiver(val replyToParty: Party) : FlowLogic() { lateinit var ownParty: Party lateinit var offer: OfferMessage diff --git a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/StateRevisionFlow.kt b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/StateRevisionFlow.kt index 1cac27e850..889a7071b1 100644 --- a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/StateRevisionFlow.kt +++ b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/flows/StateRevisionFlow.kt @@ -3,7 +3,6 @@ package net.corda.vega.flows import net.corda.core.contracts.StateAndRef import net.corda.core.identity.AbstractParty import net.corda.core.identity.Party -import net.corda.core.identity.PartyAndCertificate import net.corda.core.seconds import net.corda.core.transactions.SignedTransaction import net.corda.flows.AbstractStateReplacementFlow @@ -27,7 +26,7 @@ object StateRevisionFlow { } } - open class Receiver(otherParty: PartyAndCertificate) : AbstractStateReplacementFlow.Acceptor(otherParty) { + open class Receiver(otherParty: Party) : AbstractStateReplacementFlow.Acceptor(otherParty) { override fun verifyProposal(proposal: AbstractStateReplacementFlow.Proposal) { val proposedTx = proposal.stx.tx val state = proposal.stateRef diff --git a/samples/trader-demo/src/main/kotlin/net/corda/traderdemo/flow/BuyerFlow.kt b/samples/trader-demo/src/main/kotlin/net/corda/traderdemo/flow/BuyerFlow.kt index b667b04651..53024ad9a5 100644 --- a/samples/trader-demo/src/main/kotlin/net/corda/traderdemo/flow/BuyerFlow.kt +++ b/samples/trader-demo/src/main/kotlin/net/corda/traderdemo/flow/BuyerFlow.kt @@ -7,7 +7,7 @@ import net.corda.core.contracts.TransactionGraphSearch import net.corda.core.div import net.corda.core.flows.FlowLogic import net.corda.core.flows.InitiatedBy -import net.corda.core.identity.PartyAndCertificate +import net.corda.core.identity.Party import net.corda.core.node.NodeInfo import net.corda.core.transactions.SignedTransaction import net.corda.core.utilities.Emoji @@ -17,7 +17,7 @@ import net.corda.flows.TwoPartyTradeFlow import java.util.* @InitiatedBy(SellerFlow::class) -class BuyerFlow(val otherParty: PartyAndCertificate) : FlowLogic() { +class BuyerFlow(val otherParty: Party) : FlowLogic() { object STARTING_BUY : ProgressTracker.Step("Seller connected, purchasing commercial paper asset") diff --git a/samples/trader-demo/src/main/kotlin/net/corda/traderdemo/flow/SellerFlow.kt b/samples/trader-demo/src/main/kotlin/net/corda/traderdemo/flow/SellerFlow.kt index d4d24a3872..3a7ecba1d7 100644 --- a/samples/trader-demo/src/main/kotlin/net/corda/traderdemo/flow/SellerFlow.kt +++ b/samples/trader-demo/src/main/kotlin/net/corda/traderdemo/flow/SellerFlow.kt @@ -12,7 +12,6 @@ import net.corda.core.flows.InitiatingFlow import net.corda.core.flows.StartableByRPC import net.corda.core.identity.AbstractParty import net.corda.core.identity.Party -import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.NodeInfo import net.corda.core.seconds import net.corda.core.transactions.SignedTransaction @@ -25,10 +24,10 @@ import java.util.* @InitiatingFlow @StartableByRPC -class SellerFlow(val otherParty: PartyAndCertificate, +class SellerFlow(val otherParty: Party, val amount: Amount, override val progressTracker: ProgressTracker) : FlowLogic() { - constructor(otherParty: PartyAndCertificate, amount: Amount) : this(otherParty, amount, tracker()) + constructor(otherParty: Party, amount: Amount) : this(otherParty, amount, tracker()) companion object { val PROSPECTUS_HASH = SecureHash.parse("decd098666b9657314870e192ced0c3519c2c9d395507a238338f8d003929de9") diff --git a/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt b/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt index 8ac5392516..c9d92a61e3 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt +++ b/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt @@ -9,6 +9,8 @@ import net.corda.core.crypto.SecureHash import net.corda.core.crypto.X509Utilities import net.corda.core.crypto.commonName import net.corda.core.crypto.generateKeyPair +import net.corda.core.identity.AnonymousParty +import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.ServiceHub import net.corda.core.node.VersionInfo @@ -31,6 +33,7 @@ import java.nio.file.Files import java.nio.file.Path import java.security.KeyPair import java.security.PublicKey +import java.security.cert.CertPath import java.util.* import java.util.concurrent.atomic.AtomicInteger @@ -66,22 +69,27 @@ val ALICE_PUBKEY: PublicKey get() = ALICE_KEY.public val BOB_PUBKEY: PublicKey get() = BOB_KEY.public val CHARLIE_PUBKEY: PublicKey get() = CHARLIE_KEY.public -val MEGA_CORP: PartyAndCertificate get() = getTestPartyAndCertificate(X509Utilities.getDevX509Name("MegaCorp"), MEGA_CORP_PUBKEY) -val MINI_CORP: PartyAndCertificate get() = getTestPartyAndCertificate(X509Utilities.getDevX509Name("MiniCorp"), MINI_CORP_PUBKEY) +val MEGA_CORP_IDENTITY: PartyAndCertificate get() = getTestPartyAndCertificate(X509Utilities.getDevX509Name("MegaCorp"), MEGA_CORP_PUBKEY) +val MEGA_CORP: Party get() = MEGA_CORP_IDENTITY.party +val MINI_CORP_IDENTITY: PartyAndCertificate get() = getTestPartyAndCertificate(X509Utilities.getDevX509Name("MiniCorp"), MINI_CORP_PUBKEY) +val MINI_CORP: Party get() = MINI_CORP_IDENTITY.party val BOC_KEY: KeyPair by lazy { generateKeyPair() } val BOC_PUBKEY: PublicKey get() = BOC_KEY.public -val BOC: PartyAndCertificate get() = getTestPartyAndCertificate(getTestX509Name("BankOfCorda"), BOC_PUBKEY) +val BOC_IDENTITY: PartyAndCertificate get() = getTestPartyAndCertificate(getTestX509Name("BankOfCorda"), BOC_PUBKEY) +val BOC: Party get() = BOC_IDENTITY.party val BOC_PARTY_REF = BOC.ref(OpaqueBytes.of(1)).reference val BIG_CORP_KEY: KeyPair by lazy { generateKeyPair() } val BIG_CORP_PUBKEY: PublicKey get() = BIG_CORP_KEY.public -val BIG_CORP: PartyAndCertificate get() = getTestPartyAndCertificate(X509Utilities.getDevX509Name("BigCorporation"), BIG_CORP_PUBKEY) +val BIG_CORP_IDENTITY: PartyAndCertificate get() = getTestPartyAndCertificate(X509Utilities.getDevX509Name("BigCorporation"), BIG_CORP_PUBKEY) +val BIG_CORP: Party get() = BIG_CORP_IDENTITY.party val BIG_CORP_PARTY_REF = BIG_CORP.ref(OpaqueBytes.of(1)).reference val ALL_TEST_KEYS: List get() = listOf(MEGA_CORP_KEY, MINI_CORP_KEY, ALICE_KEY, BOB_KEY, DUMMY_NOTARY_KEY) -val MOCK_IDENTITY_SERVICE: IdentityService get() = InMemoryIdentityService(listOf(MEGA_CORP, MINI_CORP, DUMMY_NOTARY), emptyMap(), DUMMY_CA.certificate) +val MOCK_IDENTITIES = listOf(MEGA_CORP_IDENTITY, MINI_CORP_IDENTITY, DUMMY_NOTARY_IDENTITY) +val MOCK_IDENTITY_SERVICE: IdentityService get() = InMemoryIdentityService(MOCK_IDENTITIES, emptyMap(), DUMMY_CA.certificate) val MOCK_VERSION_INFO = VersionInfo(1, "Mock release", "Mock revision", "Mock Vendor") @@ -206,4 +214,4 @@ fun getTestX509Name(commonName: String): X500Name { nameBuilder.addRDN(BCStyle.L, "New York") nameBuilder.addRDN(BCStyle.C, "US") return nameBuilder.build() -} \ No newline at end of file +} diff --git a/test-utils/src/main/kotlin/net/corda/testing/node/MockNode.kt b/test-utils/src/main/kotlin/net/corda/testing/node/MockNode.kt index efdab54b7c..81afa595ca 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/node/MockNode.kt +++ b/test-utils/src/main/kotlin/net/corda/testing/node/MockNode.kt @@ -6,7 +6,6 @@ import com.google.common.util.concurrent.Futures import com.google.common.util.concurrent.ListenableFuture import net.corda.core.* import net.corda.core.crypto.entropyToKeyPair -import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate import net.corda.core.messaging.RPCOps import net.corda.core.messaging.SingleMessageRecipient @@ -166,7 +165,9 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false, } // TODO: Specify a CA to validate registration against - override fun makeIdentityService() = InMemoryIdentityService(mockNet.identities, trustRoot = null as X509Certificate?) + override fun makeIdentityService(): IdentityService { + return InMemoryIdentityService((mockNet.identities + info.legalIdentityAndCert).toSet(), trustRoot = null as X509Certificate?) + } override fun makeVaultService(dataSourceProperties: Properties): VaultService = NodeVaultService(services, dataSourceProperties) @@ -217,7 +218,7 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false, override fun start(): MockNode { super.start() - mockNet.identities.add(info.legalIdentity) + mockNet.identities.add(info.legalIdentityAndCert) return this } @@ -360,10 +361,8 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false, repeat(numPartyNodes) { nodes += createPartyNode(mapNode.info.address) } - nodes.forEach { node -> - nodes.map { it.info.legalIdentity }.forEach { identity -> - node.services.identityService.registerIdentity(identity) - } + nodes.forEach { itNode -> + nodes.map { it.info.legalIdentityAndCert }.forEach(itNode.services.identityService::registerIdentity) } return BasketOfNodes(nodes, notaryNode, mapNode) } diff --git a/test-utils/src/main/kotlin/net/corda/testing/node/MockServices.kt b/test-utils/src/main/kotlin/net/corda/testing/node/MockServices.kt index 7627774628..0c9faaa4b6 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/node/MockServices.kt +++ b/test-utils/src/main/kotlin/net/corda/testing/node/MockServices.kt @@ -3,6 +3,7 @@ package net.corda.testing.node import net.corda.core.contracts.Attachment import net.corda.core.crypto.* import net.corda.core.flows.StateMachineRunId +import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate import net.corda.core.messaging.SingleMessageRecipient import net.corda.core.node.NodeInfo @@ -13,6 +14,7 @@ import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.core.transactions.SignedTransaction import net.corda.core.utilities.DUMMY_CA import net.corda.core.utilities.DUMMY_NOTARY +import net.corda.core.utilities.DUMMY_NOTARY_IDENTITY import net.corda.core.utilities.getTestPartyAndCertificate import net.corda.node.services.identity.InMemoryIdentityService import net.corda.node.services.keys.freshCertificate @@ -24,6 +26,7 @@ import net.corda.node.services.transactions.InMemoryTransactionVerifierService import net.corda.node.services.vault.NodeVaultService import net.corda.testing.MEGA_CORP import net.corda.testing.MINI_CORP +import net.corda.testing.MOCK_IDENTITIES import net.corda.testing.MOCK_VERSION_INFO import org.bouncycastle.cert.X509CertificateHolder import org.bouncycastle.operator.ContentSigner @@ -66,8 +69,7 @@ open class MockServices(vararg val keys: KeyPair) : ServiceHub { } override val storageService: TxWritableStorageService = MockStorageService() - override final val identityService: IdentityService = InMemoryIdentityService(listOf(MEGA_CORP, MINI_CORP, DUMMY_NOTARY), - trustRoot = DUMMY_CA.certificate) + override final val identityService: IdentityService = InMemoryIdentityService(MOCK_IDENTITIES, trustRoot = DUMMY_CA.certificate) override val keyManagementService: KeyManagementService = MockKeyManagementService(identityService, *keys) override val vaultService: VaultService get() = throw UnsupportedOperationException() From 6104b107c062fdb5e184be4997c4c5e8b25472ed Mon Sep 17 00:00:00 2001 From: Katarzyna Streich Date: Fri, 2 Jun 2017 14:51:40 +0100 Subject: [PATCH 036/126] Fix how network visualiser displays node X500 names. (#785) * Fix how network visualiser displays node X500 names. * Change locations of test nodes, so when used for explorer map visualisation not all of them are stacked one on another in London. --- .../main/kotlin/net/corda/core/utilities/TestConstants.kt | 6 +++--- .../main/kotlin/net/corda/netmap/NetworkMapVisualiser.kt | 3 ++- .../src/main/kotlin/net/corda/netmap/VisualiserViewModel.kt | 3 ++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/core/src/main/kotlin/net/corda/core/utilities/TestConstants.kt b/core/src/main/kotlin/net/corda/core/utilities/TestConstants.kt index 18a24c1019..d7c81378fb 100644 --- a/core/src/main/kotlin/net/corda/core/utilities/TestConstants.kt +++ b/core/src/main/kotlin/net/corda/core/utilities/TestConstants.kt @@ -43,17 +43,17 @@ val DUMMY_BANK_C: Party get() = Party(X500Name("CN=Bank C,O=Bank C,L=Tokyo,C=JP" val ALICE_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(70)) } /** Dummy individual identity for tests and simulations */ -val ALICE_IDENTITY: PartyAndCertificate get() = getTestPartyAndCertificate(X500Name("CN=Alice Corp,O=Alice Corp,L=London,C=UK"), ALICE_KEY.public) +val ALICE_IDENTITY: PartyAndCertificate get() = getTestPartyAndCertificate(X500Name("CN=Alice Corp,O=Alice Corp,L=Madrid,C=ES"), ALICE_KEY.public) val ALICE: Party get() = ALICE_IDENTITY.party val BOB_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(80)) } /** Dummy individual identity for tests and simulations */ -val BOB_IDENTITY: PartyAndCertificate get() = getTestPartyAndCertificate(X500Name("CN=Bob Plc,O=Bob Plc,L=London,C=UK"), BOB_KEY.public) +val BOB_IDENTITY: PartyAndCertificate get() = getTestPartyAndCertificate(X500Name("CN=Bob Plc,O=Bob Plc,L=Rome,C=IT"), BOB_KEY.public) val BOB: Party get() = BOB_IDENTITY.party val CHARLIE_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(90)) } /** Dummy individual identity for tests and simulations */ -val CHARLIE: Party get() = Party(X500Name("CN=Charlie Ltd,O=Charlie Ltd,L=London,C=UK"), CHARLIE_KEY.public) +val CHARLIE: Party get() = Party(X500Name("CN=Charlie Ltd,O=Charlie Ltd,L=Athens,C=GR"), CHARLIE_KEY.public) val DUMMY_REGULATOR_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(100)) } /** Dummy regulator for tests and simulations */ diff --git a/samples/network-visualiser/src/main/kotlin/net/corda/netmap/NetworkMapVisualiser.kt b/samples/network-visualiser/src/main/kotlin/net/corda/netmap/NetworkMapVisualiser.kt index 96d15ebb6e..c6b67e3dce 100644 --- a/samples/network-visualiser/src/main/kotlin/net/corda/netmap/NetworkMapVisualiser.kt +++ b/samples/network-visualiser/src/main/kotlin/net/corda/netmap/NetworkMapVisualiser.kt @@ -11,6 +11,7 @@ import javafx.scene.input.KeyCodeCombination import javafx.scene.layout.VBox import javafx.stage.Stage import javafx.util.Duration +import net.corda.core.crypto.commonName import net.corda.core.messaging.SingleMessageRecipient import net.corda.core.serialization.deserialize import net.corda.core.then @@ -234,7 +235,7 @@ class NetworkMapVisualiser : Application() { } else if (!viewModel.trackerBoxes.containsKey(tracker)) { // New flow started up; add. val extraLabel = viewModel.simulation.extraNodeLabels[node] - val label = if (extraLabel != null) "${node.info.legalIdentity.name}: $extraLabel" else node.info.legalIdentity.name.toString() + val label = if (extraLabel != null) "${node.info.legalIdentity.name.commonName}: $extraLabel" else node.info.legalIdentity.name.commonName val widget = view.buildProgressTrackerWidget(label, tracker.topLevelTracker) println("Added: $tracker, $widget") viewModel.trackerBoxes[tracker] = widget diff --git a/samples/network-visualiser/src/main/kotlin/net/corda/netmap/VisualiserViewModel.kt b/samples/network-visualiser/src/main/kotlin/net/corda/netmap/VisualiserViewModel.kt index d328a0fc74..76e6c8888c 100644 --- a/samples/network-visualiser/src/main/kotlin/net/corda/netmap/VisualiserViewModel.kt +++ b/samples/network-visualiser/src/main/kotlin/net/corda/netmap/VisualiserViewModel.kt @@ -7,6 +7,7 @@ import javafx.scene.layout.StackPane import javafx.scene.shape.Circle import javafx.scene.shape.Line import javafx.util.Duration +import net.corda.core.crypto.commonName import net.corda.core.utilities.ProgressTracker import net.corda.irs.simulation.IRSSimulation import net.corda.testing.node.MockNetwork @@ -155,7 +156,7 @@ class VisualiserViewModel { view.root.children += longPulseOuterDot view.root.children += innerDot - val nameLabel = Label(label.toString()) + val nameLabel = Label(label.commonName) val nameLabelRect = StackPane(nameLabel).apply { styleClass += "node-label" alignment = Pos.CENTER_RIGHT From c510e67ed5a385115daaa819b75dfa34edac9c54 Mon Sep 17 00:00:00 2001 From: Andrzej Cichocki Date: Fri, 2 Jun 2017 15:32:20 +0100 Subject: [PATCH 037/126] Move ShutdownHook to node-api. (#770) --- .../main/kotlin/net/corda/nodeapi}/internal/ShutdownHook.kt | 2 +- node/src/main/kotlin/net/corda/node/driver/Driver.kt | 5 +++-- .../net/corda/node/internal/EnforceSingleNodeIsRunning.kt | 2 +- node/src/main/kotlin/net/corda/node/internal/Node.kt | 4 ++-- .../net/corda/node/services/transactions/PathManager.kt | 2 +- verifier/src/main/kotlin/net/corda/verifier/Verifier.kt | 2 +- 6 files changed, 9 insertions(+), 8 deletions(-) rename {core/src/main/kotlin/net/corda/core => node-api/src/main/kotlin/net/corda/nodeapi}/internal/ShutdownHook.kt (95%) diff --git a/core/src/main/kotlin/net/corda/core/internal/ShutdownHook.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/ShutdownHook.kt similarity index 95% rename from core/src/main/kotlin/net/corda/core/internal/ShutdownHook.kt rename to node-api/src/main/kotlin/net/corda/nodeapi/internal/ShutdownHook.kt index 63811d1ba0..8b0f628990 100644 --- a/core/src/main/kotlin/net/corda/core/internal/ShutdownHook.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/ShutdownHook.kt @@ -1,4 +1,4 @@ -package net.corda.core.internal +package net.corda.nodeapi.internal interface ShutdownHook { /** diff --git a/node/src/main/kotlin/net/corda/node/driver/Driver.kt b/node/src/main/kotlin/net/corda/node/driver/Driver.kt index 14f648fa36..2d72f47f90 100644 --- a/node/src/main/kotlin/net/corda/node/driver/Driver.kt +++ b/node/src/main/kotlin/net/corda/node/driver/Driver.kt @@ -14,8 +14,7 @@ import net.corda.core.crypto.X509Utilities import net.corda.core.crypto.appendToCommonName import net.corda.core.crypto.commonName import net.corda.core.identity.Party -import net.corda.core.internal.ShutdownHook -import net.corda.core.internal.addShutdownHook +import net.corda.core.identity.PartyAndCertificate import net.corda.core.messaging.CordaRPCOps import net.corda.core.node.NodeInfo import net.corda.core.node.services.ServiceInfo @@ -30,6 +29,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.nodeapi.internal.ShutdownHook +import net.corda.nodeapi.internal.addShutdownHook import okhttp3.OkHttpClient import okhttp3.Request import org.bouncycastle.asn1.x500.X500Name diff --git a/node/src/main/kotlin/net/corda/node/internal/EnforceSingleNodeIsRunning.kt b/node/src/main/kotlin/net/corda/node/internal/EnforceSingleNodeIsRunning.kt index c04f898a3b..ad9629f428 100644 --- a/node/src/main/kotlin/net/corda/node/internal/EnforceSingleNodeIsRunning.kt +++ b/node/src/main/kotlin/net/corda/node/internal/EnforceSingleNodeIsRunning.kt @@ -1,6 +1,6 @@ package net.corda.node.internal -import net.corda.core.internal.addShutdownHook +import net.corda.nodeapi.internal.addShutdownHook import net.corda.core.div import java.io.RandomAccessFile import java.lang.management.ManagementFactory diff --git a/node/src/main/kotlin/net/corda/node/internal/Node.kt b/node/src/main/kotlin/net/corda/node/internal/Node.kt index defa3c73e1..2377284f63 100644 --- a/node/src/main/kotlin/net/corda/node/internal/Node.kt +++ b/node/src/main/kotlin/net/corda/node/internal/Node.kt @@ -5,9 +5,8 @@ import com.google.common.net.HostAndPort import com.google.common.util.concurrent.Futures import com.google.common.util.concurrent.ListenableFuture import com.google.common.util.concurrent.SettableFuture +import net.corda.nodeapi.internal.ShutdownHook import net.corda.core.flatMap -import net.corda.core.internal.ShutdownHook -import net.corda.core.internal.addShutdownHook import net.corda.core.messaging.RPCOps import net.corda.core.minutes import net.corda.core.node.ServiceHub @@ -40,6 +39,7 @@ import net.corda.nodeapi.ArtemisMessagingComponent.Companion.PEER_USER import net.corda.nodeapi.ArtemisMessagingComponent.NetworkMapAddress import net.corda.nodeapi.ArtemisTcpTransport import net.corda.nodeapi.ConnectionDirection +import net.corda.nodeapi.internal.addShutdownHook import org.apache.activemq.artemis.api.core.ActiveMQNotConnectedException import org.apache.activemq.artemis.api.core.RoutingType import org.apache.activemq.artemis.api.core.client.ActiveMQClient diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/PathManager.kt b/node/src/main/kotlin/net/corda/node/services/transactions/PathManager.kt index 886222ea7a..e20fa46962 100644 --- a/node/src/main/kotlin/net/corda/node/services/transactions/PathManager.kt +++ b/node/src/main/kotlin/net/corda/node/services/transactions/PathManager.kt @@ -1,6 +1,6 @@ package net.corda.node.services.transactions -import net.corda.core.internal.addShutdownHook +import net.corda.nodeapi.internal.addShutdownHook import java.io.Closeable import java.nio.file.Path import java.util.concurrent.atomic.AtomicInteger diff --git a/verifier/src/main/kotlin/net/corda/verifier/Verifier.kt b/verifier/src/main/kotlin/net/corda/verifier/Verifier.kt index aeed27e3ca..a42b495072 100644 --- a/verifier/src/main/kotlin/net/corda/verifier/Verifier.kt +++ b/verifier/src/main/kotlin/net/corda/verifier/Verifier.kt @@ -5,7 +5,7 @@ import com.typesafe.config.Config import com.typesafe.config.ConfigFactory import com.typesafe.config.ConfigParseOptions import net.corda.core.ErrorOr -import net.corda.core.internal.addShutdownHook +import net.corda.nodeapi.internal.addShutdownHook import net.corda.core.div import net.corda.core.utilities.debug import net.corda.core.utilities.loggerFor From 51ea9fec1ade8aec9007f2f250a8293a820a365e Mon Sep 17 00:00:00 2001 From: Andrzej Cichocki Date: Fri, 2 Jun 2017 16:23:05 +0100 Subject: [PATCH 038/126] IRS demo fixes (#782) * Increase max network map request size so the notary can register * Suppress oracle service installation errors in non-oracle nodes * Make demos automatically build capsule jars --- .../corda/core/node/services/CordaService.kt | 5 ++- docs/source/example-code/build.gradle | 4 +-- .../net/corda/node/internal/AbstractNode.kt | 35 +++++++++++++------ .../services/network/NetworkMapService.kt | 9 +++-- samples/attachment-demo/build.gradle | 4 +-- samples/bank-of-corda-demo/build.gradle | 4 +-- samples/irs-demo/build.gradle | 4 +-- .../kotlin/net/corda/irs/IRSDemoTest.kt | 2 +- .../src/main/kotlin/net/corda/irs/Main.kt | 2 +- .../net/corda/irs/api/NodeInterestRates.kt | 7 ++-- .../main/kotlin/net/corda/irs/contract/IRS.kt | 7 ++-- .../net/corda/irs/simulation/Simulation.kt | 4 +-- .../irs/testing/NodeInterestRatesTest.kt | 4 +-- samples/network-visualiser/build.gradle | 4 +-- samples/notary-demo/build.gradle | 4 +-- samples/simm-valuation-demo/build.gradle | 4 +-- samples/trader-demo/build.gradle | 4 +-- 17 files changed, 64 insertions(+), 43 deletions(-) diff --git a/core/src/main/kotlin/net/corda/core/node/services/CordaService.kt b/core/src/main/kotlin/net/corda/core/node/services/CordaService.kt index a6b6a36b03..61dab01549 100644 --- a/core/src/main/kotlin/net/corda/core/node/services/CordaService.kt +++ b/core/src/main/kotlin/net/corda/core/node/services/CordaService.kt @@ -11,10 +11,13 @@ import kotlin.annotation.AnnotationTarget.CLASS * * The service class has to implement [net.corda.core.serialization.SerializeAsToken] to ensure correct usage within flows. * (If possible extend [net.corda.core.serialization.SingletonSerializeAsToken] instead as it removes the boilerplate.) + * + * The annotated class should expose its [ServiceType] via a public static field named `type`, so that the service is + * only loaded in nodes that declare the type in their advertisedServices. */ // TODO Handle the singleton serialisation of Corda services automatically, removing the need to implement SerializeAsToken // TODO Currently all nodes which load the plugin will attempt to load the service even if it's not revelant to them. The // underlying problem is that the entire CorDapp jar is used as a dependency, when in fact it's just the client-facing // bit of the CorDapp that should be depended on (e.g. the initiating flows). @Target(CLASS) -annotation class CordaService \ No newline at end of file +annotation class CordaService diff --git a/docs/source/example-code/build.gradle b/docs/source/example-code/build.gradle index 754026fa45..a266487d1a 100644 --- a/docs/source/example-code/build.gradle +++ b/docs/source/example-code/build.gradle @@ -43,8 +43,8 @@ dependencies { exclude group: "bouncycastle" } - runtime project(path: ":node:capsule", configuration: 'runtimeArtifacts') - runtime project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts') + compile project(path: ":node:capsule", configuration: 'runtimeArtifacts') + compile project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts') } mainClassName = "net.corda.docs.ClientRpcTutorialKt" diff --git a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt index 353b15a551..d81753a44f 100644 --- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt @@ -268,16 +268,31 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, private fun installCordaServices(scanResult: ScanResult): List { return scanResult.getClassesWithAnnotation(SerializeAsToken::class, CordaService::class).mapNotNull { - try { - installCordaService(it) - } catch (e: NoSuchMethodException) { - log.error("${it.name}, as a Corda service, must have a constructor with a single parameter " + - "of type ${PluginServiceHub::class.java.name}") - null - } catch (e: Exception) { - log.error("Unable to install Corda service ${it.name}", e) - null - } + tryInstallCordaService(it) + } + } + + private fun tryInstallCordaService(serviceClass: Class): T? { + /** TODO: This mechanism may get replaced by a different one, see comments on [CordaService]. */ + val typeField = try { + serviceClass.getField("type") + } catch (e: NoSuchFieldException) { + null + } + if (typeField == null) { + log.warn("${serviceClass.name} does not have a type field, optimistically proceeding with install.") + } else if (info.serviceIdentities(typeField.get(null) as ServiceType).isEmpty()) { + return null + } + return try { + installCordaService(serviceClass) + } catch (e: NoSuchMethodException) { + log.error("${serviceClass.name}, as a Corda service, must have a constructor with a single parameter " + + "of type ${PluginServiceHub::class.java.name}") + null + } catch (e: Exception) { + log.error("Unable to install Corda service ${serviceClass.name}", e) + null } } diff --git a/node/src/main/kotlin/net/corda/node/services/network/NetworkMapService.kt b/node/src/main/kotlin/net/corda/node/services/network/NetworkMapService.kt index 133b674307..f69779844f 100644 --- a/node/src/main/kotlin/net/corda/node/services/network/NetworkMapService.kt +++ b/node/src/main/kotlin/net/corda/node/services/network/NetworkMapService.kt @@ -18,6 +18,7 @@ import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.SerializedBytes import net.corda.core.serialization.deserialize import net.corda.core.serialization.serialize +import net.corda.core.utilities.debug import net.corda.core.utilities.loggerFor import net.corda.node.services.api.AbstractNodeService import net.corda.node.services.api.ServiceHubInternal @@ -135,10 +136,10 @@ abstract class AbstractNetworkMapService(services: ServiceHubInternal, val minimumPlatformVersion: Int) : NetworkMapService, AbstractNodeService(services) { companion object { /** - * Maximum credible size for a registration request. Generally requests are around 500-600 bytes, so this gives a + * Maximum credible size for a registration request. Generally requests are around 2000-6000 bytes, so this gives a * 10 times overhead. */ - private const val MAX_SIZE_REGISTRATION_REQUEST_BYTES = 5500 + private const val MAX_SIZE_REGISTRATION_REQUEST_BYTES = 40000 private val logger = loggerFor() } @@ -232,7 +233,9 @@ abstract class AbstractNetworkMapService(services: ServiceHubInternal, } private fun processRegistrationRequest(request: RegistrationRequest): RegistrationResponse { - if (request.wireReg.raw.size > MAX_SIZE_REGISTRATION_REQUEST_BYTES) { + val requestSize = request.wireReg.raw.size + logger.debug { "Received registration request of size: $requestSize" } + if (requestSize > MAX_SIZE_REGISTRATION_REQUEST_BYTES) { return RegistrationResponse("Request is too big") } diff --git a/samples/attachment-demo/build.gradle b/samples/attachment-demo/build.gradle index ec2d727ff0..7b7a02e5b7 100644 --- a/samples/attachment-demo/build.gradle +++ b/samples/attachment-demo/build.gradle @@ -26,8 +26,8 @@ dependencies { testCompile "junit:junit:$junit_version" // Corda integration dependencies - runtime project(path: ":node:capsule", configuration: 'runtimeArtifacts') - runtime project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts') + compile project(path: ":node:capsule", configuration: 'runtimeArtifacts') + compile project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts') compile project(':core') compile project(':test-utils') diff --git a/samples/bank-of-corda-demo/build.gradle b/samples/bank-of-corda-demo/build.gradle index c369d8100d..60455c299e 100644 --- a/samples/bank-of-corda-demo/build.gradle +++ b/samples/bank-of-corda-demo/build.gradle @@ -26,8 +26,8 @@ dependencies { testCompile "junit:junit:$junit_version" // Corda integration dependencies - runtime project(path: ":node:capsule", configuration: 'runtimeArtifacts') - runtime project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts') + compile project(path: ":node:capsule", configuration: 'runtimeArtifacts') + compile project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts') compile project(':core') compile project(':client:jfx') compile project(':client:rpc') diff --git a/samples/irs-demo/build.gradle b/samples/irs-demo/build.gradle index 7ef056ceb5..00f36bf82f 100644 --- a/samples/irs-demo/build.gradle +++ b/samples/irs-demo/build.gradle @@ -30,8 +30,8 @@ dependencies { testCompile "org.assertj:assertj-core:${assertj_version}" // Corda integration dependencies - runtime project(path: ":node:capsule", configuration: 'runtimeArtifacts') - runtime project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts') + compile project(path: ":node:capsule", configuration: 'runtimeArtifacts') + compile project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts') compile project(':core') compile project(':finance') compile project(':webserver') diff --git a/samples/irs-demo/src/integration-test/kotlin/net/corda/irs/IRSDemoTest.kt b/samples/irs-demo/src/integration-test/kotlin/net/corda/irs/IRSDemoTest.kt index 56a45f388d..9639272865 100644 --- a/samples/irs-demo/src/integration-test/kotlin/net/corda/irs/IRSDemoTest.kt +++ b/samples/irs-demo/src/integration-test/kotlin/net/corda/irs/IRSDemoTest.kt @@ -39,7 +39,7 @@ class IRSDemoTest : IntegrationTestCategory { systemProperties = mapOf("net.corda.node.cordapp.scan.package" to "net.corda.irs")) { val (controller, nodeA, nodeB) = Futures.allAsList( - startNode(DUMMY_NOTARY.name, setOf(ServiceInfo(SimpleNotaryService.type), ServiceInfo(NodeInterestRates.type))), + startNode(DUMMY_NOTARY.name, setOf(ServiceInfo(SimpleNotaryService.type), ServiceInfo(NodeInterestRates.Oracle.type))), startNode(DUMMY_BANK_A.name, rpcUsers = listOf(rpcUser)), startNode(DUMMY_BANK_B.name) ).getOrThrow() diff --git a/samples/irs-demo/src/main/kotlin/net/corda/irs/Main.kt b/samples/irs-demo/src/main/kotlin/net/corda/irs/Main.kt index 103f016a3c..7233173531 100644 --- a/samples/irs-demo/src/main/kotlin/net/corda/irs/Main.kt +++ b/samples/irs-demo/src/main/kotlin/net/corda/irs/Main.kt @@ -17,7 +17,7 @@ import net.corda.node.services.transactions.SimpleNotaryService fun main(args: Array) { driver(dsl = { val (controller, nodeA, nodeB) = Futures.allAsList( - startNode(DUMMY_NOTARY.name, setOf(ServiceInfo(SimpleNotaryService.type), ServiceInfo(NodeInterestRates.type))), + startNode(DUMMY_NOTARY.name, setOf(ServiceInfo(SimpleNotaryService.type), ServiceInfo(NodeInterestRates.Oracle.type))), startNode(DUMMY_BANK_A.name), startNode(DUMMY_BANK_B.name) ).getOrThrow() diff --git a/samples/irs-demo/src/main/kotlin/net/corda/irs/api/NodeInterestRates.kt b/samples/irs-demo/src/main/kotlin/net/corda/irs/api/NodeInterestRates.kt index f4cc09ea4c..a2ef62ec66 100644 --- a/samples/irs-demo/src/main/kotlin/net/corda/irs/api/NodeInterestRates.kt +++ b/samples/irs-demo/src/main/kotlin/net/corda/irs/api/NodeInterestRates.kt @@ -49,8 +49,6 @@ import kotlin.collections.set * for signing. */ object NodeInterestRates { - val type = ServiceType.corda.getSubType("interest_rates") - // DOCSTART 2 @InitiatedBy(RatesFixFlow.FixSignFlow::class) class FixSignHandler(val otherParty: Party) : FlowLogic() { @@ -95,6 +93,11 @@ object NodeInterestRates { ) // DOCEND 3 + companion object { + @JvmField + val type = ServiceType.corda.getSubType("interest_rates") + } + private object Table : JDBCHashedTable("demo_interest_rate_fixes") { val name = varchar("index_name", length = 255) val forDay = localDate("for_day") diff --git a/samples/irs-demo/src/main/kotlin/net/corda/irs/contract/IRS.kt b/samples/irs-demo/src/main/kotlin/net/corda/irs/contract/IRS.kt index 5674787976..d9a9abe266 100644 --- a/samples/irs-demo/src/main/kotlin/net/corda/irs/contract/IRS.kt +++ b/samples/irs-demo/src/main/kotlin/net/corda/irs/contract/IRS.kt @@ -10,6 +10,7 @@ import net.corda.core.identity.Party import net.corda.core.node.services.ServiceType import net.corda.core.serialization.CordaSerializable import net.corda.core.transactions.TransactionBuilder +import net.corda.irs.api.NodeInterestRates import net.corda.irs.flows.FixingFlow import net.corda.irs.utilities.suggestInterestRateAnnouncementTimeWindow import org.apache.commons.jexl3.JexlBuilder @@ -190,10 +191,6 @@ class FloatingRatePaymentEvent(date: LocalDate, class InterestRateSwap : Contract { override val legalContractReference = SecureHash.sha256("is_this_the_text_of_the_contract ? TBD") - companion object { - val oracleType = ServiceType.corda.getSubType("interest_rates") - } - /** * This Common area contains all the information that is not leg specific. */ @@ -665,7 +662,7 @@ class InterestRateSwap : Contract { override val contract = IRS_PROGRAM_ID override val oracleType: ServiceType - get() = InterestRateSwap.oracleType + get() = NodeInterestRates.Oracle.type override val ref = common.tradeID diff --git a/samples/irs-demo/src/main/kotlin/net/corda/irs/simulation/Simulation.kt b/samples/irs-demo/src/main/kotlin/net/corda/irs/simulation/Simulation.kt index c2f93f75f9..966c9709da 100644 --- a/samples/irs-demo/src/main/kotlin/net/corda/irs/simulation/Simulation.kt +++ b/samples/irs-demo/src/main/kotlin/net/corda/irs/simulation/Simulation.kt @@ -121,7 +121,7 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean, override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?, advertisedServices: Set, id: Int, overrideServices: Map?, entropyRoot: BigInteger): MockNetwork.MockNode { - require(advertisedServices.containsType(NodeInterestRates.type)) + require(advertisedServices.containsType(NodeInterestRates.Oracle.type)) val cfg = TestNodeConfiguration( baseDirectory = config.baseDirectory, myLegalName = RATES_SERVICE_NAME, @@ -166,7 +166,7 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean, = network.createNode(networkMap.info.address, nodeFactory = NotaryNodeFactory, advertisedServices = ServiceInfo(SimpleNotaryService.type)) as SimulatedNode val regulators: List = listOf(network.createNode(networkMap.info.address, start = false, nodeFactory = RegulatorFactory) as SimulatedNode) val ratesOracle: SimulatedNode - = network.createNode(networkMap.info.address, start = false, nodeFactory = RatesOracleFactory, advertisedServices = ServiceInfo(NodeInterestRates.type)) as SimulatedNode + = network.createNode(networkMap.info.address, start = false, nodeFactory = RatesOracleFactory, advertisedServices = ServiceInfo(NodeInterestRates.Oracle.type)) as SimulatedNode // All nodes must be in one of these two lists for the purposes of the visualiser tool. val serviceProviders: List = listOf(notary, ratesOracle, networkMap) diff --git a/samples/irs-demo/src/test/kotlin/net/corda/irs/testing/NodeInterestRatesTest.kt b/samples/irs-demo/src/test/kotlin/net/corda/irs/testing/NodeInterestRatesTest.kt index c1ad4256ec..a91ac74f74 100644 --- a/samples/irs-demo/src/test/kotlin/net/corda/irs/testing/NodeInterestRatesTest.kt +++ b/samples/irs-demo/src/test/kotlin/net/corda/irs/testing/NodeInterestRatesTest.kt @@ -209,7 +209,7 @@ class NodeInterestRatesTest { fun `network tearoff`() { val net = MockNetwork() val n1 = net.createNotaryNode() - val n2 = net.createNode(n1.info.address, advertisedServices = ServiceInfo(NodeInterestRates.type)) + val n2 = net.createNode(n1.info.address, advertisedServices = ServiceInfo(NodeInterestRates.Oracle.type)) n2.registerInitiatedFlow(NodeInterestRates.FixQueryHandler::class.java) n2.registerInitiatedFlow(NodeInterestRates.FixSignHandler::class.java) n2.database.transaction { @@ -217,7 +217,7 @@ class NodeInterestRatesTest { } val tx = TransactionType.General.Builder(null) val fixOf = NodeInterestRates.parseFixOf("LIBOR 2016-03-16 1M") - val oracle = n2.info.serviceIdentities(NodeInterestRates.type).first() + val oracle = n2.info.serviceIdentities(NodeInterestRates.Oracle.type).first() val flow = FilteredRatesFlow(tx, oracle, fixOf, "0.675".bd, "0.1".bd) LogHelper.setLevel("rates") net.runNetwork() diff --git a/samples/network-visualiser/build.gradle b/samples/network-visualiser/build.gradle index 7d95c04a9a..8170451d88 100644 --- a/samples/network-visualiser/build.gradle +++ b/samples/network-visualiser/build.gradle @@ -12,8 +12,8 @@ dependencies { testCompile "junit:junit:$junit_version" // Corda integration dependencies - runtime project(path: ":node:capsule", configuration: 'runtimeArtifacts') - runtime project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts') + compile project(path: ":node:capsule", configuration: 'runtimeArtifacts') + compile project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts') compile project(':core') compile project(':finance') testCompile project(':test-utils') diff --git a/samples/notary-demo/build.gradle b/samples/notary-demo/build.gradle index c526c4ab9b..938b38cfd4 100644 --- a/samples/notary-demo/build.gradle +++ b/samples/notary-demo/build.gradle @@ -18,8 +18,8 @@ dependencies { testCompile "junit:junit:$junit_version" // Corda integration dependencies - runtime project(path: ":node:capsule", configuration: 'runtimeArtifacts') - runtime project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts') + compile project(path: ":node:capsule", configuration: 'runtimeArtifacts') + compile project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts') compile project(':core') compile project(':client:jfx') compile project(':client:rpc') diff --git a/samples/simm-valuation-demo/build.gradle b/samples/simm-valuation-demo/build.gradle index 95c8d55cf5..6aa9ee1434 100644 --- a/samples/simm-valuation-demo/build.gradle +++ b/samples/simm-valuation-demo/build.gradle @@ -31,8 +31,8 @@ dependencies { testCompile "org.assertj:assertj-core:${assertj_version}" // Corda integration dependencies - runtime project(path: ":node:capsule", configuration: 'runtimeArtifacts') - runtime project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts') + compile project(path: ":node:capsule", configuration: 'runtimeArtifacts') + compile project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts') compile project(':core') compile project(':node') compile project(':webserver') diff --git a/samples/trader-demo/build.gradle b/samples/trader-demo/build.gradle index 58b96b7cf7..c7213addf5 100644 --- a/samples/trader-demo/build.gradle +++ b/samples/trader-demo/build.gradle @@ -27,8 +27,8 @@ dependencies { testCompile "org.assertj:assertj-core:${assertj_version}" // Corda integration dependencies - runtime project(path: ":node:capsule", configuration: 'runtimeArtifacts') - runtime project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts') + compile project(path: ":node:capsule", configuration: 'runtimeArtifacts') + compile project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts') compile project(':core') compile project(':finance') compile project(':test-utils') From e5fba5d0afb67435a2d9bbdc72fa9e248f49f4d2 Mon Sep 17 00:00:00 2001 From: Joel Dudley Date: Mon, 5 Jun 2017 13:37:23 +0100 Subject: [PATCH 039/126] Docsite reorg ahead of beta launch. --- README.md | 2 - .../net/corda/core/contracts/Structures.kt | 18 + .../core/contracts/TransactionVerification.kt | 6 + .../net/corda/core/flows/FlowException.kt | 2 + .../core/transactions/SignedTransaction.kt | 4 + .../core/transactions/TransactionBuilder.kt | 2 + .../net/corda/flows/CollectSignaturesFlow.kt | 2 + .../net/corda/flows/TwoPartyDealFlow.kt | 3 + docs/source/api-contracts.rst | 309 +++++++++++++++++ ...epts-core-types.rst => api-core-types.rst} | 71 +--- docs/source/api-flows.rst | 314 ++++++++++++++++++ docs/source/api-states.rst | 147 ++++++++ docs/source/api-transactions.rst | 299 +++++++++++++++++ docs/source/api.rst | 12 + docs/source/azure-vm.rst | 6 +- docs/source/changelog.rst | 8 +- docs/source/clientrpc.rst | 2 +- docs/source/contract-upgrade.rst | 2 +- docs/source/corda-plugins.rst | 54 --- docs/source/corda-repo-layout.rst | 30 ++ docs/source/cordapp-overview.rst | 26 ++ docs/source/faq.rst | 4 + ...inancial-model.rst => financial-model.rst} | 0 docs/source/flow-library.rst | 2 +- docs/source/flow-state-machines.rst | 4 +- docs/source/further-notes-on-kotlin.rst | 14 - docs/source/getting-set-up.rst | 86 +++-- docs/source/index.rst | 132 +++++--- docs/source/inthebox.rst | 53 --- .../key-concepts-consensus-notaries.rst | 162 --------- docs/source/key-concepts-consensus.rst | 62 ++++ docs/source/key-concepts-contracts.rst | 73 ++++ docs/source/key-concepts-data-model.rst | 142 -------- docs/source/key-concepts-ecosystem.rst | 82 ++--- docs/source/key-concepts-flow-framework.rst | 37 --- docs/source/key-concepts-flows.rst | 48 +++ docs/source/key-concepts-ledger.rst | 26 ++ docs/source/key-concepts-node.rst | 72 ++++ docs/source/key-concepts-notaries.rst | 88 +++++ docs/source/key-concepts-oracles.rst | 26 ++ docs/source/key-concepts-security-model.rst | 45 --- docs/source/key-concepts-states.rst | 44 +++ docs/source/key-concepts-time-windows.rst | 50 +++ docs/source/key-concepts-tradeoffs.rst | 76 +++++ docs/source/key-concepts-transactions.rst | 148 +++++++++ docs/source/key-concepts.rst | 98 +++++- docs/source/node-services.rst | 4 +- docs/source/oracles.rst | 4 +- docs/source/out-of-process-verification.rst | 2 +- docs/source/resources/basic-tx.png | Bin 0 -> 148852 bytes docs/source/resources/commands.png | Bin 0 -> 329823 bytes docs/source/resources/committed_tx.png | Bin 0 -> 155663 bytes docs/source/resources/flow-overview.png | Bin 0 -> 373238 bytes docs/source/resources/flow.gif | Bin 0 -> 251877 bytes docs/source/resources/flowFramework.png | Bin 225159 -> 0 bytes docs/source/resources/full-tx.png | Bin 0 -> 301549 bytes docs/source/resources/grouped-tx.png | Bin 0 -> 143035 bytes docs/source/resources/in-out-groups.png | Bin 0 -> 199544 bytes docs/source/resources/ledger-table.png | Bin 0 -> 229828 bytes docs/source/resources/ledger-venn.png | Bin 0 -> 303830 bytes docs/source/resources/network.png | Bin 0 -> 291895 bytes docs/source/resources/node-architecture.png | Bin 0 -> 371367 bytes docs/source/resources/node-diagram.png | Bin 0 -> 389402 bytes docs/source/resources/state-hierarchy.png | Bin 0 -> 182078 bytes docs/source/resources/state-sequence.png | Bin 0 -> 363372 bytes docs/source/resources/state.png | Bin 0 -> 262904 bytes docs/source/resources/time-window.gif | Bin 0 -> 74077 bytes docs/source/resources/transaction-flow.png | Bin 0 -> 294290 bytes docs/source/resources/tx-chain.png | Bin 0 -> 283124 bytes docs/source/resources/tx-validation.png | Bin 0 -> 156918 bytes docs/source/resources/tx_with_sigs.png | Bin 0 -> 115279 bytes docs/source/resources/uncommitted_tx.png | Bin 0 -> 113911 bytes docs/source/resources/ungrouped-tx.png | Bin 0 -> 138388 bytes .../source/resources/uniqueness-consensus.png | Bin 0 -> 233753 bytes .../source/resources/validation-consensus.png | Bin 0 -> 347384 bytes docs/source/resources/vault-simple.png | Bin 0 -> 481380 bytes ...ating-a-cordapp.rst => running-a-node.rst} | 60 +--- docs/source/running-the-demos.rst | 3 +- docs/source/secure-coding-guidelines.rst | 3 +- docs/source/serialization.rst | 4 +- docs/source/setting-up-a-corda-network.rst | 2 +- ...-fault-finding.rst => troubleshooting.rst} | 0 docs/source/tutorial-clientrpc-api.rst | 8 +- docs/source/tutorial-contract.rst | 4 +- .../{key-concepts-vault.rst => vault.rst} | 0 docs/source/writing-cordapps.rst | 137 ++++++++ .../kotlin/net/corda/contracts/asset/Cash.kt | 4 + gradle-plugins/cordformation/README.rst | 2 +- node/src/main/kotlin/net/corda/node/Corda.kt | 2 +- 89 files changed, 2339 insertions(+), 793 deletions(-) create mode 100644 docs/source/api-contracts.rst rename docs/source/{key-concepts-core-types.rst => api-core-types.rst} (54%) create mode 100644 docs/source/api-flows.rst create mode 100644 docs/source/api-states.rst create mode 100644 docs/source/api-transactions.rst create mode 100644 docs/source/api.rst delete mode 100644 docs/source/corda-plugins.rst create mode 100644 docs/source/corda-repo-layout.rst create mode 100644 docs/source/cordapp-overview.rst create mode 100644 docs/source/faq.rst rename docs/source/{key-concepts-financial-model.rst => financial-model.rst} (100%) delete mode 100644 docs/source/further-notes-on-kotlin.rst delete mode 100644 docs/source/inthebox.rst delete mode 100644 docs/source/key-concepts-consensus-notaries.rst create mode 100644 docs/source/key-concepts-consensus.rst create mode 100644 docs/source/key-concepts-contracts.rst delete mode 100644 docs/source/key-concepts-data-model.rst delete mode 100644 docs/source/key-concepts-flow-framework.rst create mode 100644 docs/source/key-concepts-flows.rst create mode 100644 docs/source/key-concepts-ledger.rst create mode 100644 docs/source/key-concepts-node.rst create mode 100644 docs/source/key-concepts-notaries.rst create mode 100644 docs/source/key-concepts-oracles.rst delete mode 100644 docs/source/key-concepts-security-model.rst create mode 100644 docs/source/key-concepts-states.rst create mode 100644 docs/source/key-concepts-time-windows.rst create mode 100644 docs/source/key-concepts-tradeoffs.rst create mode 100644 docs/source/key-concepts-transactions.rst create mode 100644 docs/source/resources/basic-tx.png create mode 100644 docs/source/resources/commands.png create mode 100644 docs/source/resources/committed_tx.png create mode 100644 docs/source/resources/flow-overview.png create mode 100644 docs/source/resources/flow.gif delete mode 100644 docs/source/resources/flowFramework.png create mode 100644 docs/source/resources/full-tx.png create mode 100644 docs/source/resources/grouped-tx.png create mode 100644 docs/source/resources/in-out-groups.png create mode 100644 docs/source/resources/ledger-table.png create mode 100644 docs/source/resources/ledger-venn.png create mode 100644 docs/source/resources/network.png create mode 100644 docs/source/resources/node-architecture.png create mode 100644 docs/source/resources/node-diagram.png create mode 100644 docs/source/resources/state-hierarchy.png create mode 100644 docs/source/resources/state-sequence.png create mode 100644 docs/source/resources/state.png create mode 100644 docs/source/resources/time-window.gif create mode 100644 docs/source/resources/transaction-flow.png create mode 100644 docs/source/resources/tx-chain.png create mode 100644 docs/source/resources/tx-validation.png create mode 100644 docs/source/resources/tx_with_sigs.png create mode 100644 docs/source/resources/uncommitted_tx.png create mode 100644 docs/source/resources/ungrouped-tx.png create mode 100644 docs/source/resources/uniqueness-consensus.png create mode 100644 docs/source/resources/validation-consensus.png create mode 100644 docs/source/resources/vault-simple.png rename docs/source/{creating-a-cordapp.rst => running-a-node.rst} (72%) rename docs/source/{getting-set-up-fault-finding.rst => troubleshooting.rst} (100%) rename docs/source/{key-concepts-vault.rst => vault.rst} (100%) create mode 100644 docs/source/writing-cordapps.rst diff --git a/README.md b/README.md index e592d86a21..521a202836 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,6 @@ Corda is a decentralised database system in which nodes trust each other as litt * "Notary" infrastructure to validate uniqueness of transactions * Written as a platform for distributed apps called CorDapps * Written in [Kotlin](https://kotlinlang.org), targeting the JVM - -Read our full and planned feature list [here](https://docs.corda.net/inthebox.html). ## Getting started diff --git a/core/src/main/kotlin/net/corda/core/contracts/Structures.kt b/core/src/main/kotlin/net/corda/core/contracts/Structures.kt index e56a42f409..29a651b01b 100644 --- a/core/src/main/kotlin/net/corda/core/contracts/Structures.kt +++ b/core/src/main/kotlin/net/corda/core/contracts/Structures.kt @@ -54,6 +54,7 @@ interface MultilateralNettableState { interface NettableState, out T : Any> : BilateralNettableState, MultilateralNettableState +// DOCSTART 1 /** * A contract state (or just "state") contains opaque data used by a contract program. It can be thought of as a disk * file that the program can use to persist data across transactions. States are immutable: once created they are never @@ -116,7 +117,9 @@ interface ContractState { */ val participants: List } +// DOCEND 1 +// DOCSTART 4 /** * A wrapper for [ContractState] containing additional platform-level state information. * This is the definitive state that is stored on the ledger and used in transaction outputs. @@ -145,6 +148,7 @@ data class TransactionState @JvmOverloads constructor( * otherwise the transaction is not valid. */ val encumbrance: Int? = null) +// DOCEND 4 /** Wraps the [ContractState] in a [TransactionState] object */ infix fun T.`with notary`(newNotary: Party) = withNotary(newNotary) @@ -169,6 +173,7 @@ data class Issued(val issuer: PartyAndReference, val product: P) { */ fun Amount>.withoutIssuer(): Amount = Amount(quantity, token.product) +// DOCSTART 3 /** * A contract state that can have a single owner. */ @@ -179,6 +184,7 @@ interface OwnableState : ContractState { /** Copies the underlying data structure, replacing the owner field with this new value and leaving the rest alone */ fun withNewOwner(newOwner: AbstractParty): Pair } +// DOCEND 3 /** Something which is scheduled to happen at a point in time */ interface Scheduled { @@ -207,6 +213,7 @@ data class ScheduledStateRef(val ref: StateRef, override val scheduledAt: Instan */ data class ScheduledActivity(val logicRef: FlowLogicRef, override val scheduledAt: Instant) : Scheduled +// DOCSTART 2 /** * A state that evolves by superseding itself, all of which share the common "linearId". * @@ -245,6 +252,7 @@ interface LinearState : ContractState { } } } +// DOCEND 2 interface SchedulableState : ContractState { /** @@ -325,13 +333,17 @@ fun ContractState.hash(): SecureHash = SecureHash.sha256(serialize().bytes) * transaction defined the state and where in that transaction it was. */ @CordaSerializable +// DOCSTART 8 data class StateRef(val txhash: SecureHash, val index: Int) { override fun toString() = "$txhash($index)" } +// DOCEND 8 /** A StateAndRef is simply a (state, ref) pair. For instance, a vault (which holds available assets) contains these. */ @CordaSerializable +// DOCSTART 7 data class StateAndRef(val state: TransactionState, val ref: StateRef) +// DOCEND 7 /** Filters a list of [StateAndRef] objects according to the type of the states */ inline fun Iterable>.filterStatesOfType(): List> { @@ -359,7 +371,9 @@ abstract class TypeOnlyCommandData : CommandData { /** Command data/content plus pubkey pair: the signature is stored at the end of the serialized bytes */ @CordaSerializable +// DOCSTART 9 data class Command(val value: CommandData, val signers: List) { +// DOCEND 9 init { require(signers.isNotEmpty()) } @@ -395,6 +409,7 @@ interface NetCommand : CommandData { /** Indicates that this transaction replaces the inputs contract state to another contract state */ data class UpgradeCommand(val upgradedContractClass: Class>) : CommandData +// DOCSTART 6 /** Wraps an object that was signed by a public key, which may be a well known/recognised institutional key. */ @CordaSerializable data class AuthenticatedObject( @@ -403,6 +418,7 @@ data class AuthenticatedObject( val signingParties: List, val value: T ) +// DOCEND 6 /** * A time-window is required for validation/notarization purposes. @@ -457,6 +473,7 @@ class TimeWindow private constructor( override fun toString() = "TimeWindow(fromTime=$fromTime, untilTime=$untilTime)" } +// DOCSTART 5 /** * Implemented by a program that implements business logic on the shared ledger. All participants run this code for * every [LedgerTransaction] they see on the network, for every input and output state. All contracts must accept the @@ -482,6 +499,7 @@ interface Contract { */ val legalContractReference: SecureHash } +// DOCEND 5 /** * Interface which can upgrade state objects issued by a contract to a new state object issued by a different contract. diff --git a/core/src/main/kotlin/net/corda/core/contracts/TransactionVerification.kt b/core/src/main/kotlin/net/corda/core/contracts/TransactionVerification.kt index 47ee213c09..5417169459 100644 --- a/core/src/main/kotlin/net/corda/core/contracts/TransactionVerification.kt +++ b/core/src/main/kotlin/net/corda/core/contracts/TransactionVerification.kt @@ -13,6 +13,7 @@ import java.util.* * A transaction to be passed as input to a contract verification function. Defines helper methods to * simplify verification logic in contracts. */ +// DOCSTART 1 data class TransactionForContract(val inputs: List, val outputs: List, val attachments: List, @@ -20,6 +21,7 @@ data class TransactionForContract(val inputs: List, val origHash: SecureHash, val inputNotary: Party? = null, val timeWindow: TimeWindow? = null) { +// DOCEND 1 override fun hashCode() = origHash.hashCode() override fun equals(other: Any?) = other is TransactionForContract && other.origHash == origHash @@ -37,6 +39,7 @@ data class TransactionForContract(val inputs: List, * currency. To solve this, you would use groupStates with a type of Cash.State and a selector that returns the * currency field: the resulting list can then be iterated over to perform the per-currency calculation. */ + // DOCSTART 2 fun groupStates(ofType: Class, selector: (T) -> K): List> { val inputs = inputs.filterIsInstance(ofType) val outputs = outputs.filterIsInstance(ofType) @@ -47,6 +50,7 @@ data class TransactionForContract(val inputs: List, @Suppress("DEPRECATION") return groupStatesInternal(inGroups, outGroups) } + // DOCEND 2 /** See the documentation for the reflection-based version of [groupStates] */ inline fun groupStates(selector: (T) -> K): List> { @@ -83,7 +87,9 @@ data class TransactionForContract(val inputs: List, * up on both sides of the transaction, but the values must be summed independently per currency. Grouping can * be used to simplify this logic. */ + // DOCSTART 3 data class InOutGroup(val inputs: List, val outputs: List, val groupingKey: K) + // DOCEND 3 } class TransactionResolutionException(val hash: SecureHash) : FlowException() { diff --git a/core/src/main/kotlin/net/corda/core/flows/FlowException.kt b/core/src/main/kotlin/net/corda/core/flows/FlowException.kt index 92a8998288..153baeae46 100644 --- a/core/src/main/kotlin/net/corda/core/flows/FlowException.kt +++ b/core/src/main/kotlin/net/corda/core/flows/FlowException.kt @@ -3,6 +3,7 @@ package net.corda.core.flows import net.corda.core.utilities.CordaException import net.corda.core.utilities.CordaRuntimeException +// DOCSTART 1 /** * Exception which can be thrown by a [FlowLogic] at any point in its logic to unexpectedly bring it to a permanent end. * The exception will propagate to all counterparty flows and will be thrown on their end the next time they wait on a @@ -17,6 +18,7 @@ open class FlowException(message: String?, cause: Throwable?) : CordaException(m constructor(cause: Throwable?) : this(cause?.toString(), cause) constructor() : this(null, null) } +// DOCEND 1 /** * Thrown when a flow session ends unexpectedly due to a type mismatch (the other side sent an object of a type diff --git a/core/src/main/kotlin/net/corda/core/transactions/SignedTransaction.kt b/core/src/main/kotlin/net/corda/core/transactions/SignedTransaction.kt index e100c89793..00f83fdf3e 100644 --- a/core/src/main/kotlin/net/corda/core/transactions/SignedTransaction.kt +++ b/core/src/main/kotlin/net/corda/core/transactions/SignedTransaction.kt @@ -26,9 +26,11 @@ import java.util.* * when verifying composite key signatures, but may be used as individual signatures where a single key is expected to * sign. */ +// DOCSTART 1 data class SignedTransaction(val txBits: SerializedBytes, val sigs: List ) : NamedByHash { +// DOCEND 1 init { require(sigs.isNotEmpty()) } @@ -64,8 +66,10 @@ data class SignedTransaction(val txBits: SerializedBytes, * @throws SignatureException if any signatures are invalid or unrecognised. * @throws SignaturesMissingException if any signatures should have been present but were not. */ + // DOCSTART 2 @Throws(SignatureException::class) fun verifySignatures(vararg allowedToBeMissing: PublicKey): WireTransaction { + // DOCEND 2 // Embedded WireTransaction is not deserialised until after we check the signatures. checkSignaturesAreValid() diff --git a/core/src/main/kotlin/net/corda/core/transactions/TransactionBuilder.kt b/core/src/main/kotlin/net/corda/core/transactions/TransactionBuilder.kt index ce8646d825..91698ecd0c 100644 --- a/core/src/main/kotlin/net/corda/core/transactions/TransactionBuilder.kt +++ b/core/src/main/kotlin/net/corda/core/transactions/TransactionBuilder.kt @@ -77,6 +77,7 @@ open class TransactionBuilder( this.timeWindow = timeWindow } + // DOCSTART 1 /** A more convenient way to add items to this transaction that calls the add* methods for you based on type */ fun withItems(vararg items: Any): TransactionBuilder { for (t in items) { @@ -91,6 +92,7 @@ open class TransactionBuilder( } return this } + // DOCEND 1 /** The signatures that have been collected so far - might be incomplete! */ protected val currentSigs = arrayListOf() diff --git a/core/src/main/kotlin/net/corda/flows/CollectSignaturesFlow.kt b/core/src/main/kotlin/net/corda/flows/CollectSignaturesFlow.kt index f6788653cf..5bd80d9f98 100644 --- a/core/src/main/kotlin/net/corda/flows/CollectSignaturesFlow.kt +++ b/core/src/main/kotlin/net/corda/flows/CollectSignaturesFlow.kt @@ -122,6 +122,7 @@ class CollectSignaturesFlow(val partiallySignedTx: SignedTransaction, partyNode.legalIdentity } + // DOCSTART 1 /** * Get and check the required signature. */ @@ -131,6 +132,7 @@ class CollectSignaturesFlow(val partiallySignedTx: SignedTransaction, it } } + // DOCEND 1 } /** diff --git a/core/src/main/kotlin/net/corda/flows/TwoPartyDealFlow.kt b/core/src/main/kotlin/net/corda/flows/TwoPartyDealFlow.kt index 45b8694c80..4df44568c6 100644 --- a/core/src/main/kotlin/net/corda/flows/TwoPartyDealFlow.kt +++ b/core/src/main/kotlin/net/corda/flows/TwoPartyDealFlow.kt @@ -99,7 +99,10 @@ object TwoPartyDealFlow { logger.trace { "Signed proposed transaction." } progressTracker.currentStep = COLLECTING_SIGNATURES + + // DOCSTART 1 val stx = subFlow(CollectSignaturesFlow(ptx)) + // DOCEND 1 logger.trace { "Got signatures from other party, verifying ... " } diff --git a/docs/source/api-contracts.rst b/docs/source/api-contracts.rst new file mode 100644 index 0000000000..db1c4a0b08 --- /dev/null +++ b/docs/source/api-contracts.rst @@ -0,0 +1,309 @@ +.. highlight:: kotlin +.. raw:: html + + + + +API: Contracts +============== + +.. note:: Before reading this page, you should be familiar with the key concepts of :doc:`key-concepts-contracts`. + +All Corda contracts are JVM classes that implement ``net.corda.core.contracts.Contract``. + +The ``Contract`` interface is defined as follows: + +.. container:: codeset + + .. literalinclude:: ../../core/src/main/kotlin/net/corda/core/contracts/Structures.kt + :language: kotlin + :start-after: DOCSTART 5 + :end-before: DOCEND 5 + +Where: + +* ``verify(tx: TransactionForContract)`` determines whether transactions involving states which reference this + contract type are valid +* ``legalContractReference`` is the hash of the legal prose contract that ``verify`` seeks to express in code + +verify() +-------- + +``verify()`` is a method that doesn't return anything and takes a ``TransactionForContract`` as a parameter. It +either throws an exception if the transaction is considered invalid, or returns normally if the transaction is +considered valid. + +``verify()`` is executed in a sandbox. It does not have access to the enclosing scope, and is not able to access +the network or perform any other I/O. It only has access to the properties defined on ``TransactionForContract`` when +establishing whether a transaction is valid. + +The two simplest ``verify`` functions are the one that accepts all transactions, and the one that rejects all +transactions. + +Here is the ``verify`` that accepts all transactions: + +.. container:: codeset + + .. sourcecode:: kotlin + + override fun verify(tx: TransactionForContract) { + // Always accepts! + } + + .. sourcecode:: java + + @Override + public void verify(TransactionForContract tx) { + // Always accepts! + } + +And here is the ``verify`` that rejects all transactions: + +.. container:: codeset + + .. sourcecode:: kotlin + + override fun verify(tx: TransactionForContract) { + throw IllegalArgumentException("Always rejects!") + } + + .. sourcecode:: java + + @Override + public void verify(TransactionForContract tx) { + throw new IllegalArgumentException("Always rejects!"); + } + +TransactionForContract +^^^^^^^^^^^^^^^^^^^^^^ + +The ``TransactionForContract`` object passed into ``verify()`` represents the full set of information available to +``verify()`` when deciding whether to accept or reject the transaction. It has the following properties: + +.. container:: codeset + + .. literalinclude:: ../../core/src/main/kotlin/net/corda/core/contracts/TransactionVerification.kt + :language: kotlin + :start-after: DOCSTART 1 + :end-before: DOCEND 1 + +Where: + +* ``inputs`` is a list of the transaction's inputs +* ``outputs`` is a list of the transaction's outputs +* ``attachments`` is a list of the transaction's attachments +* ``commands`` is a list of the transaction's commands, and their associated signatures +* ``origHash`` is the transaction's hash +* ``inputNotary`` is the transaction's notary +* ``timestamp`` is the transaction's timestamp + +requireThat() +^^^^^^^^^^^^^ + +Instead of throwing exceptions manually to reject a transaction, we can use the ``requireThat`` DSL: + +.. container:: codeset + + .. sourcecode:: kotlin + + requireThat { + "No inputs should be consumed when issuing an X." using (tx.inputs.isEmpty()) + "Only one output state should be created." using (tx.outputs.size == 1) + val out = tx.outputs.single() as XState + "The sender and the recipient cannot be the same entity." using (out.sender != out.recipient) + "All of the participants must be signers." using (command.signers.containsAll(out.participants)) + "The X's value must be non-negative." using (out.x.value > 0) + } + + .. sourcecode:: java + + requireThat(require -> { + require.using("No inputs should be consumed when issuing an X.", tx.getInputs().isEmpty()); + require.using("Only one output state should be created.", tx.getOutputs().size() == 1); + final XState out = (XState) tx.getOutputs().get(0); + require.using("The sender and the recipient cannot be the same entity.", out.getSender() != out.getRecipient()); + require.using("All of the participants must be signers.", command.getSigners().containsAll(out.getParticipants())); + require.using("The X's value must be non-negative.", out.getX().getValue() > 0); + return null; + }); + +For each <``String``, ``Boolean``> pair within ``requireThat``, if the boolean condition is false, an +``IllegalArgumentException`` is thrown with the corresponding string as the exception message. In turn, this +exception will cause the transaction to be rejected. + +Commands +^^^^^^^^ + +``TransactionForContract`` contains the commands as a list of ``AuthenticatedObject`` instances. +``AuthenticatedObject`` pairs an object with a list of signers. In this case, ``AuthenticatedObject`` pairs a command + with a list of the entities that are required to sign a transaction where this command is present: + +.. container:: codeset + + .. literalinclude:: ../../core/src/main/kotlin/net/corda/core/contracts/Structures.kt + :language: kotlin + :start-after: DOCSTART 6 + :end-before: DOCEND 6 + +Where: + +* ``signers`` is the list of each signer's ``PublicKey`` +* ``signingParties`` is the list of the signer's identities, if known +* ``value`` is the object being signed (a command, in this case) + +Extracting commands +~~~~~~~~~~~~~~~~~~~ +You can use the ``requireSingleCommand()`` helper method to extract commands. + +`` Collection>.requireSingleCommand(klass: Class)`` asserts that +the transaction contains exactly one command of type ``T``, and returns it. If there is not exactly one command of this +type in the transaction, an exception is thrown, rejecting the transaction. + +For ``requireSingleCommand`` to work, all the commands that we wish to match against must be grouped using the same +marker interface. + +Here is an example of using ``requireSingleCommand`` to extract a transaction's command and using it to fork the +execution of ``verify()``: + +.. container:: codeset + + .. sourcecode:: kotlin + + class XContract : Contract { + interface Commands : CommandData { + class Issue : TypeOnlyCommandData(), Commands + class Transfer : TypeOnlyCommandData(), Commands + } + + override fun verify(tx: TransactionForContract) { + val command = tx.commands.requireSingleCommand() + + when (command.value) { + is Commands.Issue -> { + // Issuance verification logic. + } + is Commands.Transfer -> { + // Transfer verification logic. + } + } + } + + override val legalContractReference: SecureHash = SecureHash.sha256("X contract hash") + } + + .. sourcecode:: java + + public class XContract implements Contract { + public interface Commands extends CommandData { + class Issue extends TypeOnlyCommandData implements Commands {} + class Transfer extends TypeOnlyCommandData implements Commands {} + } + + @Override + public void verify(TransactionForContract tx) { + final AuthenticatedObject command = requireSingleCommand(tx.getCommands(), Commands.class); + + if (command.getValue() instanceof Commands.Issue) { + // Issuance verification logic. + } else if (command.getValue() instanceof Commands.Transfer) { + // Transfer verification logic. + } + } + + private final SecureHash legalContractReference = SecureHash.sha256("X contract hash"); + @Override public final SecureHash getLegalContractReference() { return legalContractReference; } + } + +Grouping states +--------------- +Suppose we have the following transaction, where 15 USD is being exchanged for 10 GBP: + +.. image:: resources/ungrouped-tx.png + :scale: 20 + :align: center + +We can imagine that we would like to verify the USD states and the GBP states separately: + +.. image:: resources/grouped-tx.png + :scale: 20 + :align: center + +``TransactionForContract`` provides a ``groupStates`` method to allow you to group states in this way: + +.. container:: codeset + + .. literalinclude:: ../../core/src/main/kotlin/net/corda/core/contracts/TransactionVerification.kt + :language: kotlin + :start-after: DOCSTART 2 + :end-before: DOCEND 2 + +Where ``InOutGroup`` is defined as: + +.. container:: codeset + + .. literalinclude:: ../../core/src/main/kotlin/net/corda/core/contracts/TransactionVerification.kt + :language: kotlin + :start-after: DOCSTART 3 + :end-before: DOCEND 3 + +For example, we could group the states in the transaction above by currency (i.e. by ``amount.token``): + +.. container:: codeset + + .. sourcecode:: kotlin + + val groups: List>> = tx.groupStates(Cash.State::class.java) { + it -> it.amount.token + } + + .. sourcecode:: java + + final List>> groups = tx.groupStates( + Cash.State.class, + it -> it.getAmount().getToken() + ); + +This would produce the following InOutGroups: + +.. image:: resources/in-out-groups.png + +We can now verify these groups individually: + +.. container:: codeset + + .. sourcecode:: kotlin + + for ((in_, out, key) in groups) { + when (key) { + is GBP -> { + // GBP verification logic. + } + is USD -> { + // USD verification logic. + } + } + } + + .. sourcecode:: java + + for (InOutGroup group : groups) { + if (group.getGroupingKey() == USD) { + // USD verification logic. + } else if (group.getGroupingKey() == GBP) { + // GBP verification logic. + } + } + +Legal prose +----------- + +Current, ``legalContractReference`` is simply the SHA-256 hash of a contract: + +.. container:: codeset + + .. literalinclude:: ../../finance/src/main/kotlin/net/corda/contracts/asset/Cash.kt + :language: kotlin + :start-after: DOCSTART 2 + :end-before: DOCEND 2 + +In the future, a contract's legal prose will be included as an attachment instead. \ No newline at end of file diff --git a/docs/source/key-concepts-core-types.rst b/docs/source/api-core-types.rst similarity index 54% rename from docs/source/key-concepts-core-types.rst rename to docs/source/api-core-types.rst index d76da267d8..f86011d2db 100644 --- a/docs/source/key-concepts-core-types.rst +++ b/docs/source/api-core-types.rst @@ -1,30 +1,8 @@ -Core types -========== +API: Core types +=============== -Corda provides a large standard library of data types used to represent the :doc:`key-concepts-data-model` previously described. -In addition, there are a series of helper libraries which provide date manipulation, maths and cryptography functions. - -State and References --------------------- -State objects contain mutable data which we would expect to evolve over the lifetime of a contract. - -A reference to a state in the ledger (whether it has been consumed or not) is represented with a ``StateRef`` object. -If the state ref has been looked up from storage, you will have a ``StateAndRef`` which is simply a ``StateRef`` plus the data. - -The ``ContractState`` type is an interface that all states must implement. A ``TransactionState`` is a simple -container for a ``ContractState`` (the custom data used by a contract program) and additional platform-level state -information, such as the *notary* pointer (see :doc:`key-concepts-consensus-notaries`). - -A number of interfaces then extend ``ContractState``, representing standardised functionality for common kinds -of state such as: - - ``OwnableState`` - A state which has an owner (represented as a ``PublicKey`` which can be a ``CompositeKey``, discussed later). Exposes the owner and a function - for replacing the owner e.g. when an asset is sold. - - ``SchedulableState`` - A state to indicate whether there is some activity to be performed at some future point in time with respect to this - contract, what that activity is and at what point in time it should be initiated. +Corda provides a large standard library of data types used to represent the Corda data model. In addition, there are a +series of helper libraries which provide date manipulation, maths and cryptography functions. NamedByHash and UniqueIdentifier -------------------------------- @@ -38,47 +16,6 @@ This is a combination of a (Java) ``UUID`` representing a globally unique 128 bi string which can be paired with it. For instance the string may represent an existing "weak" (not guaranteed unique) identifier for convenience purposes. - -Transaction lifecycle types ---------------------------- - -A ``WireTransaction`` instance contains the core of a transaction without signatures, and with references to attachments -in place of the attachments themselves (see also :doc:`key-concepts-data-model`). Once signed these are encapsulated in a -``SignedTransaction`` instance. For processing a transaction (i.e. to verify it) a ``SignedTransaction`` is then converted to a -``LedgerTransaction``, which involves verifying the signatures and associating them to the relevant command(s), and -resolving the attachment references to the attachments. Commands with valid signatures are encapsulated in the -``AuthenticatedObject`` type. - -.. note:: A ``LedgerTransaction`` has not necessarily had its contract code executed, and thus could be contract-invalid - (but not signature-invalid). You can use the ``verify`` method as shown below to validate the contracts. - -When constructing a new transaction from scratch, you use ``TransactionBuilder``, which is a mutable transaction that -can be signed once its construction is complete. This builder class should be used to create the initial transaction representation -(before signature, before verification). It is intended to be passed around code that may edit it by adding new states/commands. -Then once the states and commands are right then an initial DigitalSignature.WithKey can be added to freeze the transaction data. -Typically, the signInitialTransaction method on the flow's serviceHub object will be used to look up the default node identity PrivateKey, -sign the transaction and return a partially signed SignedTransaction. This can then be distributed to other participants using the :doc:`key-concepts-flow-framework`. - -Here's an example of building a transaction that creates an issuance of bananas (note that bananas are not a real -contract type in the library): - -.. container:: codeset - - .. sourcecode:: kotlin - - val notaryToUse: Party = ... - val txb = TransactionBuilder(notary = notaryToUse).withItems(BananaState(Amount(20, Bananas), fromCountry = "Elbonia")) - txb.setTime(Instant.now(), notaryToUse, 30.seconds) - // Carry out the initial signing of the transaction and creation of a (partial) SignedTransation. - val stx = serviceHub.signInitialTransaction(txb) - // Alternatively, let's just check it verifies pretending it was fully signed. To do this, we get - // a WireTransaction, which is what the SignedTransaction wraps. Thus by verifying that directly we - // skip signature checking. - txb.toWireTransaction().toLedgerTransaction(services).verify() - -In a unit test, you would typically use a freshly created ``MockServices`` object, or more realistically, you would -write your tests using the :doc:`domain specific language for writing tests `. - Party and CompositeKey ---------------------- diff --git a/docs/source/api-flows.rst b/docs/source/api-flows.rst new file mode 100644 index 0000000000..4d3367bb1c --- /dev/null +++ b/docs/source/api-flows.rst @@ -0,0 +1,314 @@ +.. highlight:: kotlin +.. raw:: html + + + + +API: Flows +========== + +.. note:: Before reading this page, you should be familiar with the key concepts of :doc:`key-concepts-flows`. + +An example flow +--------------- +Let's imagine a flow for agreeing a basic ledger update between Alice and Bob. This flow will have two sides: + +* An ``Initiator`` side, that will initiate the request to update the ledger +* A ``Responder`` side, that will respond to the request to update the ledger + +Initiator +^^^^^^^^^ +In our flow, the Initiator flow class will be doing the majority of the work: + +*Part 1 - Build the transaction* + +1. Choose a notary for the transaction +2. Create a transaction builder +3. Extract any input states from the vault and add them to the builder +4. Create any output states and add them to the builder +5. Add any commands, attachments and timestamps to the builder + +*Part 2 - Sign the transaction* + +6. Sign the transaction builder +7. Convert the builder to a signed transaction + +*Part 3 - Verify the transaction* + +8. Verify the transaction by running its contracts + +*Part 4 - Gather the counterparty's signature* + +9. Send the transaction to the counterparty +10. Wait to receive back the counterparty's signature +11. Add the counterparty's signature to the transaction +12. Verify the transaction's signatures + +*Part 5 - Finalize the transaction* + +13. Send the transaction to the notary +14. Wait to receive back the notarised transaction +15. Record the transaction locally +16. Store any relevant states in the vault +17. Send the transaction to the counterparty for recording + +We can visualize the work performed by initiator as follows: + +.. image:: resources/flow-overview.png + +Responder +^^^^^^^^^ +To respond to these actions, the responder takes the following steps: + +*Part 1 - Sign the transaction* + +1. Receive the transaction from the counterparty +2. Verify the transaction's existing signatures +3. Verify the transaction by running its contracts +4. Generate a signature over the transaction +5. Send the signature back to the counterparty + +*Part 2 - Record the transaction* + +6. Receive the notarised transaction from the counterparty +7. Record the transaction locally +8. Store any relevant states in the vault + +FlowLogic +--------- +In practice, a flow is implemented as one or more communicating ``FlowLogic`` subclasses. Each ``FlowLogic`` subclass +must override ``FlowLogic.call()``, which describes the actions it will take as part of the flow. + +So in the example above, we would have an ``Initiator`` ``FlowLogic`` subclass and a ``Responder`` ``FlowLogic`` +subclass. The actions of the initiator's side of the flow would be defined in ``Initiator.call``, and the actions +of the responder's side of the flow would be defined in ``Responder.call``. + +FlowLogic annotations +^^^^^^^^^^^^^^^^^^^^^ +Any flow that you wish to start either directly via RPC or as a subflow must be annotated with the +``@InitiatingFlow`` annotation. Additionally, if you wish to start the flow via RPC, you must annotate it with the +``@StartableByRPC`` annotation. + +Any flow that responds to a message from another flow must be annotated with the ``@InitiatedBy`` annotation. +``@InitiatedBy`` takes the class of the flow it is responding to as its single parameter. + +So in our example, we would have: + +.. container:: codeset + + .. sourcecode:: kotlin + + @InitiatingFlow + @StartableByRPC + class Initiator(): FlowLogic() { + + ... + + @InitiatedBy(Initiator::class) + class Responder(val otherParty: Party) : FlowLogic() { + + .. sourcecode:: java + + @InitiatingFlow + @StartableByRPC + public static class Initiator extends FlowLogic { + + ... + + @InitiatedBy(Initiator.class) + public static class Responder extends FlowLogic { + +Additionally, any flow that is started by a ``SchedulableState`` must be annotated with the ``@SchedulableFlow`` +annotation. + +ServiceHub +---------- +Within ``FlowLogic.call()``, the flow developer has access to the node's ``ServiceHub`` that provides access to the +various services the node provides. + +The key ``ServiceHub`` services are: + +* ``ServiceHub.networkMapCache`` + * Provides info on other nodes on the network (e.g. notaries…) +* ``ServiceHub.vaultService`` + * Stores the node’s current and historic states +* ``ServiceHub.storageService`` + * Stores additional info such as transactions and attachments +* ``ServiceHub.keyManagementService`` + * Manages the node’s digital signing keys +* ``ServiceHub.myInfo`` + * Other information about the node +* ``ServiceHub.clock`` + * Provides access to the node’s internal time and date + +Some common tasks performed using the ``ServiceHub`` are: + +* Looking up your own identity or the identity of a counterparty using the ``networkMapCache`` +* Identifying the providers of a given service (e.g. a notary service) using the ``networkMapCache`` +* Retrieving states to use in a transaction using the ``vaultService`` +* Retrieving attachments and past transactions to use in a transaction using the ``storageService`` +* Creating a timestamp using the ``clock`` +* Signing a transaction using the ``keyManagementService`` + +Common flow tasks +----------------- +There are a number of common tasks that you will need to perform within ``FlowLogic.call`` in order to agree ledger +updates. This section details the API for the most common tasks. + +Retrieving information about other nodes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +We use the network map to retrieve information about other nodes on the network: + +.. container:: codeset + + .. sourcecode:: kotlin + + val networkMap = serviceHub.networkMapCache + + val allNodes = networkMap.partyNodes + val allNotaryNodes = networkMap.notaryNodes + val randomNotaryNode = networkMap.getAnyNotary() + + val alice = networkMap.getNodeByLegalName(X500Name("CN=Alice,O=Alice,L=London,C=UK")) + val bob = networkMap.getNodeByLegalIdentityKey(bobsKey) + + .. sourcecode:: java + + final NetworkMapCache networkMap = getServiceHub().getNetworkMapCache(); + + final List allNodes = networkMap.getPartyNodes(); + final List allNotaryNodes = networkMap.getNotaryNodes(); + final Party randomNotaryNode = networkMap.getAnyNotary(null); + + final NodeInfo alice = networkMap.getNodeByLegalName(new X500Name("CN=Alice,O=Alice,L=London,C=UK")); + final NodeInfo bob = networkMap.getNodeByLegalIdentityKey(bobsKey); + +Communication between parties +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +``FlowLogic`` instances communicate using three functions: + +* ``send(otherParty: Party, payload: Any)`` + * Sends the ``payload`` object to the ``otherParty`` +* ``receive(receiveType: Class, otherParty: Party)`` + * Receives an object of type ``receiveType`` from the ``otherParty`` +* ``sendAndReceive(receiveType: Class, otherParty: Party, payload: Any)`` + * Sends the ``payload`` object to the ``otherParty``, and receives an object of type ``receiveType`` back + +Each ``FlowLogic`` subclass can be annotated to respond to messages from a given *counterparty* flow using the +``@InitiatedBy`` annotation. When a node first receives a message from a given ``FlowLogic.call()`` invocation, it +responds as follows: + +* The node checks whether they have a ``FlowLogic`` subclass that is registered to respond to the ``FlowLogic`` that + is sending the message: + + a. If yes, the node starts an instance of this ``FlowLogic`` by invoking ``FlowLogic.call()`` + b. Otherwise, the node ignores the message + +* The counterparty steps through their ``FlowLogic.call()`` method until they encounter a call to ``receive()``, at + which point they process the message from the initiator + +Upon calling ``receive()``/``sendAndReceive()``, the ``FlowLogic`` is suspended until it receives a response. + +UntrustworthyData +~~~~~~~~~~~~~~~~~ +``send()`` and ``sendAndReceive()`` return a payload wrapped in an ``UntrustworthyData`` instance. This is a +reminder that any data received off the wire is untrustworthy and must be verified. + +We verify the ``UntrustworthyData`` and retrieve its payload by calling ``unwrap``: + +.. container:: codeset + + .. sourcecode:: kotlin + + val partSignedTx = receive(otherParty).unwrap { partSignedTx -> + val wireTx = partSignedTx.verifySignatures(keyPair.public, notaryPubKey) + wireTx.toLedgerTransaction(serviceHub).verify() + partSignedTx + } + + .. sourcecode:: java + + final SignedTransaction partSignedTx = receive(SignedTransaction.class, otherParty) + .unwrap(tx -> { + try { + final WireTransaction wireTx = tx.verifySignatures(keyPair.getPublic(), notaryPubKey); + wireTx.toLedgerTransaction(getServiceHub()).verify(); + } catch (SignatureException ex) { + throw new FlowException(tx.getId() + " failed signature checks", ex); + } + return tx; + }); + +Subflows +-------- +Corda provides a number of built-in flows that should be used for handling common tasks. The most important are: + +* ``CollectSignaturesFlow``, which should be used to collect a transaction's required signatures +* ``FinalityFlow``, which should be used to notarise and record a transaction +* ``ResolveTransactionsFlow``, which should be used to verify the chain of inputs to a transaction +* ``ContractUpgradeFlow``, which should be used to change a state's contract +* ``NotaryChangeFlow``, which should be used to change a state's notary + +These flows are designed to be used as building blocks in your own flows. You invoke them by calling +``FlowLogic.subFlow`` from within your flow's ``call`` method. Here is an example from ``TwoPartyDealFlow.kt``: + +.. container:: codeset + + .. literalinclude:: ../../core/src/main/kotlin/net/corda/flows/TwoPartyDealFlow.kt + :language: kotlin + :start-after: DOCSTART 1 + :end-before: DOCEND 1 + :dedent: 12 + +In this example, we are starting a ``CollectSignaturesFlow``, passing in a partially signed transaction, and +receiving back a fully-signed version of the same transaction. + +Subflows in our example flow +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +In practice, many of the actions in our example flow would be automated using subflows: + +* Parts 2-4 of ``Initiator.call`` should be automated by invoking ``CollectSignaturesFlow`` +* Part 5 of ``Initiator.call`` should be automated by invoking ``FinalityFlow`` +* Part 1 of ``Responder.call`` should be automated by invoking ``SignTransactionFlow`` +* Part 2 of ``Responder.call`` will be handled automatically when the counterparty invokes ``FinalityFlow`` + +FlowException +------------- +Suppose a node throws an exception while running a flow. Any counterparty flows waiting for a message from the node +(i.e. as part of a call to ``receive`` or ``sendAndReceive``) will be notified that the flow has unexpectedly +ended and will themselves end. However, the exception thrown will not be propagated back to the counterparties. + +If you wish to notify any waiting counterparties of the cause of the exception, you can do so by throwing a +``FlowException``: + +.. container:: codeset + + .. literalinclude:: ../../core/src/main/kotlin/net/corda/core/flows/FlowException.kt + :language: kotlin + :start-after: DOCSTART 1 + :end-before: DOCEND 1 + +The flow framework will automatically propagate the ``FlowException`` back to the waiting counterparties. + +There are many scenarios in which throwing a ``FlowException`` would be appropriate: + +* A transaction doesn't ``verify()`` +* A transaction's signatures are invalid +* The transaction does not match the parameters of the deal as discussed +* You are reneging on a deal + +Suspending flows +---------------- +In order for nodes to be able to run multiple flows concurrently, and to allow flows to survive node upgrades and +restarts, flows need to be checkpointable and serializable to disk. + +This is achieved by marking any function invoked from within ``FlowLogic.call()`` with an ``@Suspendable`` annotation. + +We can see an example in ``CollectSignaturesFlow``: + +.. container:: codeset + + .. literalinclude:: ../../core/src/main/kotlin/net/corda/flows/CollectSignaturesFlow.kt + :language: kotlin + :start-after: DOCSTART 1 + :end-before: DOCEND 1 \ No newline at end of file diff --git a/docs/source/api-states.rst b/docs/source/api-states.rst new file mode 100644 index 0000000000..e25d8ebd75 --- /dev/null +++ b/docs/source/api-states.rst @@ -0,0 +1,147 @@ +API: States +=========== + +.. note:: Before reading this page, you should be familiar with the key concepts of :doc:`key-concepts-states`. + +ContractState +------------- +In Corda, states are classes that implement ``ContractState``. The ``ContractState`` interface is defined as follows: + +.. container:: codeset + + .. literalinclude:: ../../core/src/main/kotlin/net/corda/core/contracts/Structures.kt + :language: kotlin + :start-after: DOCSTART 1 + :end-before: DOCEND 1 + +Where: + +* ``contract`` is the ``Contract`` class defining the constraints on transactions involving states of this type +* ``participants`` is a ``List`` of the ``AbstractParty`` who are considered to have a stake in the state. For example, + all the ``participants`` will: + + * Need to sign a notary-change transaction for this state + * Receive any committed transactions involving this state as part of ``FinalityFlow`` + +The vault +--------- +Each node has a vault, where it stores the states that are "relevant" to the node's owner. Whenever the node sees a +new transaction, it performs a relevancy check to decide whether to add each of the transaction's output states to +its vault. The default vault implementation decides whether a state is relevant as follows: + + * The vault will store any state for which it is one of the ``participants`` + * This behavior is overridden for states that implement ``LinearState`` or ``OwnableState`` (see below) + +If a state is not considered relevant, the node will still store the transaction in its local storage, but it will +not track the transaction's states in its vault. + +ContractState sub-interfaces +---------------------------- +There are two common optional sub-interfaces of ``ContractState``: + +* ``LinearState``, which helps represent objects that have a constant identity over time +* ``OwnableState``, which helps represent fungible assets + +For example, a cash is an ``OwnableState`` - you don't have a specific piece of cash you are tracking over time, but +rather a total amount of cash that you can combine and divide at will. A contract, on the other hand, cannot be +merged with other contracts of the same type - it has a unique separate identity over time. + +We can picture the hierarchy as follows: + +.. image:: resources/state-hierarchy.png + +LinearState +^^^^^^^^^^^ +``LinearState`` models facts that have a constant identity over time. Remember that in Corda, states are immutable and +can't be updated directly. Instead, we represent an evolving fact as a sequence of states where every state is a +``LinearState`` that shares the same ``linearId``. Each sequence of linear states represents the lifecycle of a given +fact up to the current point in time. It represents the historic audit trail of how the fact evolved over time to its +current "state". + +The ``LinearState`` interface is defined as follows: + +.. container:: codeset + + .. literalinclude:: ../../core/src/main/kotlin/net/corda/core/contracts/Structures.kt + :language: kotlin + :start-after: DOCSTART 2 + :end-before: DOCEND 2 + +Where: + +* ``linearId`` is a ``UniqueIdentifier`` that: + + * Allows the successive versions of the fact to be linked over time + * Provides an ``externalId`` for referencing the state in external systems + +* ``isRelevant(ourKeys: Set)`` overrides the default vault implementation's relevancy check. You would + generally override it to check whether ``ourKeys`` is relevant to the state at hand in some way. + +The vault tracks the head (i.e. the most recent version) of each ``LinearState`` chain (i.e. each sequence of +states all sharing a ``linearId``). To create a transaction updating a ``LinearState``, we retrieve the state from the +vault using its ``linearId``. + +OwnableState +^^^^^^^^^^^^ +``OwnableState`` models fungible assets. Fungible assets are assets for which it's the total amount held that is +important, rather than the actual units held. US dollars are an example of a fungible asset - we do not track the +individual dollar bills held, but rather the total amount of dollars. + +The ``OwnableState`` interface is defined as follows: + +.. container:: codeset + + .. literalinclude:: ../../core/src/main/kotlin/net/corda/core/contracts/Structures.kt + :language: kotlin + :start-after: DOCSTART 3 + :end-before: DOCEND 3 + +Where: + +* ``owner`` is the ``PublicKey`` of the asset's owner + + * ``OwnableState`` also override the default behavior of the vault's relevancy check. The default vault + implementation will track any ``OwnableState`` of which it is the owner. + +* ``withNewOwner(newOwner: PublicKey)`` creates an identical copy of the state, only with a new owner + +Other interfaces +^^^^^^^^^^^^^^^^ +``ContractState`` has several more sub-interfaces that can optionally be implemented: + +* ``QueryableState``, which allows the state to be queried in the node's database using SQL (see + :doc:`persistence`) +* ``SchedulableState``, which allows us to schedule future actions for the state (e.g. a coupon on a bond) (see + :doc:`event-scheduling`) + +User-defined fields +------------------- +Beyond implementing ``LinearState`` or ``OwnableState``, the definition of the state is up to the CorDapp developer. +You can define any additional class fields and methods you see fit. + +For example, here is a relatively complex state definition, for a state representing cash: + +.. container:: codeset + + .. literalinclude:: ../../finance/src/main/kotlin/net/corda/contracts/asset/Cash.kt + :language: kotlin + :start-after: DOCSTART 1 + :end-before: DOCEND 1 + +TransactionState +---------------- +When a ``ContractState`` is added to a ``TransactionBuilder``, it is wrapped in a ``TransactionState``: + +.. container:: codeset + + .. literalinclude:: ../../core/src/main/kotlin/net/corda/core/contracts/Structures.kt + :language: kotlin + :start-after: DOCSTART 4 + :end-before: DOCEND 4 + +Where: + +* ``data`` is the state to be stored on-ledger +* ``notary`` is the notary service for this state +* ``encumbrance`` points to another state that must also appear as an input to any transaction consuming this + state \ No newline at end of file diff --git a/docs/source/api-transactions.rst b/docs/source/api-transactions.rst new file mode 100644 index 0000000000..9b736b3ce8 --- /dev/null +++ b/docs/source/api-transactions.rst @@ -0,0 +1,299 @@ +.. highlight:: kotlin +.. raw:: html + + + + +API: Transactions +================= + +.. note:: Before reading this page, you should be familiar with the key concepts of :doc:`key-concepts-transactions`. + +Transaction types +----------------- +There are two types of transaction in Corda: + +* ``TransactionType.NotaryChange``, used to change the notary for a set of states +* ``TransactionType.General``, for transactions other than notary-change transactions + +Notary-change transactions +^^^^^^^^^^^^^^^^^^^^^^^^^^ +A single Corda network will usually have multiple notary services. To commit a transaction, we require a signature +from the notary service associated with each input state. If we tried to commit a transaction where the input +states were associated with different notary services, the transaction would require a signature from multiple notary +services, creating a complicated multi-phase commit scenario. To prevent this, every input state in a transaction +must be associated the same notary. + +However, we will often need to create a transaction involving input states associated with different notaries. Before +we can create this transaction, we will need to change the notary service associated with each state by: + +* Deciding which notary service we want to notarise the transaction +* For each set of inputs states that point to the same notary service that isn't the desired notary service, creating a + ``TransactionType.NotaryChange`` transaction that: + + * Consumes the input states pointing to the old notary + * Outputs the same states, but that now point to the new notary + +* Using the outputs of the notary-change transactions as inputs to a standard ``TransactionType.General`` transaction + +In practice, this process is handled automatically by a built-in flow called ``NotaryChangeFlow``. See +:doc:`api-flows` for more details. + +Transaction workflow +-------------------- +There are four states the transaction can occupy: + +* ``TransactionBuilder``, a mutable transaction-in-construction +* ``WireTransaction``, an immutable transaction +* ``SignedTransaction``, a ``WireTransaction`` with 1+ associated signatures +* ``LedgerTransaction``, a resolved ``WireTransaction`` that can be checked for contract validity + +Here are the possible transitions between transaction states: + +.. image:: resources/transaction-flow.png + +TransactionBuilder +------------------ +Creating a builder +^^^^^^^^^^^^^^^^^^ +The first step when building a transaction is to create a ``TransactionBuilder``: + +.. container:: codeset + + .. sourcecode:: kotlin + + // A general transaction builder. + val generalTxBuilder = TransactionType.General.Builder() + + // A notary-change transaction builder. + val notaryChangeTxBuilder = TransactionType.NotaryChange.Builder() + + .. sourcecode:: java + + // A general transaction builder. + final TransactionBuilder generalTxBuilder = new TransactionType.General.Builder(); + + // A notary-change transaction builder. + final TransactionBuilder notaryChangeTxBuilder = new TransactionType.NotaryChange.Builder(); + +Adding items +^^^^^^^^^^^^ +The transaction builder is mutable. We add items to it using the ``TransactionBuilder.withItems`` method: + +.. container:: codeset + + .. literalinclude:: ../../core/src/main/kotlin/net/corda/core/transactions/TransactionBuilder.kt + :language: kotlin + :start-after: DOCSTART 1 + :end-before: DOCEND 1 + +``withItems`` takes a ``vararg`` of objects and adds them to the builder based on their type: + +* ``StateAndRef`` objects are added as input states +* ``TransactionState`` and ``ContractState`` objects are added as output states +* ``Command`` objects are added as commands + +Passing in objects of any other type will cause an ``IllegalArgumentException`` to be thrown. + +You can also add the following items to the transaction: + +* ``TimeWindow`` objects, using ``TransactionBuilder.setTime`` +* ``SecureHash`` objects referencing the hash of an attachment stored on the node, using + ``TransactionBuilder.addAttachment`` + +Input states +~~~~~~~~~~~~ +Input states are added to a transaction as ``StateAndRef`` instances, rather than as ``ContractState`` instances. + +A ``StateAndRef`` combines a ``ContractState`` with a pointer to the transaction that created it. This series of +pointers from the input states back to the transactions that created them is what allows a node to work backwards and +verify the entirety of the transaction chain. It is defined as: + +.. container:: codeset + + .. literalinclude:: ../../core/src/main/kotlin/net/corda/core/contracts/Structures.kt + :language: kotlin + :start-after: DOCSTART 7 + :end-before: DOCEND 7 + +Where ``StateRef`` is defined as: + +.. container:: codeset + + .. literalinclude:: ../../core/src/main/kotlin/net/corda/core/contracts/Structures.kt + :language: kotlin + :start-after: DOCSTART 8 + :end-before: DOCEND 8 + +``StateRef.index`` is the state's position in the outputs of the transaction that created it. In this way, a +``StateRef`` allows a notary service to uniquely identify the existing states that a transaction is marking as historic. + +Output states +~~~~~~~~~~~~~ +Since a transaction's output states do not exist until the transaction is committed, they cannot be referenced as the +outputs of previous transactions. Instead, we create the desired output states as ``ContractState`` instances, and +add them to the transaction. + +Commands +~~~~~~~~ +Commands are added to the transaction as ``Command`` instances. ``Command`` combines a ``CommandData`` +instance representing the type of the command with a list of the command's required signers. It is defined as: + +.. container:: codeset + + .. literalinclude:: ../../core/src/main/kotlin/net/corda/core/contracts/Structures.kt + :language: kotlin + :start-after: DOCSTART 9 + :end-before: DOCEND 9 + +Signing the builder +^^^^^^^^^^^^^^^^^^^ +Once the builder is ready, we finalize it by signing it and converting it into a ``SignedTransaction``: + +.. container:: codeset + + .. sourcecode:: kotlin + + // Finalizes the builder by signing it with our primary signing key. + val signedTx1 = serviceHub.signInitialTransaction(unsignedTx) + + // Finalizes the builder by signing it with a different key. + val signedTx2 = serviceHub.signInitialTransaction(unsignedTx, otherKey) + + // Finalizes the builder by signing it with a set of keys. + val signedTx3 = serviceHub.signInitialTransaction(unsignedTx, otherKeys) + + .. sourcecode:: java + + // Finalizes the builder by signing it with our primary signing key. + final SignedTransaction signedTx1 = getServiceHub().signInitialTransaction(unsignedTx); + + // Finalizes the builder by signing it with a different key. + final SignedTransaction signedTx2 = getServiceHub().signInitialTransaction(unsignedTx, otherKey); + + // Finalizes the builder by signing it with a set of keys. + final SignedTransaction signedTx3 = getServiceHub().signInitialTransaction(unsignedTx, otherKeys); + +SignedTransaction +----------------- +A ``SignedTransaction`` is a combination of an immutable ``WireTransaction`` and a list of signatures over that +transaction: + +.. container:: codeset + + .. literalinclude:: ../../core/src/main/kotlin/net/corda/core/transactions/SignedTransaction.kt + :language: kotlin + :start-after: DOCSTART 1 + :end-before: DOCEND 1 + +Verifying the signatures +^^^^^^^^^^^^^^^^^^^^^^^^ +The signatures on a ``SignedTransaction`` have not necessarily been checked for validity. We check them using +``SignedTransaction.verifySignatures``: + +.. container:: codeset + + .. literalinclude:: ../../core/src/main/kotlin/net/corda/core/transactions/SignedTransaction.kt + :language: kotlin + :start-after: DOCSTART 2 + :end-before: DOCEND 2 + +``verifySignatures`` takes a ``vararg`` of the public keys for which the signatures are allowed to be missing. If the +transaction is missing any signatures without the corresponding public keys being passed in, a +``SignaturesMissingException`` is thrown. + +Verifying the transaction +^^^^^^^^^^^^^^^^^^^^^^^^^ +Verifying a transaction is a multi-step process: + +* We check the transaction's signatures: + +.. container:: codeset + + .. sourcecode:: kotlin + + subFlow(ResolveTransactionsFlow(transactionToVerify, partyWithTheFullChain)) + + .. sourcecode:: java + + subFlow(new ResolveTransactionsFlow(transactionToVerify, partyWithTheFullChain)); + +* Before verifying the transaction, we need to retrieve from the proposer(s) of the transaction any parts of the + transaction chain that our node doesn't currently have in its local storage: + +.. container:: codeset + + .. sourcecode:: kotlin + + subFlow(ResolveTransactionsFlow(transactionToVerify, partyWithTheFullChain)) + + .. sourcecode:: java + + subFlow(new ResolveTransactionsFlow(transactionToVerify, partyWithTheFullChain)); + +* To verify the transaction, we first need to resolve any state references and attachment hashes by converting the + ``SignedTransaction`` into a ``LedgerTransaction``. We can then verify the fully-resolved transaction: + +.. container:: codeset + + .. sourcecode:: kotlin + + partSignedTx.tx.toLedgerTransaction(serviceHub).verify() + + .. sourcecode:: java + + partSignedTx.getTx().toLedgerTransaction(getServiceHub()).verify(); + +* We will generally also want to conduct some custom validation of the transaction, beyond what is provided for in the + contract: + +.. container:: codeset + + .. sourcecode:: kotlin + + val ledgerTransaction = partSignedTx.tx.toLedgerTransaction(serviceHub) + val inputStateAndRef = ledgerTransaction.inputs.single() + val input = inputStateAndRef.state.data as MyState + if (input.value > 1000000) { + throw FlowException("Proposed input value too high!") + } + + .. sourcecode:: java + + final LedgerTransaction ledgerTransaction = partSignedTx.getTx().toLedgerTransaction(getServiceHub()); + final StateAndRef inputStateAndRef = ledgerTransaction.getInputs().get(0); + final MyState input = (MyState) inputStateAndRef.getState().getData(); + if (input.getValue() > 1000000) { + throw new FlowException("Proposed input value too high!"); + } + +Signing the transaction +^^^^^^^^^^^^^^^^^^^^^^^ +We add an additional signature to an existing ``SignedTransaction`` using: + +.. container:: codeset + + .. sourcecode:: kotlin + + val fullySignedTx = serviceHub.addSignature(partSignedTx) + + .. sourcecode:: java + + SignedTransaction fullySignedTx = getServiceHub().addSignature(partSignedTx); + +We can also generate a signature over the transaction without adding it to the transaction directly by using: + +.. container:: codeset + + .. sourcecode:: kotlin + + val signature = serviceHub.createSignature(partSignedTx) + + .. sourcecode:: java + + DigitalSignature.WithKey signature = getServiceHub().createSignature(partSignedTx); + +Notarising and recording +^^^^^^^^^^^^^^^^^^^^^^^^ +Notarising and recording a transaction is handled by a built-in flow called ``FinalityFlow``. See +:doc:`api-flows` for more details. \ No newline at end of file diff --git a/docs/source/api.rst b/docs/source/api.rst new file mode 100644 index 0000000000..de10eaf1a1 --- /dev/null +++ b/docs/source/api.rst @@ -0,0 +1,12 @@ +API overview +============ + +This section describes the APIs that are available for the development of CorDapps: + +* :doc:`api-states` +* :doc:`api-contracts` +* :doc:`api-transactions` +* :doc:`api-flows` +* :doc:`api-core-types` + +Before reading this page, you should be familiar with the key concepts of Corda: :doc:`key-concepts`. diff --git a/docs/source/azure-vm.rst b/docs/source/azure-vm.rst index 50f94d072e..bc5ae24fa4 100644 --- a/docs/source/azure-vm.rst +++ b/docs/source/azure-vm.rst @@ -59,7 +59,7 @@ Define the version of Corda you want on your nodes and the type of notary. .. image:: resources/azure_multi_node_step3.png :width: 300px - + Click 'OK' STEP 4: Summary @@ -146,7 +146,7 @@ In the browser window type the following URL to send a Yo message to a target no .. sourcecode:: shell http://(public IP address):(port)/api/yo/yo?target=(legalname of target node) - + where (public IP address) is the public IP address of one of your Corda nodes on the Azure Corda network and (port) is the web server port number for your Corda node, 10004 by default and (legalname of target node) is the Legal Name for the target node as defined in the node.conf file, for example: .. sourcecode:: shell @@ -197,7 +197,7 @@ You can open log files with any text editor. .. image:: resources/azure_syslog.png :width: 300px - + Next Steps ---------- Now you have built a Corda network and used a basic Corda CorDapp do go and visit the `dedicated Corda website `_ diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index dc833934c5..1b267689e0 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -530,7 +530,7 @@ New features in this release: are trees of public keys in which interior nodes can have validity thresholds attached, thus allowing boolean formulas of keys to be created. This is similar to Bitcoin's multi-sig support and the data model is the same as the InterLedger Crypto-Conditions spec, which should aid interop in future. Read more about - key trees in the ":doc:`key-concepts-core-types`" article. + key trees in the ":doc:`api-core-types`" article. * A new tutorial has been added showing how to use transaction attachments in more detail. * Testnet @@ -546,7 +546,7 @@ New features in this release: * Standalone app development: * The Corda libraries that app developers need to link against can now be installed into your local Maven - repository, where they can then be used like any other JAR. See :doc:`creating-a-cordapp`. + repository, where they can then be used like any other JAR. See :doc:`running-a-node`. * User interfaces: @@ -705,8 +705,8 @@ Highlights of this release: We have new documentation on: * :doc:`event-scheduling` -* :doc:`key-concepts-core-types` -* :doc:`key-concepts-consensus-notaries` +* :doc:`core-types` +* :doc:`key-concepts-consensus` Summary of API changes (not exhaustive): diff --git a/docs/source/clientrpc.rst b/docs/source/clientrpc.rst index 82def31fed..38e8661c82 100644 --- a/docs/source/clientrpc.rst +++ b/docs/source/clientrpc.rst @@ -86,7 +86,7 @@ Whitelisting classes with the Corda node To avoid the RPC interface being wide open to all classes on the classpath, Cordapps have to whitelist any classes they require with the serialization framework of Corda, if they are not one of those whitelisted by default in ``DefaultWhitelist``, via either the plugin architecture or simply -with the annotation ``@CordaSerializable``. See :doc:`creating-a-cordapp` or :doc:`serialization`. An example is shown in :doc:`tutorial-clientrpc-api`. +with the annotation ``@CordaSerializable``. See :doc:`running-a-node` or :doc:`serialization`. An example is shown in :doc:`tutorial-clientrpc-api`. .. warning:: We will be replacing the use of Kryo in the serialization framework and so additional changes here are likely. diff --git a/docs/source/contract-upgrade.rst b/docs/source/contract-upgrade.rst index ac3600165a..e448ade570 100644 --- a/docs/source/contract-upgrade.rst +++ b/docs/source/contract-upgrade.rst @@ -4,7 +4,7 @@ -Upgrading Contracts +Upgrading contracts =================== While every care is taken in development of contract code, diff --git a/docs/source/corda-plugins.rst b/docs/source/corda-plugins.rst deleted file mode 100644 index 281c6874ec..0000000000 --- a/docs/source/corda-plugins.rst +++ /dev/null @@ -1,54 +0,0 @@ -The Corda plugin framework -========================== - -The intention is that Corda is a common platform, which will be extended -by numerous application extensions (CorDapps). These extensions will -package together all of the Corda contract code, state structures, -protocols/flows to create and modify state as well as RPC extensions for -node clients. Details of writing these CorDapps is given elsewhere -:doc:`creating-a-cordapp`. - -To enable these plugins to register dynamically with the Corda framework -the node uses the Java ``ServiceLoader`` to locate and load the plugin -components during the ``AbstractNode.start`` call. Therefore, -to be recognised as a plugin the component must: - -1. Include a default constructable class extending from -``net.corda.core.node.CordaPluginRegistry`` which overrides the relevant -registration methods. - -2. Include a resource file named -``net.corda.core.node.CordaPluginRegistry`` in the ``META-INF.services`` -path. This must include a line containing the fully qualified name of -the ``CordaPluginRegistry`` implementation class. Multiple plugin -registries are allowed in this file if desired. - -3. The plugin component must be on the classpath. In the normal use this -means that it should be present within the plugins subfolder of the -node's workspace. - -4. As a plugin the registered components are then allowed access to some -of the node internal subsystems. - -5. The overridden properties on the registry class information about the different -extensions to be created, or registered at startup. In particular: - - a. The ``webApis`` property is a list of JAX-RS annotated REST access - classes. These classes will be constructed by the bundled web server - and must have a single argument constructor taking a ``CordaRPCOps`` - reference. This will allow it to communicate with the node process - via the RPC interface. These web APIs will not be available if the - bundled web server is not started. - - b. The ``staticServeDirs`` property maps static web content to virtual - paths and allows simple web demos to be distributed within the CorDapp - jars. These static serving directories will not be available if the - bundled web server is not started. - - c. The ``customizeSerialization`` function allows classes to be whitelisted - for object serialisation, over and above those tagged with the ``@CordaSerializable`` - annotation. In general the annotation should be preferred. For - instance new state types will need to be explicitly registered. This will be called at - various points on various threads and needs to be stable and thread safe. See - :doc:`serialization`. - diff --git a/docs/source/corda-repo-layout.rst b/docs/source/corda-repo-layout.rst new file mode 100644 index 0000000000..0c95bb74f2 --- /dev/null +++ b/docs/source/corda-repo-layout.rst @@ -0,0 +1,30 @@ +Corda repo layout +================= + +The Corda repository comprises the following folders: + +* **buildSrc** contains necessary gradle plugins to build Corda +* **client** contains libraries for connecting to a node, working with it remotely and binding server-side data to + JavaFX UI +* **config** contains logging configurations and the default node configuration file +* **cordform-common** contains utilities related to building and running nodes +* **core** containing the core Corda libraries such as crypto functions, types for Corda's building blocks: states, + contracts, transactions, attachments, etc. and some interfaces for nodes and protocols +* **docs** contains the Corda docsite in restructured text format as well as the built docs in html. The docs can be + accessed via ``/docs/index.html`` from the root of the repo +* **experimental** contains platform improvements that are still in the experimental stage +* **finance** defines a range of elementary contracts (and associated schemas) and protocols, such as abstract fungible + assets, cash, obligation and commercial paper +* **gradle** contains the gradle wrapper which you'll use to execute gradle commands +* **gradle-plugins** contains some additional plugins which we use to deploy Corda nodes +* **lib** contains some dependencies +* **node** contains the core code of the Corda node (eg: node driver, node services, messaging, persistence) +* **node-api** contains data structures shared between the node and the client module, e.g. types sent via RPC +* **node-schemas** contains entity classes used to represent relational database tables +* **samples** contains all our Corda demos and code samples +* **test-utils** contains some utilities for unit testing contracts ( the contracts testing DSL) and protocols (the + mock network) implementation +* **tools** contains the explorer which is a GUI front-end for Corda, and also the DemoBench which is a GUI tool that + allows you to run Corda nodes locally for demonstrations +* **verifier** allows out-of-node transaction verification, allowing verification to scale horizontally +* **webserver** is a servlet container for CorDapps that export HTTP endpoints. This server is an RPC client of the node \ No newline at end of file diff --git a/docs/source/cordapp-overview.rst b/docs/source/cordapp-overview.rst new file mode 100644 index 0000000000..5429a075c3 --- /dev/null +++ b/docs/source/cordapp-overview.rst @@ -0,0 +1,26 @@ +CorDapp overview +================ + +Corda is a platform. Its functionality is extended by developers through the writing of Corda distributed +applications (CorDapps). CorDapps are installed at the level of the individual node, rather than on the network +itself. + +Each CorDapp allows a node to handle new business processes - everything from asset trading (see :ref:`irs-demo`) to +portfolio valuations (see :ref:`simm-demo`). It does so by defining new flows on the node that, once started by the +node owner, conduct the process of negotiating a specific ledger update with other nodes on the network. The node's +owner can then start these flows as required, either through remote procedure calls (RPC) or HTTP requests that +leverage the RPC interface. + +.. image:: resources/node-diagram.png + +CorDapp developers will usually define not only these flows, but also any states and contracts that these flows use. +They will also have to define any web APIs that will run on the node's standalone web server, any static web content, +and any new services that they want their CorDapp to offer. + +CorDapps are made up of definitions for the following components: + +* States +* Contracts +* Flows +* Web APIs and static web content +* Services \ No newline at end of file diff --git a/docs/source/faq.rst b/docs/source/faq.rst new file mode 100644 index 0000000000..4d84639c7e --- /dev/null +++ b/docs/source/faq.rst @@ -0,0 +1,4 @@ +Frequently asked questions +========================== + +A list of frequently asked questions can be found on our `forum `_. diff --git a/docs/source/key-concepts-financial-model.rst b/docs/source/financial-model.rst similarity index 100% rename from docs/source/key-concepts-financial-model.rst rename to docs/source/financial-model.rst diff --git a/docs/source/flow-library.rst b/docs/source/flow-library.rst index 1110dbc813..d6633f50b1 100644 --- a/docs/source/flow-library.rst +++ b/docs/source/flow-library.rst @@ -1,4 +1,4 @@ -Flow Library +Flow library ============ There are a number of built-in flows supplied with Corda, which cover some core functionality. diff --git a/docs/source/flow-state-machines.rst b/docs/source/flow-state-machines.rst index 2e467cadba..f03d751ab5 100644 --- a/docs/source/flow-state-machines.rst +++ b/docs/source/flow-state-machines.rst @@ -154,8 +154,8 @@ simply flow messages or exceptions. The other two represent the buyer and seller Going through the data needed to become a seller, we have: - ``otherParty: Party`` - the party with which you are trading. -- ``notaryNode: NodeInfo`` - the entry in the network map for the chosen notary. See - ":doc:`key-concepts-consensus-notaries`" for more information on notaries. +- ``notaryNode: NodeInfo`` - the entry in the network map for the chosen notary. See ":doc:`key-concepts-notaries`" for more + information on notaries. - ``assetToSell: StateAndRef`` - a pointer to the ledger entry that represents the thing being sold. - ``price: Amount`` - the agreed on price that the asset is being sold for (without an issuer constraint). - ``myKey: PublicKey`` - the PublicKey part of the node's internal KeyPair that controls the asset being sold. diff --git a/docs/source/further-notes-on-kotlin.rst b/docs/source/further-notes-on-kotlin.rst deleted file mode 100644 index 64992d82ac..0000000000 --- a/docs/source/further-notes-on-kotlin.rst +++ /dev/null @@ -1,14 +0,0 @@ -Further notes on Kotlin ------------------------ - -Corda is written in a language called `Kotlin `_. Kotlin is a language that targets the JVM -and can be thought of as a simpler Scala, with much better Java interop. It is developed by and has commercial support -from JetBrains, the makers of the IntelliJ IDE and other popular developer tools. - -Kotlin is a relatively new language and is extremely easy to learn. It is designed as a better Java for industrial -use and, as such, the syntax was carefully designed to be readable even to people who don't know the language, after only -a few minutes of introduction. Additionally, at R3, we find that all of our developers are up to productive writing speed -in Kotlin within their first week. - -Due to the seamless Java interop the use of Kotlin to extend the platform is *not* required and the tutorial shows how -to write contracts in both Kotlin and Java. You can `read more about why Kotlin is a potentially strong successor to Java here `_. diff --git a/docs/source/getting-set-up.rst b/docs/source/getting-set-up.rst index 690b779374..914adb93e5 100644 --- a/docs/source/getting-set-up.rst +++ b/docs/source/getting-set-up.rst @@ -3,54 +3,49 @@ Getting set up Software requirements --------------------- +Corda uses industry-standard tools: -Corda uses industry-standard tools to make set-up as simple as possible. Following the software recommendations below will minimize the number of errors you encounter, and make it easier for others to provide support. However, if you do use other tools, we'd be interested to hear about any issues that arise. +* **Oracle JDK 8 JVM** - supported version **8u131** +* **IntelliJ IDEA** - supported versions **2017.1**, **2017.2** and **2017.3** +* **Gradle** - supported version **3.4** +* **Kotlin** - supported version **1.1.2** +* **Git** -JVM -~~~ +You do not need to install Gradle or Kotlin. A standalone Gradle wrapper is provided, and it will download the correct +version of Kotlin. -Corda is written in Kotlin and runs in a JVM. We develop against Oracle JDK 8, and other JVM implementations are not actively supported. +Please note: -Please ensure that you keep your Oracle JDK installation updated to the latest version while working with Corda. Even earlier versions of JDK 8 versions can cause cryptic errors. +* Corda runs in a JVM. JVM implementations other than Oracle JDK 8 are not actively supported. However, if you do + choose to use OpenJDK, you will also need to install OpenJFX -If you do choose to use OpenJDK instead of Oracle's JDK, you will also need to install OpenJFX. +* Applications on Corda (CorDapps) can be written in any language targeting the JVM. However, Corda itself and most of + the samples are written in Kotlin. Kotlin is an + `official Android language `_, and you can read more about why + Kotlin is a strong successor to Java + `here `_. If you're + unfamiliar with Kotlin, there is an official + `getting started guide `_, and a series of + `Kotlin Koans `_. -Kotlin -~~~~~~ +* IntelliJ IDEA is recommended due to the strength of its Kotlin integration. -Applications on Corda (CorDapps) can be written in any JVM-targeting language. However, Corda itself and most of the samples are written in Kotlin. If you're unfamiliar with Kotlin, there is an official `getting started guide `_. - -See also our :doc:`further-notes-on-kotlin`. - -IDE -~~~ - -We strongly recommend the use of IntelliJ IDEA as an IDE, primarily due to the strength of its Kotlin integration. - -Please make sure that you're running the latest version of IDEA, as older versions have been known to have problems integrating with Gradle, the build tool used by Corda. - -Git -~~~ - -We use git to version-control Corda. - -Gradle -~~~~~~ - -We use Gradle as the build tool for Corda. However, you do not need to install Gradle itself, as a wrapper is provided. +Following these software recommendations will minimize the number of errors you encounter, and make it easier for +others to provide support. However, if you do use other tools, we'd be interested to hear about any issues that arise. Set-up instructions ------------------- - -The instructions below will allow you to set up a Corda development environment and run a basic CorDapp on a Windows or Mac machine. If you have any issues, please consult the :doc:`getting-set-up-fault-finding` page, or reach out on `Slack `_ or the `forums `_. +The instructions below will allow you to set up a Corda development environment and run a basic CorDapp on a Windows +or Mac machine. If you have any issues, please consult the :doc:`troubleshooting` page, or reach out on +`Slack `_ or the `forums `_. .. note:: The set-up instructions are also available in video form for both `Windows `_ and `Mac `_. Windows -~~~~~~~ +^^^^^^^ Java -"""" +~~~~ 1. Visit http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 2. Scroll down to "Java SE Development Kit 8uXXX" (where "XXX" is the latest minor version number) 3. Toggle "Accept License Agreement" @@ -59,19 +54,19 @@ Java 6. Open a new command prompt and run ``java -version`` to test that Java is installed correctly Git -""" +~~~ 1. Visit https://git-scm.com/download/win 2. Click the "64-bit Git for Windows Setup" download link. 3. Download and run the executable to install Git (use the default settings) 4. Open a new command prompt and type ``git --version`` to test that git is installed correctly IntelliJ -"""""""" +~~~~~~~~ 1. Visit https://www.jetbrains.com/idea/download/download-thanks.html?code=IIC 2. Download and run the executable to install IntelliJ Community Edition (use the default settings) Download a sample project -""""""""""""""""""""""""" +~~~~~~~~~~~~~~~~~~~~~~~~~ 1. Open a command prompt 2. Clone the CorDapp tutorial repo by running ``git clone https://github.com/corda/cordapp-tutorial`` 3. Move into the cordapp-tutorial folder by running ``cd cordapp-tutorial`` @@ -79,14 +74,14 @@ Download a sample project 5. Check out the latest milestone release by running ``git checkout release-MX`` (where "X" is the latest milestone) Run from the command prompt -""""""""""""""""""""""""""" +~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1. From the cordapp-tutorial folder, deploy the nodes by running ``gradlew deployNodes`` 2. Start the nodes by running ``call kotlin-source/build/nodes/runnodes.bat`` 3. Wait until all the terminal windows display either "Webserver started up in XX.X sec" or "Node for "NodeC" started up and registered in XX.XX sec" 4. Test the CorDapp is running correctly by visiting the front end at http://localhost:10007/web/example/ Run from IntelliJ -""""""""""""""""" +~~~~~~~~~~~~~~~~~ 1. Open IntelliJ Community Edition 2. On the splash screen, click "Open" (do NOT click "Import Project") and select the cordapp-template folder @@ -100,10 +95,10 @@ Run from IntelliJ 8. Test the CorDapp is running correctly by visiting the front end at http://localhost:10007/web/example/ Mac -~~~ +^^^ Java -"""" +~~~~ 1. Open "System Preferences > Java" 2. In the Java Control Panel, if an update is available, click "Update Now" 3. In the "Software Update" window, click "Install Update". If required, enter your password and click "Install Helper" when prompted @@ -111,12 +106,12 @@ Java 5. Open a new terminal and type ``java -version`` to test that Java is installed correctly IntelliJ -"""""""" +~~~~~~~~ 1. Visit https://www.jetbrains.com/idea/download/download-thanks.html?platform=mac&code=IIC 2. Download and run the executable to install IntelliJ Community Edition (use the default settings) Download a sample project -""""""""""""""""""""""""" +~~~~~~~~~~~~~~~~~~~~~~~~~ 1. Open a terminal 2. Clone the CorDapp tutorial repo by running ``git clone https://github.com/corda/cordapp-tutorial`` 3. Move into the cordapp-tutorial folder by running ``cd cordapp-tutorial`` @@ -124,14 +119,14 @@ Download a sample project 5. Check out the latest milestone release by running ``git checkout release-MX`` (where "X" is the latest milestone) Run from the terminal -""""""""""""""""""""" +~~~~~~~~~~~~~~~~~~~~~ 1. From the cordapp-tutorial folder, deploy the nodes by running ``./gradlew deployNodes`` 2. Start the nodes by running ``kotlin-source/build/nodes/runnodes``. Do not click while 8 additional terminal windows start up. 3. Wait until all the terminal windows display either "Webserver started up in XX.X sec" or "Node for "NodeC" started up and registered in XX.XX sec" 4. Test the CorDapp is running correctly by visiting the front end at http://localhost:10007/web/example/ Run from IntelliJ -""""""""""""""""" +~~~~~~~~~~~~~~~~~ 1. Open IntelliJ Community Edition 2. On the splash screen, click "Open" (do NOT click "Import Project") and select the cordapp-template folder 3. Once the project is open, click "File > Project Structure". Under "Project SDK:", set the project SDK by clicking "New...", clicking "JDK", and navigating to /Library/Java/JavaVirtualMachines/jdk1.8.0_XXX (where "XXX" is the latest minor version number). Click "OK". @@ -158,7 +153,8 @@ And a simple example CorDapp for you to explore basic concepts is available here You can clone these repos to your local machine by running the command ``git clone [repo URL]``. -By default, these repos will be on the unstable ``master`` branch. You should check out the latest milestone release instead by running ``git checkout release-M11.1``. +By default, these repos will be on the unstable ``master`` branch. You should check out the latest milestone release +instead by running ``git checkout release-M11.1``. Next steps ---------- @@ -168,5 +164,5 @@ The best way to check that everything is working fine is by :doc:`running-the-de Once you have these demos running, you may be interested in writing your own CorDapps, in which case you should refer to :doc:`tutorial-cordapp`. -If you encounter any issues, please see the :doc:`getting-set-up-fault-finding` page, or get in touch with us on the +If you encounter any issues, please see the :doc:`troubleshooting` page, or get in touch with us on the `forums `_ or via `slack `_. diff --git a/docs/source/index.rst b/docs/source/index.rst index 0fa0e49946..dbf7474938 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -38,56 +38,67 @@ Documentation Contents: ======================= .. toctree:: - :maxdepth: 2 - :caption: Getting started + :maxdepth: 1 + :caption: Quickstart - inthebox getting-set-up - getting-set-up-fault-finding + tutorial-cordapp running-the-demos CLI-vs-IDE - cheat-sheet .. toctree:: - :maxdepth: 2 + :maxdepth: 1 :caption: Key concepts key-concepts key-concepts-ecosystem - key-concepts-data-model - key-concepts-core-types - key-concepts-financial-model - key-concepts-flow-framework - key-concepts-consensus-notaries - key-concepts-vault - key-concepts-security-model + key-concepts-ledger + key-concepts-states + key-concepts-contracts + key-concepts-transactions + key-concepts-flows + key-concepts-consensus + key-concepts-notaries + key-concepts-time-windows + key-concepts-oracles + key-concepts-node + key-concepts-tradeoffs .. toctree:: - :maxdepth: 2 - :caption: CorDapps + :maxdepth: 1 + :caption: Building a CorDapp - creating-a-cordapp - tutorial-cordapp + cordapp-overview + writing-cordapps + api + api-states + api-contracts + api-transactions + api-flows + api-core-types + cheat-sheet .. toctree:: - :maxdepth: 2 - :caption: The Corda node + :maxdepth: 1 + :caption: Corda nodes - versioning - shell - serialization + running-a-node clientrpc - messaging - persistence + shell node-administration corda-configuration-file - corda-plugins - node-services - node-explorer - permissioning + out-of-process-verification .. toctree:: - :maxdepth: 2 + :maxdepth: 1 + :caption: Corda networks + + setting-up-a-corda-network + permissioning + versioning + +.. toctree:: + :maxdepth: 1 :caption: Tutorials tutorial-contract @@ -106,42 +117,69 @@ Documentation Contents: event-scheduling .. toctree:: - :maxdepth: 2 - :caption: Other + :maxdepth: 1 + :caption: Tools network-simulator - clauses - merkle-trees - json + demobench + node-explorer + azure-vm + loadtesting .. toctree:: - :maxdepth: 2 + :maxdepth: 1 + :caption: Node internals + + node-services + vault + serialization + messaging + persistence + +.. toctree:: + :maxdepth: 1 :caption: Component library flow-library contract-catalogue + financial-model contract-irs .. toctree:: - :maxdepth: 2 - :caption: Appendix + :maxdepth: 1 + :caption: Release process - loadtesting - demobench - setting-up-a-corda-network - secure-coding-guidelines release-process release-notes changelog - codestyle - building-the-docs - further-notes-on-kotlin publishing-corda - azure-vm - out-of-process-verification + codestyle .. toctree:: - :maxdepth: 2 + :maxdepth: 1 + :caption: FAQ + + faq + +.. toctree:: + :maxdepth: 1 + :caption: Troubleshooting + + troubleshooting + +.. toctree:: + :maxdepth: 1 + :caption: Other + + clauses + merkle-trees + json + secure-coding-guidelines + corda-repo-layout + building-the-docs + +.. toctree:: + :maxdepth: 1 :caption: Glossary glossary diff --git a/docs/source/inthebox.rst b/docs/source/inthebox.rst deleted file mode 100644 index 8531257252..0000000000 --- a/docs/source/inthebox.rst +++ /dev/null @@ -1,53 +0,0 @@ -What's included? -================ - -This Corda early access preview includes: - -* A collection of samples, for instance a web app demo that uses it to implement IRS trading. -* A template app you can use to get started, and tutorial app that teaches you the basics. -* A peer to peer network with message persistence and delivery retries. -* Key data structures for defining contracts and states. -* Smart contracts, which you can find in the :doc:`contract-catalogue`. -* API documentation and tutorials (what you're reading). -* A business process workflow framework. -* Notary infrastructure for precise timestamping, and elimination of double spending without a blockchain. -* A simple RPC API. -* A user interface for administration. - -Some things it does not currently include but should gain later are: - -* Sandboxing, distribution and publication of smart contract code. -* A well specified wire protocol. -* An identity framework. - -The open source version of Corda is designed for developers exploring how to write apps. It is not intended to -be production grade software. For example it uses an embedded SQL database and doesn't yet have connectivity -support for mainstream SQL vendors (Oracle, Postgres, MySQL, SQL Server etc). It hasn't been security audited -and the APIs change in every release. - -Source tree layout ------------------- - -The Corda repository comprises the following folders: - -* **buildSrc** contains necessary gradle plugins to build Corda. -* **client** contains libraries for connecting to a node, working with it remotely and binding server-side data to JavaFX UI. -* **config** contains logging configurations and the default node configuration file. -* **core** containing the core Corda libraries such as crypto functions, types for Corda's building blocks: states, - contracts, transactions, attachments, etc. and some interfaces for nodes and protocols. -* **docs** contains the Corda docsite in restructured text format as well as the built docs in html. The docs can be - accessed via ``/docs/index.html`` from the root of the repo. -* **finance** defines a range of elementary contracts (and associated schemas) and protocols, such as abstract fungible - assets, cash, obligation and commercial paper. -* **gradle** contains the gradle wrapper which you'll use to execute gradle commands. -* **gradle-plugins** contains some additional plugins which we use to deploy Corda nodes. -* **lib** contains some dependencies. -* **node** contains the core code of the Corda node (eg: node driver, node services, messaging, persistence). -* **node-api** contains data structures shared between the node and the client module, e.g. types sent via RPC. -* **node-schemas** contains entity classes used to represent relational database tables. -* **samples** contains all our Corda demos and code samples. -* **test-utils** contains some utilities for unit testing contracts ( the contracts testing DSL) and protocols (the - mock network) implementation. -* **tools** contains the explorer which is a GUI front-end for Corda, and also the DemoBench which is a GUI tool that allows you to run Corda nodes locally for demonstrations. -* **verifier** allows out-of-node transaction verification, allowing verification to scale horizontally. -* **webserver** is a servlet container for CorDapps that export HTTP endpoints. This server is an RPC client of the node. diff --git a/docs/source/key-concepts-consensus-notaries.rst b/docs/source/key-concepts-consensus-notaries.rst deleted file mode 100644 index 8b8a1efd0a..0000000000 --- a/docs/source/key-concepts-consensus-notaries.rst +++ /dev/null @@ -1,162 +0,0 @@ -Consensus and notaries -====================== - -A notary is a service that provides transaction ordering and timestamping. - -Notaries are expected to be composed of multiple mutually distrusting parties who use a standard consensus algorithm. -Notaries are identified by and sign with :ref:`composite-keys`. Notaries accept transactions submitted to them for processing -and either return a signature over the transaction, or a rejection error that states that a double spend attempt has occurred. - -Corda has "pluggable" notary services to improve privacy, scalability, legal-system compatibility and algorithmic agility. -The platform currently provides validating and non-validating notaries, and a distributed RAFT implementation. - -Consensus model ---------------- - -The fundamental unit of consensus in Corda is the **state**. Consensus can be divided into two parts: - -1. Consensus over state **validity** -- parties can reach certainty that a transaction is accepted by the contracts pointed - to by the input and output states, and has all the required signatures. This is achieved by parties independently running - the same contract code and validation logic (as described in :doc:`data model `) - -2. Consensus over state **uniqueness** -- parties can reach certainty the output states created in a transaction are the - unique successors to the input states consumed by that transaction (in other words -- an input state has not been previously - consumed) - -.. note:: The current model is still a **work in progress** and everything described in this article can and is likely to change - -Notary ------- - -A **notary** is an authority responsible for attesting that for a given transaction, it has not signed another transaction -consuming any of the same input states. Every **state** has an appointed notary: - -.. sourcecode:: kotlin - - /** - * A wrapper for [ContractState] containing additional platform-level state information. - * This is the definitive state that is stored on the ledger and used in transaction outputs - */ - data class TransactionState( - /** The custom contract state */ - val data: T, - /** Identity of the notary that ensures the state is not used as an input to a transaction more than once */ - val notary: Party) { - ... - } - -Transactions are signed by a notary to ensure their input states are **valid** (apart from *issue* transactions, containing no input states). -Furthermore, when using a validating notary, a transaction is only valid if all its dependencies are also valid. - -.. note:: The notary is a logical concept and can itself be a distributed entity, potentially a cluster maintained by mutually distrusting parties - -When the notary is requested to sign a transaction, it either signs it, attesting that the outputs are the **unique** -successors of the inputs, or provides conflict information for any input state that has been consumed by another transaction -it has already signed. In doing so, the notary provides the point of finality in the system. Until the notary signature -is obtained, parties cannot be sure that an equally valid, but conflicting, transaction will not be regarded as confirmed. -After the signature is obtained, the parties know that the inputs to this transaction have been uniquely consumed by this transaction. -Hence, it is the point at which we can say finality has occurred. - -Multiple notaries -~~~~~~~~~~~~~~~~~ - -More than one notary can exist in a network. This gives the following benefits: - -* **Custom behaviour**. We can have both validating and privacy preserving Notaries -- parties can make a choice based - on their specific requirements. -* **Load balancing**. Spreading the transaction load over multiple notaries will allow higher transaction throughput in - the platform overall -* **Low latency**. Latency could be minimised by choosing a notary physically closer the transacting parties - -Changing notaries -~~~~~~~~~~~~~~~~~ - -A transaction should only be signed by a notary if all of its input states point to the same notary. -In cases where a transaction involves states controlled by multiple notaries, the states first have to be repointed to the same notary. -This is achieved by using a special type of transaction whose sole output state is identical to its sole input state except for its designated notary. -Ensuring that all input states point to the same notary is the responsibility of each involved party -(it is another condition for an output state of the transaction to be **valid**) - -To change the notary for an input state, use the ``NotaryChangeFlow``. For example: - -.. sourcecode:: kotlin - - @Suspendable - fun changeNotary(originalState: StateAndRef, - newNotary: Party): StateAndRef { - val flow = NotaryChangeFlow(originalState, newNotary) - return subFlow(flow) - } - -The flow will: - -1. Construct a transaction with the old state as the input and the new state as the output - -2. Obtain signatures from all *participants* (a participant is any party that is able to consume this state in a valid transaction, as defined by the state itself) - -3. Obtain the *old* notary signature - -4. Record and distribute the final transaction to the participants so that everyone possesses the new state - -.. note:: Eventually, changing notaries will be handled automatically on demand. - -Validation ----------- - -One of the design decisions for a notary is whether or not to **validate** a transaction before accepting it. - -If a transaction is not checked for validity, it opens the platform to "denial of state" attacks, where anyone can build -an invalid transaction consuming someone else's states and submit it to the notary to get the states blocked. However, -if the transaction is validated, this requires the notary to be able to see the full contents of the transaction in -question and its dependencies. This is an obvious privacy leak. - -The platform is flexible and currently supports both validating and non-validating notary implementations -- a -party can select which one to use based on its own privacy requirements. - -.. note:: In the non-validating model, the "denial of state" attack is partially alleviated by requiring the calling - party to authenticate and storing its identity for the request. The conflict information returned by the notary - specifies the consuming transaction ID along with the identity of the party that had created the transaction. If the - conflicting transaction is valid, the current one is aborted; if not, a dispute can be raised and the input states - of the conflicting invalid transaction are "un-committed" (via a legal process). - -Timestamping ------------- - -A notary can also act as a *timestamping authority*, verifying the transaction timestamp command. - -For a timestamp to be meaningful, its implications must be binding on the party requesting it. -A party can obtain a timestamp signature in order to prove that some event happened *before*, *on*, or *after* a particular point in time. -However, if the party is not also compelled to commit to the associated transaction, it has a choice of whether or not to reveal this fact until some point in the future. -As a result, we need to ensure that the notary either has to also sign the transaction within some time tolerance, -or perform timestamping *and* notarisation at the same time, which is the chosen behaviour for this model. - -There will never be exact clock synchronisation between the party creating the transaction and the notary. -This is not only due to physics, network latencies, etc. but also because between inserting the command and getting the -notary to sign there may be many other steps, like sending the transaction to other parties involved in the trade, or -even requesting human sign-off. Thus the time observed by the notary may be quite different to the time observed by the -party creating the transaction. - -For this reason, times in transactions are specified as time *windows*, not absolute times. -In a distributed system there can never be "true time", only an approximation of it. Time windows can be -open-ended (i.e. specify only one of "before" and "after") or they can be fully bounded. If a time window needs to -be converted to an absolute time (e.g. for display purposes), there is a utility method on ``Timestamp`` to -calculate the mid point. - -In this way, we express the idea that the *true value* of the fact "the current time" is actually unknowable. Even when both before and -after times are included, the transaction could have occurred at any point between those two timestamps. Here, -"occurrence" could mean the execution date, the value date, the trade date etc ... The notary doesn't care what precise -meaning the timestamp has to the contract. - -By creating a range that can be either closed or open at one end, we allow all of the following facts to be modelled: - -* This transaction occurred at some point after the given time (e.g. after a maturity event) -* This transaction occurred at any time before the given time (e.g. before a bankruptcy event) -* This transaction occurred at some point roughly around the given time (e.g. on a specific day) - -.. note:: It is assumed that the time feed for a notary is GPS/NaviStar time as defined by the atomic - clocks at the US Naval Observatory. This time feed is extremely accurate and available globally for free. - -Also see section 7 of the `Technical white paper`_ which covers this topic in significantly more depth. - -.. _`Technical white paper`: _static/corda-technical-whitepaper.pdf - diff --git a/docs/source/key-concepts-consensus.rst b/docs/source/key-concepts-consensus.rst new file mode 100644 index 0000000000..dc665c247c --- /dev/null +++ b/docs/source/key-concepts-consensus.rst @@ -0,0 +1,62 @@ +Consensus +========= + +.. topic:: Summary + + * *To be committed, transactions must achieve both validity and uniqueness consensus* + * *Validity consensus requires contractual validity of the transaction and all its dependencies* + * *Uniqueness consensus prevents double-spends* + +Two types of consensus +---------------------- +Determining whether a proposed transaction is a valid ledger update involves reaching two types of consensus: + +* *Validity consensus* - this is checked by each required signer before they sign the transaction +* *Uniqueness consensus* - this is only checked by a notary service + +Validity consensus +------------------ +Validity consensus is the process of checking that the following conditions hold both for the proposed transaction, +and for every transaction in the transaction chain that generated the inputs to the proposed transaction: + +* The transaction is accepted by the contracts of every input and output state +* The transaction has all the required signatures + +It is not enough to verify the proposed transaction itself. We must also verify every transaction in the chain of +transactions that led up to the creation of the inputs to the proposed transaction. + +This is known as *walking the chain*. Suppose, for example, that a party on the network proposes a transaction +transferring us a treasury bond. We can only be sure that the bond transfer is valid if: + +* The treasury bond was issued by the central bank in a valid issuance transaction +* Every subsequent transaction in which the bond changed hands was also valid + +The only way to be sure of both conditions is to walk the transaction's chain. We can visualize this process as follows: + +.. image:: resources/validation-consensus.png + +When verifying a proposed transaction, a given party may not have every transaction in the transaction chain that they +need to verify. In this case, they can request the missing transactions from the transaction proposer(s). The +transaction proposer(s) will always have the full transaction chain, since they would have requested it when +verifying the transaction that created the proposed transaction's input states. + +Uniqueness consensus +-------------------- +Imagine that Bob holds a valid central-bank-issued cash state of $1,000,000. Bob can now create two transaction +proposals: + +* A transaction transferring the $1,000,000 to Charlie in exchange for £800,000 +* A transaction transferring the $1,000,000 to Dan in exchange for €900,000 + +This is a problem because, although both transactions will achieve validity consensus, Bob has managed to +"double-spend" his USD to get double the amount of GBP and EUR. We can visualize this as follows: + +.. image:: resources/uniqueness-consensus.png + +To prevent this, a valid transaction proposal must also achieve uniqueness consensus. Uniqueness consensus is the +requirement that none of the inputs to a proposed transaction have already been consumed in another transaction. + +If one or more of the inputs have already been consumed in another transaction, this is known as a *double spend*, +and the transaction proposal is considered invalid. + +Uniqueness consensus is provided by notaries. See :doc:`key-concepts-notaries` for more details. \ No newline at end of file diff --git a/docs/source/key-concepts-contracts.rst b/docs/source/key-concepts-contracts.rst new file mode 100644 index 0000000000..26558044f0 --- /dev/null +++ b/docs/source/key-concepts-contracts.rst @@ -0,0 +1,73 @@ +Contracts +========= + +.. topic:: Summary + + * *A valid transaction must be accepted by the contract of each of its input and output states* + * *Contracts are written in a JVM programming language (e.g. Java or Kotlin)* + * *Contract execution is deterministic and its acceptance of a transaction is based on the transaction's contents alone* + +Transaction verification +------------------------ +Recall that a transaction is only valid if it is digitally signed by all required signers. However, even if a +transaction gathers all the required signatures, it is only valid if it is also **contractually valid**. + +**Contract validity** is defined as follows: + +* Each state points to a *contract* +* A *contract* takes a transaction as input, and states whether the transaction is considered valid based on the + contract's rules +* A transaction is only valid if the contract of **every input state** and **every output state** considers it to be + valid + +We can picture this situation as follows: + +.. image:: resources/tx-validation.png + +The contract code can be written in any JVM language, and has access to the full capabilities of the language, +including: + +* Checking the number of inputs, outputs, commands, timestamps, and/or attachments +* Checking the contents of any of these components +* Looping constructs, variable assignment, function calls, helper methods, etc. +* Grouping similar states to validate them as a group (e.g. imposing a rule on the combined value of all the cash + states) + +A transaction that is not contractually valid is not a valid proposal to update the ledger, and thus can never be +committed to the ledger. In this way, contracts impose rules on the evolution of states over time that are +independent of the willingness of the required signers to sign a given transaction. + +The contract sandbox +-------------------- +Transaction verification must be *deterministic* - a contract should either **always accept** or **always reject** a +given transaction. For example, transaction validity cannot depend on the time at which validation is conducted, or +the amount of information the peer running the contract holds. This is a necessary condition to ensure that all peers +on the network reach consensus regarding the validity of a given ledger update. + +To achieve this, contracts evaluate transactions in a deterministic sandbox. The sandbox has a whitelist that +prevents the contract from importing libraries that could be a source of non-determinism. This includes libraries +that provide the current time, random number generators, libraries that provide filesystem access or networking +libraries, for example. Ultimately, the only information available to the contract when verifying the transaction is +the information included in the transaction itself. + +Contract limitations +-------------------- +Since a contract has no access to information from the outside world, it can only check the transaction for internal +validity. It cannot check, for example, that the transaction is in accordance with what was originally agreed with the +counterparties. + +Peers should therefore check the contents of a transaction before signing it, *even if the transaction is +contractually valid*, to see whether they agree with the proposed ledger update. A peer is under no obligation to +sign a transaction just because it is contractually valid. For example, they may be unwilling to take on a loan that +is too large, or may disagree on the amount of cash offered for an asset. + +Oracles +------- +Sometimes, transaction validity will depend on some external piece of information, such as an exchange rate. In +these cases, an oracle is required. See :doc:`key-concepts-oracles` for further details. + +Legal prose +----------- +Each contract also refers to a legal prose document that states the rules governing the evolution of the state over +time in a way that is compatible with traditional legal systems. This document can be relied upon in the case of +legal disputes. \ No newline at end of file diff --git a/docs/source/key-concepts-data-model.rst b/docs/source/key-concepts-data-model.rst deleted file mode 100644 index bc3d0358ef..0000000000 --- a/docs/source/key-concepts-data-model.rst +++ /dev/null @@ -1,142 +0,0 @@ -Data model -========== - -Overview --------- -Corda uses the so-called "UTXO set" model (unspent transaction output). In this model, the database -does not track accounts or balances. An entry is either spent or not spent but it cannot be changed. In this model the -database is a set of immutable rows keyed by (hash:output index). Transactions define outputs that append new rows and -inputs which consume existing rows. - -The Corda ledger is defined as a set of immutable **states**, which are created and destroyed by digitally signed **transactions**. -Each transaction points to a set of states that it will consume/destroy, these are called **inputs**, and contains a set -of new states that it will create, these are called **outputs**. -Although the ledger is shared, it is not always the case that transactions and ledger entries are globally visible. -In cases where a set of transactions stays within a small subgroup of users it is possible to keep the relevant -data purely within that group. To ensure consistency, we rely heavily on secure hashes like SHA-256 to identify things. - -The Corda model provides the following additional features: - -* There is no global broadcast at any point. -* States can include arbitrary typed data. -* Transactions invoke not only input contracts but also the contracts of the outputs. -* Contracts refer to a bundle of business logic that may handle various different tasks, beyond transaction verification. -* Contracts are Turing-complete and can be written in any ordinary programming language that targets the JVM. -* Arbitrarily-precise time-bounds may be specified in transactions (which must be attested to by a notary) -* Primary consensus implementations use block-free conflict resolution algorithms. -* Transactions are not ordered using a block chain and by implication Corda does not use miners or proof-of-work. - Instead each state points to a notary, which is a service that guarantees it will sign a transaction only if all the - input states are un-consumed. - -Corda provides three main tools to achieve global distributed consensus: - -* Smart contract logic to ensure state transitions are valid according to the pre-agreed rules. -* Uniqueness and timestamping services to order transactions temporally and eliminate conflicts. -* An :doc:`orchestration framework ` which simplifies the process of writing complex multi-step protocols between multiple different parties. - -Comparisons of the Corda data model with Bitcoin and Ethereum can be found in the white papers. - -States ------- -A state object represents an agreement between two or more parties, the evolution of which governed by machine-readable contract code. -This code references, and is intended to implement, portions of human-readable legal prose. -It is intended to be shared only with those who have a legitimate reason to see it. - -The following diagram illustrates a state object: - -.. image:: resources/contract.png - -In the diagram above, we see a state object representing a cash claim of £100 against a commercial bank, owned by a fictional shipping company. - -.. note:: Legal prose (depicted above in grey-shade) is currently implemented as an unparsed reference to the natural language - contract that the code is supposed to express (usually a hash of the contract's contents). - -States contain arbitrary data, but they always contain at minimum a hash of the bytecode of a -**contract code** file, which is a program expressed in JVM byte code that runs sandboxed inside a Java virtual machine. -Contract code (or just "contracts" in the rest of this document) are globally shared pieces of business logic. - -.. note:: In the current code dynamic loading of contracts is not implemented. This will change in the near future. - -Contracts ---------- -Contracts define part of the business logic of the ledger. - -Corda enforces business logic through smart contract code, which is constructed as a pure function (called "verify") that either accepts -or rejects a transaction, and which can be composed from simpler, reusable functions. The functions interpret transactions -as taking states as inputs and producing output states through the application of (smart contract) commands, and accept -the transaction if the proposed actions are valid. Given the same transaction, a contract’s “verify” function always yields -exactly the same result. Contracts do not have storage or the ability to interact with anything. - -.. note:: In the future, contracts will be mobile. Nodes will download and run contracts inside a sandbox without any review in some deployments, - although we envisage the use of signed code for Corda deployments in the regulated sphere. Corda will use an augmented - JVM custom sandbox that is radically more restrictive than the ordinary JVM sandbox, and it will enforce not only - security requirements but also deterministic execution. - -To further aid writing contracts we introduce the concept of :doc:`clauses` which provide a means of re-using common -verification logic. - -Transactions ------------- -Transactions are used to update the ledger by consuming existing state objects and producing new state objects. - -A transaction update is accepted according to the following two aspects of consensus: - - #. Transaction validity: parties can ensure that the proposed transaction and all its ancestors are valid - by checking that the associated contract code runs successfully and has all the required signatures - #. Transaction uniqueness: parties can ensure there exists no other transaction, over which we have previously reached - consensus (validity and uniqueness), that consumes any of the same states. This is the responsibility of a notary service. - -Beyond inputs and outputs, transactions may also contain **commands**, small data packets that -the platform does not interpret itself but which parameterise execution of the contracts. They can be thought of as -arguments to the verify function. Each command has a list of **composite keys** associated with it. The platform ensures -that the transaction has signatures matching every key listed in the commands before the contracts start to execute. Thus, a verify -function can trust that all listed keys have signed the transaction, but is responsible for verifying that any keys required -for the transaction to be valid from the verify function's perspective are included in the list. Public keys -may be random/identityless for privacy, or linked to a well known legal identity, for example via a -*public key infrastructure* (PKI). - -.. note:: Linkage of keys with identities via a PKI is only partially implemented in the current code. - -Commands are always embedded inside a transaction. Sometimes, there's a larger piece of data that can be reused across -many different transactions. For this use case, we have **attachments**. Every transaction can refer to zero or more -attachments by hash. Attachments are always ZIP/JAR files, which may contain arbitrary content. These files are -then exposed on the classpath and so can be opened by contract code in the same manner as any JAR resources -would be loaded. - -Note that there is nothing that explicitly binds together specific inputs, outputs, commands or attachments. Instead, -it's up to the contract code to interpret the pieces inside the transaction and ensure they fit together correctly. This -is done to maximise flexibility for the contract developer. - -Transactions may sometimes need to provide a contract with data from the outside world. Examples may include stock -prices, facts about events or the statuses of legal entities (e.g. bankruptcy), and so on. The providers of such -facts are called **oracles** and they provide facts to the ledger by signing transactions that contain commands they -recognise, or by creating signed attachments. The commands contain the fact and the signature shows agreement to that fact. - -Time is also modelled as a fact and represented as a **timestamping command** placed inside the transaction. This specifies a -time window in which the transaction is considered valid for notarisation. The time window can be open ended (i.e. with a start but no end or vice versa). -In this way transactions can be linked to the notary's clock. - -It is possible for a single Corda network to have multiple competing notaries. A new (output) state is tied to a specific -notary when it is created. Transactions can only consume (input) states that are all associated with the same notary. -A special type of transaction is provided that can move a state (or set of states) from one notary to another. - -.. note:: Currently the platform code will not automatically re-assign states to a single notary. This is a future planned feature. - -Transaction Validation -^^^^^^^^^^^^^^^^^^^^^^ -When a transaction is presented to a node as part of a flow it may need to be checked. Checking original transaction validity is -the responsibility of the ``ResolveTransactions`` flow. This flow performs a breadth-first search over the transaction graph, -downloading any missing transactions into local storage and validating them. The search bottoms out at transactions without inputs -(eg. these are mostly created from issuance transactions). A transaction is not considered valid if any of its transitive dependencies are invalid. - -.. note:: Non-validating notaries assume transaction validity and do not request transaction data or their dependencies - beyond the list of states consumed. - -The tutorial ":doc:`tutorial-contract`" provides a hand-ons walk-through using these concepts. - -Transaction Representation -^^^^^^^^^^^^^^^^^^^^^^^^^^ -By default, all transaction data (input and output states, commands, attachments) is visible to all participants in -a multi-party, multi-flow business workflow. :doc:`merkle-trees` describes how Corda uses Merkle trees to -ensure data integrity and hiding of sensitive data within a transaction that shouldn't be visible in its entirety to all -participants (eg. oracles nodes providing facts). diff --git a/docs/source/key-concepts-ecosystem.rst b/docs/source/key-concepts-ecosystem.rst index 5c4df45442..740f532b9f 100644 --- a/docs/source/key-concepts-ecosystem.rst +++ b/docs/source/key-concepts-ecosystem.rst @@ -1,47 +1,51 @@ -Corda ecosystem -=============== +The network +=========== -A Corda network consists of the following components: +.. topic:: Summary -* Nodes, where each node represents a JVM run-time environment hosting Corda services and executing applications ("CorDapps"). - Nodes communicate using AMQP/1.0 over TLS. -* A permissioning service that automates the process of provisioning TLS certificates. -* A network map service that publishes information about nodes on the network. -* One or more pluggable notary service types (which may be distributed over multiple nodes). - A notary guarantees uniqueness and validity of transactions. -* Zero or more oracle services. An oracle is a well known service that signs transactions if they state a fact and that fact is considered to be true. -* CorDapps which represent participant applications that execute contract code and communicate using the flow framework to achieve consensus over some business activity -* Standalone Corda applications that provide manageability and tooling support to a Corda network. + * *A Corda network is made up of nodes running Corda and CorDapps* + * *The network is permissioned, with access controlled by a doorman* + * *Communication between nodes is point-to-point, instead of relying on global broadcasts* + +Network structure +----------------- +A Corda network is an authenticated peer-to-peer network of nodes, where each node is a JVM run-time environment +hosting Corda services and executing applications known as *CorDapps*. + +All communication between nodes is direct, with TLS-encrypted messages sent over AMQP/1.0. This means that data is +shared only on a need-to-know basis; in Corda, there are **no global broadcasts**. + +Each network has a **network map service** that publishes the IP addresses through which every node on the network can +be reached, along with the identity certificates of those nodes and the services they provide. + +The doorman +----------- +Corda networks are semi-private. Each network has a doorman service that enforces rules regarding the information +that nodes must provide and the know-your-customer processes that they must complete before being admitted to the +network. + +To join the network, a node must contact the doorman and provide the required information. If the doorman is +satisfied, the node will receive a root-authority-signed TLS certificate from the network's permissioning service. +This certificate certifies the node's identity when communicating with other participants on the network. + +We can visualize a network as follows: + +.. image:: resources/network.png + +Network services +---------------- +Nodes can provide several types of services: + +* One or more pluggable **notary services**. Notaries guarantee the uniqueness, and possibility the validity, of ledger + updates. Each notary service may be run on a single node, or across a cluster of nodes. +* Zero or more **oracle services**. An oracle is a well-known service that signs transactions if they state a fact and + that fact is considered to be true. These components are illustrated in the following diagram: .. image:: resources/cordaNetwork.png :align: center -Note: - -* Corda infrastructure services are those which all participants depend upon, such as the network map and notaries. -* Corda services can be deployed by participants, third parties or a central network operator (eg. such as R3); - this diagram is not intended to imply only a centralised model is supported - -It is important to highlight the following: - -* Corda is designed for semi-private networks in which admission requires obtaining an identity signed by a root authority. -* Nodes are arranged in an authenticated peer to peer network. All communication is direct. -* Data is shared on a need-to-know basis. Nodes provide the dependency graph of a transaction they are sending to another node on demand, but there is no global broadcast of all transactions. -* Nodes are backed by a relational database and data placed in the ledger can be queried using SQL -* The network map publishes the IP addresses through which every node on the network can be reached, along with the identity certificates of those nodes and the services they provide. -* All communication takes the form of small multi-party sub-protocols called flows. -* Oracles represent gateways to proprietary (or other) business logic executors (e.g., central counterparties or valuation agents) that can be verified on-ledger by participants. - -CorDapps --------- -Corda is a platform for the writing of “CorDapps”: applications that extend the distributed ledger with new capabilities. -Such apps define new data types, new inter-node protocol flows and the “smart contracts” that determine allowed changes. -The combination of state objects (data), contract code (allowable operations), transaction flows (business logic -choreography), any necessary APIs, vault plugins, and UI components can be thought of as a shared ledger application, -or corda distributed application (“CorDapp”). This is the core set of components a contract developer on the platform -should expect to build. - -Examples of CorDapps include asset trading (see :ref:`irs-demo` and :ref:`trader-demo`), portfolio valuations (see :ref:`simm-demo`), trade finance, -post-trade order matching, KYC/AML, etc. \ No newline at end of file +In this diagram, Corda infrastructure services are those upon which all participants depend, such as the network map +and notary services. Corda services may be deployed by participants, third parties or a central network operator +(such as R3). The diagram is not intended to imply that only a centralised model is supported. \ No newline at end of file diff --git a/docs/source/key-concepts-flow-framework.rst b/docs/source/key-concepts-flow-framework.rst deleted file mode 100644 index 81d744e7d3..0000000000 --- a/docs/source/key-concepts-flow-framework.rst +++ /dev/null @@ -1,37 +0,0 @@ - -Flow framework --------------- -In Corda all communication takes the form of structured sequences of messages passed between parties which we call flows. - -Flows enable complex multi-step, multi-party business interactions to be modelled as blocking code without a central controller. -The code is transformed into an asynchronous state machine, with checkpoints written to the node’s backing database when messages are sent and received. -A node may potentially have millions of flows active at once and they may last days, across node restarts and even upgrades. - -A flow library is provided to enable developers to re-use common flow types such as notarisation, membership broadcast, -transaction resolution and recording, and so on. - -APIs are provided to send and receive object graphs to and from other identities on the network, embed sub-flows, -report progress information to observers and even interact with people (for manual resolution of exceptional scenarios) - -Flows are embedded within CorDapps and deployed to a participant's node for execution. - -.. note:: We will be implementing the concept of a flow hospital to provide a means for a node administrator to decide - whether a paused flow should be killed or repaired. Flows enter this state if they throw exceptions or explicitly request human assistance. - -Section 4 of the `Technical white paper`_ provides further detail of the above features. - -The following diagram illustrates a sample multi-party business flow: - -.. image:: resources/flowFramework.png - -Note the following: - -* there are 3 participants in this workflow including the notary -* the Buyer and Seller flows (depicted in green) are custom written by developers and deployed within a CorDapp -* the custom written flows invoke both financial library flows such as ``TwoPartyTradeFlow`` (depicted in orange) and core - library flows such as ``ResolveTransactionsFlow`` and ``NotaryFlow`` (depicted in yellow) -* each side of the flow illustrates the stage of execution with a progress tracker notification -* activities within a flow directly or indirectly interact with its node's ledger (eg. to record a signed, notarised transaction) and vault (eg. to perform a spend of some fungible asset) -* flows interact across parties using send, receive and sendReceive messaging semantics (by implementing the ``FlowLogic`` interface) - -.. _`Technical white paper`: _static/corda-technical-whitepaper.pdf \ No newline at end of file diff --git a/docs/source/key-concepts-flows.rst b/docs/source/key-concepts-flows.rst new file mode 100644 index 0000000000..bfd55bffca --- /dev/null +++ b/docs/source/key-concepts-flows.rst @@ -0,0 +1,48 @@ +Flows +===== + +.. topic:: Summary + + * *Flows automate the process of agreeing ledger updates* + * *Communication between nodes only occurs in the context of these flows, and is point-to-point* + * *Built-in flows are provided to automate common tasks* + +Corda networks use point-to-point messaging instead of a global broadcast. This means that coordinating a ledger update +requires network participants to specify exactly what information needs to be sent, to which counterparties, and in +what order. + +Rather than having to specify these steps manually, Corda automates the process using *flows*. A flow is a sequence +of actions that tells a node how to achieve a specific ledger update, such as issuing an asset or settling a trade. + +Once a given business process has been encapsulated in a flow and installed on the node as part of a CorDapp, the node's +owner can instruct the node to kick off this business process at any time with a simple RPC call. All activity on the +node, and all inter-node communication, occurs in the context of these flows. + +A flow's steps may include: + +* Identifying counterparties on the network +* Extracting information from the vault or local storage +* Building a transaction +* Sending messages +* Notarising and recording a transaction +* Reporting progress to observers +* Requesting human interaction... + +A node can have millions of flows active at once and they may last days, across node restarts and even upgrades. + +An example flow +--------------- +Here is a visualisation of an example flow, showing Alice and Bob agreeing on a ledger update: + +.. image:: resources/flow.gif + +The flow library +---------------- +Corda provides a library of flows to handle common tasks, meaning that developers do not have to redefine the +logic behind common processes such as: + +* Notarising and recording a transaction +* Gathering signatures from counterparty nodes +* Verifying a chain of transactions + +Further information on the available built-in flows can be found in :doc:`flow-library`. \ No newline at end of file diff --git a/docs/source/key-concepts-ledger.rst b/docs/source/key-concepts-ledger.rst new file mode 100644 index 0000000000..a553e0053b --- /dev/null +++ b/docs/source/key-concepts-ledger.rst @@ -0,0 +1,26 @@ +The ledger +========== + +.. topic:: Summary + + * *The ledger is subjective from each peer's perspective* + * *Two peers are always guaranteed to see the exact same version of any on-ledger facts they share* + +Overview +-------- +In Corda, there is **no single central store of data**. Instead, each node maintains a separate database of known +facts. As a result, each peer only sees a subset of facts on the ledger, and no peer is aware of the ledger in its +entirety. + +For example, imagine a network with five nodes, where each coloured circle represents a shared fact: + +.. image:: resources/ledger-venn.png + +We can see that although Carl, Demi and Ed are aware of shared fact 3, **Alice and Bob are not**. + +Equally importantly, Corda guarantees that whenever one of these facts is shared by multiple nodes on the network, it evolves +in lockstep in the database of every node that is aware of it: + +.. image:: resources/ledger-table.png + +For example, Alice and Bob will both see the **exact same version** of shared facts 1 and 7. \ No newline at end of file diff --git a/docs/source/key-concepts-node.rst b/docs/source/key-concepts-node.rst new file mode 100644 index 0000000000..a849cf4ac3 --- /dev/null +++ b/docs/source/key-concepts-node.rst @@ -0,0 +1,72 @@ +Nodes +===== + +.. topic:: Summary + + * *A node is JVM run-time with a unique network identity running the Corda software* + * *The node has two interfaces with the outside world:* + + * *A network layer, for interacting with other nodes* + * *RPC, for interacting with the node's owner* + + * *The node's functionality is extended by installing CorDapps in the plugin registry* + +Node architecture +----------------- +A Corda node is a JVM run-time environment with a unique identity on the network that hosts Corda services and +CorDapps. + +We can visualize the node's internal architecture as follows: + +.. image:: resources/node-architecture.png + +The core elements of the architecture are: + +* A persistence layer for storing data +* A network interface for interacting with other nodes +* An RPC interface for interacting with the node's owner +* A service hub for allowing the node's flows to call upon the node's other services +* A plugin registry for extending the node by installing CorDapps + +Persistence layer +----------------- +The persistence layer has two parts: + +* The **vault**, where the node stores any relevant current and historic states +* The **storage service**, where it stores transactions, attachments and flow checkpoints + +The node's owner can query the node's storage using the RPC interface (see below). + +Network interface +----------------- +All communication with other nodes on the network is handled by the node itself, as part of running a flow. The +node's owner does not interact with other network nodes directly. + +RPC interface +------------- +The node's owner interacts with the node via remote procedure calls (RPC). RPC operations exposed by the node include: + +* Starting a flow +* Reading the contents of the vault or the transaction storage +* Uploading and downloading attachments + +The service hub +--------------- +Internally, the node has access to a rich set of services that are used during flow execution to coordinate ledger +updates. The key services provided are: + +* Information on other nodes on the network and the services they offer +* Access to the contents of the vault and the storage service +* Access to, and generation of, the node's public-private keypairs +* Information about the node itself +* The current time, as tracked by the node + +The plugin registry +------------------- +The plugin registry is where new CorDapps are installed to extend the behavior of the node. + +The node also has several plugins installed by default to handle common tasks such as: + +* Retrieving transactions and attachments from counterparties +* Upgrading contracts +* Broadcasting agreed ledger updates for recording by counterparties \ No newline at end of file diff --git a/docs/source/key-concepts-notaries.rst b/docs/source/key-concepts-notaries.rst new file mode 100644 index 0000000000..673bf330fe --- /dev/null +++ b/docs/source/key-concepts-notaries.rst @@ -0,0 +1,88 @@ +Notaries +======== + +.. topic:: Summary + + * *Notaries prevent "double-spends"* + * *Notaries may optionally also validate transactions* + * *A network can have several notaries, each running a different consensus algorithm* + +Notarisation +------------ +A *notary* is a network service that provides **uniqueness consensus** by attesting that, for a given transaction, it +has not already signed other transactions that consumes any of the proposed transaction's input states. + +Upon being sent asked to notarise a transaction, a notary will either: + +* Sign the transaction if it has not already signed other transactions consuming any of the proposed transaction's + input states +* Reject the transaction and flag that a double-spend attempt has occurred otherwise + +In doing so, the notary provides the point of finality in the system. Until the notary's signature is obtained, parties +cannot be sure that an equally valid, but conflicting, transaction will not be regarded as the "valid" attempt to spend +a given input state. However, after the notary's signature is obtained, we can be sure that the proposed +transaction's input states had not already been consumed by a prior transaction. Hence, notarisation is the point +of finality in the system. + +Every state has an appointed notary, and a notary will only notarise a transaction if it is the appointed notary +of all the transaction's input states. + +Consensus algorithms +^^^^^^^^^^^^^^^^^^^^ +Corda has "pluggable" consensus, allowing notaries to choose a consensus algorithm based on their requirements in +terms of privacy, scalability, legal-system compatibility and algorithmic agility. + +In particular, notaries may differ in terms of: + +* **Structure** - a notary may be a single network node, a cluster of mutually-trusting nodes, or a cluster of + mutually-distrusting nodes +* **Consensus algorithm** - a notary service may choose to run a high-speed, high-trust algorithm such as RAFT, a + low-speed, low-trust algorithm such as BFT, or any other consensus algorithm it chooses + +Validation +^^^^^^^^^^ +A notary service must also decide whether or not to provide **validity consensus** by validating each transaction +before committing it. In making this decision, they face the following trade-off: + +* If a transaction **is not** checked for validity, it creates the risk of "denial of state" attacks, where a node + knowingly builds an invalid transaction consuming some set of existing states and sends it to the + notary, causing the states to be marked as consumed + +* If the transaction **is** checked for validity, the notary will need to see the full contents of the transaction and + its dependencies. This leaks potentially private data to the notary + +There are several further points to keep in mind when evaluating this trade-off. In the case of the non-validating +model, Corda's controlled data distribution model means that information on unconsumed states is not widely shared. +Additionally, Corda's permissioned network means that the notary can store to the identity of the party that created +the "denial of state" transaction, allowing the attack to be resolved off-ledger. + +In the case of the validating model, the use of anonymous, freshly-generated public keys instead of legal identities to +identify parties in a transaction limit the information the notary sees. + +Multiple notaries +^^^^^^^^^^^^^^^^^ +Each Corda network can have multiple notaries, each potentially running a different consensus algorithm. This provides +several benefits: + +* **Privacy** - we can have both validating and non-validating notary services on the same network, each running a + different algorithm. This allows nodes to choose the preferred notary on a per-transaction basis +* **Load balancing** - spreading the transaction load over multiple notaries allows higher transaction throughput for + the platform overall +* **Low latency** - latency can be minimised by choosing a notary physically closer to the transacting parties + +Changing notaries +^^^^^^^^^^^^^^^^^ +Remember that a notary will only sign a transaction if it is the appointed notary of all of the transaction's input +states. However, there are cases in which we may need to change a state's appointed notary. These include: + +* When a single transaction needs to consume several states that have different appointed notaries +* When a node would prefer to use a different notary for a given transaction due to privacy or efficiency concerns + +Before these transactions can be created, the states must first be repointed to all have the same notary. This is +achieved using a special notary-change transaction that takes: + +* A single input state +* An output state identical to the input state, except that the appointed notary has been changed + +The input state's appointed notary will sign the transaction if it doesn't constitute a double-spend, at which point +a state will enter existence that has all the properties of the old state, but has a different appointed notary. \ No newline at end of file diff --git a/docs/source/key-concepts-oracles.rst b/docs/source/key-concepts-oracles.rst new file mode 100644 index 0000000000..82859d9817 --- /dev/null +++ b/docs/source/key-concepts-oracles.rst @@ -0,0 +1,26 @@ +Oracles +======= + +.. topic:: Summary + + * *A fact can be included in a transaction as part of a command* + * *An oracle is a service that will only sign the transaction if the included fact is true* + +In many cases, a transaction's contractual validity depends on some external piece of data, such as the current +exchange rate. However, if we were to let each participant evaluate the transaction's validity based on their own +view of the current exchange rate, the contract's execution would be non-deterministic: some signers would consider the +transaction valid, while others would consider it invalid. As a result, disagreements would arise over the true state +of the ledger. + +Corda addresses this issue using *oracles*. Oracles are network services that, upon request, provide commands +that encapsulate a specific fact (e.g. the exchange rate at time x) and list the oracle as a required signer. + +If a node wishes to use a given fact in a transaction, they request a command asserting this fact from the oracle. If +the oracle considers the fact to be true, they send back the required command. The node then includes the command in +their transaction, and the oracle will sign the transaction to assert that the fact is true. + +If they wish to monetize their services, oracles can choose to only sign a transaction and attest to the validity of +the fact it contains for a fee. + +Transaction tear-offs are used to prevent the oracle from seeing information about the transaction that is not +relevant to them. See :doc:`merkle-trees` for further details. \ No newline at end of file diff --git a/docs/source/key-concepts-security-model.rst b/docs/source/key-concepts-security-model.rst deleted file mode 100644 index 66be831da0..0000000000 --- a/docs/source/key-concepts-security-model.rst +++ /dev/null @@ -1,45 +0,0 @@ -Security model -============== - -Corda has been designed from the ground up to implement a global, decentralised database where all nodes are assumed to be -untrustworthy. This means that each node must actively cross-check each other's work to reach consensus -amongst a group of interacting participants. - -The security model plays a role in the following areas: - -* Identity: - Corda is designed for semi-private networks in which admission requires obtaining an identity signed by a root authority. - This assumption is pervasive – the flow API provides messaging in terms of identities, with routing and delivery to underlying nodes being handled automatically. - See sections 3.2 of the `Technical white paper`_ for further details on identity and the permissioning service. - -* Notarisation: pluggable notaries and algorithms offering different levels of trust. - Notaries may be validating or non-validating. A validating notary will resolve and fully check transactions they are asked to deconflict. - Without the use of any other privacy features, they gain full visibility into every transaction. - On the other hand, non-validating notaries assume transaction validity and do not request transaction data or their dependencies - beyond the list of states consumed (and thus, their level of trust is much lower and exposed to malicious use of transaction inputs). - From an algorithm perspective, Corda currently provides a distributed notary implementation that uses Raft. - -.. note:: A byzantine fault tolerant notary based on the BFT-SMaRT algorithm is included in the code, but is - still incubating and is not yet ready for use. - -* Authentication, authorisation and entitlements: - Network permissioning, including node to node authentication, is performed using TLS and certificates. - See :doc:`permissioning` for further detail. - -.. warning:: API level authentication (RPC, Web) is currently simple username/password for demonstration purposes and will be revised. - Similarly, authorisation is currently based on permission groups applied to flow execution. - -Privacy techniques - -* Partial data visibility: transactions are not globally broadcast as in many other systems. -* Transaction tear-offs: Transactions are structured as Merkle trees, and may have individual subcomponents be revealed to parties who already know the Merkle root hash. Additionally, they may sign the transaction without being able to see all of it. - - See :doc:`merkle-trees` for further detail. - -* Multi-signature support: Corda uses composite keys to support scenarios where more than one key or party is required to authorise a state object transition. - -.. note:: Future privacy techniques will include key randomisation, graph pruning, deterministic JVM sandboxing and support for secure signing devices. - See sections 10 and 13 of the `Technical white paper`_ for detailed descriptions of these techniques and features. - -.. _`Technical white paper`: _static/corda-technical-whitepaper.pdf - diff --git a/docs/source/key-concepts-states.rst b/docs/source/key-concepts-states.rst new file mode 100644 index 0000000000..da12907a72 --- /dev/null +++ b/docs/source/key-concepts-states.rst @@ -0,0 +1,44 @@ +States +====== + +.. topic:: Summary + + * *States represent on-ledger facts* + * *States are evolved by marking the current state as historic and creating an updated state* + * *Each node has a vault where it stores any relevant states to itself* + +A *state* is an immutable object representing a fact known by one or more Corda nodes at a specific point in time. +States can contain arbitrary data, allowing them to represent facts of any kind (e.g. stocks, bonds, loans, KYC data, +identity information...). + +For example, the following state represents an IOU - an agreement that Alice owes Bob an amount X: + +.. image:: resources/state.png + +Specifically, this state represents an IOU of £10 from Alice to Bob. + +As well as any information about the fact itself, the state also contains a reference to the *contract* that governs +the evolution of the state over time. We discuss contracts in :doc:`key-concepts-contracts`. + +State sequences +--------------- +As states are immutable, they cannot be modified directly to reflect a change in the state of the world. + +Instead, the lifecycle of a shared fact over time is represented by a **state sequence**. When a state needs to be +updated, we create a new version of the state representing the new state of the world, and mark the existing state as +historic. + +This sequence of state replacements gives us a full view of the evolution of the shared fact over time. We can +picture this situation as follows: + +.. image:: resources/state-sequence.png + +The vault +--------- +Each node on the network maintains a *vault* - a database where it tracks all the current and historic states that it +is aware of, and which it considers to be relevant to itself: + +.. image:: resources/vault-simple.png + +We can think of the ledger from each node's point of view as the set of all the current (i.e. non-historic) states that +it is aware of. \ No newline at end of file diff --git a/docs/source/key-concepts-time-windows.rst b/docs/source/key-concepts-time-windows.rst new file mode 100644 index 0000000000..60fb608a11 --- /dev/null +++ b/docs/source/key-concepts-time-windows.rst @@ -0,0 +1,50 @@ +Time-windows +============ + +.. topic:: Summary + + * *If a transaction includes a time-window, it can only be committed during that window* + * *The notary is the timestamping authority, refusing to commit transactions outside of that window* + * *Time-windows can have a start and end time, or be open at either end* + +Time in a distributed system +---------------------------- +A notary also act as the *timestamping authority*, verifying that a transaction occurred during a specific time-window +before notarising it. + +For a time-window to be meaningful, its implications must be binding on the party requesting it. A party can obtain a +time-window signature in order to prove that some event happened *before*, *on*, or *after* a particular point in time. +However, if the party is not also compelled to commit to the associated transaction, it has a choice of whether or not +to reveal this fact until some point in the future. As a result, we need to ensure that the notary either has to also +sign the transaction within some time tolerance, or perform timestamping *and* notarisation at the same time. The +latter is the chosen behaviour for this model. + +There will never be exact clock synchronisation between the party creating the transaction and the notary. +This is not only due to issues of physics and network latency, but also because between inserting the command and +getting the notary to sign there may be many other steps (e.g. sending the transaction to other parties involved in the +trade, requesting human sign-off...). Thus the time at which the transaction is sent for notarisation may be quite +different to the time at which the transaction was created. + +Time-windows +------------ +For this reason, times in transactions are specified as time *windows*, not absolute times. In a distributed system +there can never be "true time", only an approximation of it. Time windows can be open-ended (i.e. specify only one of +"before" and "after") or they can be fully bounded. + +.. image:: resources/time-window.gif + +In this way, we express the idea that the *true value* of the fact "the current time" is actually unknowable. Even when +both a before and an after time are included, the transaction could have occurred at any point within that time-window. + +By creating a range that can be either closed or open at one end, we allow all of the following situations to be +modelled: + +* A transaction occurring at some point after the given time (e.g. after a maturity event) +* A transaction occurring at any time before the given time (e.g. before a bankruptcy event) +* A transaction occurring at some point roughly around the given time (e.g. on a specific day) + +If a time window needs to be converted to an absolute time (e.g. for display purposes), there is a utility method to +calculate the mid point. + +.. note:: It is assumed that the time feed for a notary is GPS/NaviStar time as defined by the atomic +clocks at the US Naval Observatory. This time feed is extremely accurate and available globally for free. \ No newline at end of file diff --git a/docs/source/key-concepts-tradeoffs.rst b/docs/source/key-concepts-tradeoffs.rst new file mode 100644 index 0000000000..c1e68a6696 --- /dev/null +++ b/docs/source/key-concepts-tradeoffs.rst @@ -0,0 +1,76 @@ +Tradeoffs +========= + +.. topic:: Summary + + * *Permissioned networks are better suited for financial use-cases* + * *Point-to-point communication allows information to be shared need-to-know* + * *A UTXO model allows for more transactions-per-second* + +Permissioned vs. permissionless +------------------------------- +Traditional blockchain networks are *permissionless*. The parties on the network are anonymous, and can join and +leave at will. + +By contrast, Corda networks are *permissioned*. Each party on the network has a known identity that they use when +communicating with counterparties, and network access is controlled by a doorman. This has several benefits: + +* Anonymous parties are inappropriate for most scenarios involving regulated financial institutions +* Knowing the identity of your counterparties allows for off-ledger resolution of conflicts using existing + legal systems +* Sybil attacks are averted without the use of expensive mechanisms such as proof-of-work + +Point-to-point vs. global broadcasts +------------------------------------ +Traditional blockchain networks broadcast every message to every participant. The reason for this is two-fold: + +* Counterparty identities are not known, so a message must be sent to every participant to ensure it reaches its + intended recipient +* Making every participant aware of every transaction allows the network to prevent double-spends + +The downside is that all participants see everyone else's data. This is unacceptable for many use-cases. + +In Corda, each message is instead addressed to a specific counterparty, and is not seen by any uninvolved third +parties. The developer has full control over what messages are sent, to whom, and in what order. As a result, **data +is shared on a need-to-know basis only**. To prevent double-spends in this system, we employ notaries as +an alternative to proof-of-work. + +Corda also uses several other techniques to maximize privacy on the network: + +* **Transaction tear-offs**: Transactions are structured in a way that allows them to be digitally signed without + disclosing the transaction's contents. This is achieved using a data structure called a Merkle tree. You can read + more about this technique in :doc:`merkle-trees`. +* **Key randomisation**: The parties to a transaction are identified only by their public keys, and fresh keypairs are + generated for each transaction. As a result, an onlooker cannot identify which parties were involved in a given + transaction. + +UTXO vs. account model +---------------------- +Corda uses a *UTXO* (unspent transaction output) model. Each transaction consumes a set of existing states to produce +a set of new states. + +The alternative would be an *account* model. In an account model, stateful objects are stored on-ledger, and +transactions take the form of requests to update the current state of these objects. + +The main advantage of the UTXO model is that transactions with different inputs can be applied in parallel, +vastly increasing the network's potential transactions-per-second. In the account model, the number of +transactions-per-second is limited by the fact that updates to a given object must be applied sequentially. + +Code-is-law vs. existing legal systems +-------------------------------------- +Financial institutions need the ability to resolve conflicts using the traditional legal system where required. Corda +is designed to make this possible by: + +* Having permissioned networks, meaning that participants are aware of who they are dealing with in every single + transaction +* All code contracts are backed by a legal document describing the contract's intended behavior which can be relied + upon to resolve conflicts + +Build vs. re-use +---------------- +Wherever possible, Corda re-uses existing technologies to make the platform more robust platform overall. For +example, Corda re-uses: + +* Standard JVM programming languages for the development of CorDapps +* Existing SQL databases +* Existing message queue implementations \ No newline at end of file diff --git a/docs/source/key-concepts-transactions.rst b/docs/source/key-concepts-transactions.rst new file mode 100644 index 0000000000..3c445874ea --- /dev/null +++ b/docs/source/key-concepts-transactions.rst @@ -0,0 +1,148 @@ +Transactions +============ + +.. topic:: Summary + + * *Transactions are proposals to update the ledger* + * *A transaction proposal will only be committed if:* + + * *It doesn't contain double-spends* + * *It is contractually valid* + * *It is signed by the required parties* + +Corda uses a *UTXO* (unspent transaction output) model where every state on the ledger is immutable. The ledger +evolves over time by applying *transactions*, which update the ledger by marking zero or more existing ledger states +as historic (the *inputs*) and producing zero or more new ledger states (the *outputs*). Transactions represent a +single link in the state sequences seen in :doc:`key-concepts-states`. + +Here is an example of an update transaction, with two inputs and two outputs: + +.. image:: resources/basic-tx.png + +A transaction can contain any number of inputs and outputs of any type: + +* They can include many different state types (e.g. both cash and bonds) +* They can be issuances (have zero inputs) or exits (have zero outputs) +* They can merge or split fungible assets (e.g. combining a $2 state and a $5 state into a $7 cash state) + +Transactions are *atomic*: either all the transaction's proposed changes are accepted, or none are. + +There are two basic types of transactions: + +* Notary-change transactions (used to change a state's notary - see :doc:`key-concepts-notaries`) +* General transactions (used for everything else) + +Transaction chains +------------------ +When creating a new transaction, the output states that the transaction will propose do not exist yet, and must +therefore be created by the proposer(s) of the transaction. However, the input states already exist as the outputs of +previous transactions. We therefore include them in the proposed transaction by reference. + +These input states references are a combination of: + +* The hash of the transaction that created the input +* The input's index in the outputs of the previous transaction + +This situation can be illustrated as follows: + +.. image:: resources/tx-chain.png + +These input state references link together transactions over time, forming what is known as a *transaction chain*. + +Committing transactions +----------------------- +Initially, a transaction is just a **proposal** to update the ledger. It represents the future state of the ledger +that is desired by the transaction builder(s): + +.. image:: resources/uncommitted_tx.png + +To become reality, the transaction must receive signatures from all of the *required signers* (see **Commands**, below). Each +required signer appends their signature to the transaction to indicate that they approve the proposal: + +.. image:: resources/tx_with_sigs.png + +If all of the required signatures are gathered, the transaction becomes committed: + +.. image:: resources/committed_tx.png + +This means that: + +* The transaction's inputs are marked as historic, and cannot be used in any future transactions +* The transaction's outputs become part of the current state of the ledger + +Transaction validity +-------------------- +Each required signers should only sign the transaction if the following two conditions hold: + + * **Transaction validity**: For both the proposed transaction, and every transaction in the chain of transactions + that created the current proposed transaction's inputs: + * The transaction is digitally signed by all the required parties + * The transaction is *contractually valid* (see :doc:`key-concepts-contracts`) + * **Transaction uniqueness**: There exists no other committed transaction that has consumed any of the inputs to + our proposed transaction (see :doc:`key-concepts-consensus`) + +If the transaction gathers all the required signatures but these conditions do not hold, the transaction's outputs +will not be valid, and will not be accepted as inputs to subsequent transactions. + +Other transaction components +---------------------------- +As well as input states and output states, transactions may contain: + +* Commands +* Attachments +* Timestamps + +For example, a transaction where Alice pays off £5 of an IOU with Bob using a £5 cash payment, supported by two +attachments and a timestamp, may look as follows: + +.. image:: resources/full-tx.png + +We explore the role played by the remaining transaction components below. + +Commands +^^^^^^^^ +Suppose we have a transaction with a cash state and a bond state as inputs, and a cash state and a bond state as +outputs. This transaction could represent two different scenarios: + +* A bond purchase +* A coupon payment on a bond + +We can imagine that we'd want to impose different rules on what constitutes a valid transaction depending on whether +this is a purchase or a coupon payment. For example, in the case of a purchase, we would require a change in the bond's +current owner, whereas in the case of a coupon payment, we would require that the ownership of the bond does not +change. + +For this, we have *commands*. Including a command in a transaction allows us to indicate the transaction's intent, +affecting how we check the validity of the transaction. + +Each command is also associated with a list of one or more *signers*. By taking the union of all the public keys +listed in the commands, we get the list of the transaction's required signers. In our example, we might imagine that: + +* In a coupon payment on a bond, only the owner of the bond is required to sign +* In a cash payment, only the owner of the cash is required to sign + +We can visualize this situation as follows: + +.. image:: resources/commands.png + +Attachments +^^^^^^^^^^^ +Sometimes, we have a large piece of data that can be reused across many different transactions. Some examples: + +* A calendar of public holidays +* Supporting legal documentation +* A table of currency codes + +For this use case, we have *attachments*. Each transaction can refer to zero or more attachments by hash. These +attachments are ZIP/JAR files containing arbitrary content. The information in these files can then be +used when checking the transaction's validity. + +Time-windows +^^^^^^^^^^^^ +In some cases, we want a transaction proposed to only be approved during a certain time-window. For example: + +* An option can only be exercised after a certain date +* A bond may only be redeemed before its expiry date + +In such cases, we can add a *time-window* to the transaction. Time-windows specify the time window during which the +transaction can be committed. We discuss time-windows in the section on :doc:`key-concepts-time-windows`. \ No newline at end of file diff --git a/docs/source/key-concepts.rst b/docs/source/key-concepts.rst index d54a13b936..faff68663c 100644 --- a/docs/source/key-concepts.rst +++ b/docs/source/key-concepts.rst @@ -1,14 +1,108 @@ Overview ======== -This section describes the key concepts and features of the Corda platform. +This section describes the key concepts and features of the Corda platform. It is intended for readers who are new to +Corda, and want to understand its architecture. It does not contain any code, and is suitable for non-developers. + +This section should be read in order: + + * :doc:`key-concepts-ecosystem` + * :doc:`key-concepts-ledger` + * :doc:`key-concepts-states` + * :doc:`key-concepts-contracts` + * :doc:`key-concepts-transactions` + * :doc:`key-concepts-flows` + * :doc:`key-concepts-consensus` + * :doc:`key-concepts-notaries` + * :doc:`key-concepts-time-windows` + * :doc:`key-concepts-oracles` + * :doc:`key-concepts-node` + * :doc:`key-concepts-tradeoffs` The detailed thinking and rationale behind these concepts are presented in two white papers: * `Corda: An Introduction`_ * `Corda: A Distributed Ledger`_ (A.K.A. the Technical White Paper) -Explanations of the key concepts are also available as `videos `_. +Explanations of the key concepts are also available as `videos `_: + +.. raw:: html + +

The Corda Ledger

+ +

+ +.. raw:: html + +

States

+ +

+ +.. raw:: html + +

Transactions

+ +

+ +.. raw:: html + +

Contracts

+ +

+ +.. raw:: html + +

Legal Prose

+ +

+ +.. raw:: html + +

Commands

+ +

+ +.. raw:: html + +

Timestamps

+ +

+ +.. raw:: html + +

Attachments

+ +

+ +.. raw:: html + +

Flows

+ +

+ +.. raw:: html + +

Consensus

+ +

+ +.. raw:: html + +

Notaries

+ +

+ +.. raw:: html + +

Oracles

+ +

+ +.. raw:: html + +

Corda Node, CorDapps and Network

+ +

.. _`Corda: An Introduction`: _static/corda-introductory-whitepaper.pdf .. _`Corda: A Distributed Ledger`: _static/corda-technical-whitepaper.pdf diff --git a/docs/source/node-services.rst b/docs/source/node-services.rst index 059f8e0070..b2db166b8f 100644 --- a/docs/source/node-services.rst +++ b/docs/source/node-services.rst @@ -1,5 +1,5 @@ -Brief introduction to the node services -======================================= +Node services +============= This document is intended as a very brief introduction to the current service components inside the node. Whilst not at all exhaustive it is diff --git a/docs/source/oracles.rst b/docs/source/oracles.rst index e3e74473ca..d0086b980f 100644 --- a/docs/source/oracles.rst +++ b/docs/source/oracles.rst @@ -171,7 +171,7 @@ Let's see what parameters we pass to the constructor of this oracle. class Oracle(val identity: Party, private val signingKey: PublicKey, val clock: Clock) = TODO() Here we see the oracle needs to have its own identity, so it can check which transaction commands it is expected to -sign for, and also needs the PublicKey portion of its signing key. Later this PublicKey will be passed to the KeyManagementService +sign for, and also needs the PublicKey portion of its signing key. Later this PublicKey will be passed to the KeyManagementService to identify the internal PrivateKey used for transaction signing. The clock is used for the deadline functionality which we will not discuss further here. @@ -200,7 +200,7 @@ Binding to the network .. note:: Before reading any further, we advise that you understand the concept of flows and how to write them and use them. See :doc:`flow-state-machines`. Likewise some understanding of Cordapps, plugins and services will be helpful. - See :doc:`creating-a-cordapp`. + See :doc:`running-a-node`. The first step is to create the oracle as a service by annotating its class with ``@CordaService``. Let's see how that's done: diff --git a/docs/source/out-of-process-verification.rst b/docs/source/out-of-process-verification.rst index 90e3f6befc..269fc37eaf 100644 --- a/docs/source/out-of-process-verification.rst +++ b/docs/source/out-of-process-verification.rst @@ -1,4 +1,4 @@ -Out of process verification +Out-of-process verification =========================== A Corda node does transaction verification through ``ServiceHub.transactionVerifierService``. This is by default an diff --git a/docs/source/resources/basic-tx.png b/docs/source/resources/basic-tx.png new file mode 100644 index 0000000000000000000000000000000000000000..90b5271055a6e760267198fbc796991436e93711 GIT binary patch literal 148852 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 J{jIiv{|`7rG4lWb literal 0 HcmV?d00001 diff --git a/docs/source/resources/commands.png b/docs/source/resources/commands.png new file mode 100644 index 0000000000000000000000000000000000000000..d5b2052815df315f1489a5bf19a75cdcb0116e86 GIT binary patch literal 329823 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 SYup0h@8?6u4&v;*uKW*PHS?GN literal 0 HcmV?d00001 diff --git a/docs/source/resources/committed_tx.png b/docs/source/resources/committed_tx.png new file mode 100644 index 0000000000000000000000000000000000000000..eaee83f82cdc644d2b8f4ec0910283e43d97550b GIT binary patch literal 155663 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 q3AFOKMenjQ+3x;hm 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
}b{y-%iT1-=n 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 hocFn%IP&I%R)ACVM1SLyrh5vIvrM= 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 z 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 literal 0 HcmV?d00001 diff --git a/docs/source/resources/flow.gif b/docs/source/resources/flow.gif new file mode 100644 index 0000000000000000000000000000000000000000..8ec9f939b5c3138d206c97af9cfde096a7724659 GIT binary patch literal 251877 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
55r?+hK}&KhAdXoIcL~ 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�uH0C4rvcOMmzgvp6Fe!mKonL5r%te5{

m}C<+ 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

_Tdiv|bC?E`N>_q|Qv#zn#Qq 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%0DiNPuQG&kih+PzBa<^ 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