diff --git a/build.gradle b/build.gradle index e771afb318..94c6add7aa 100644 --- a/build.gradle +++ b/build.gradle @@ -36,10 +36,6 @@ buildscript { mavenLocal() mavenCentral() jcenter() - // TODO: Remove this once all packages are published to jcenter or maven central. (M6 or 7). - maven { - url "http://r3.bintray.com/corda" - } } dependencies { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" @@ -146,7 +142,6 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['build']) { nearestCity "London" advertisedServices = ["corda.notary.validating"] artemisPort 10002 - webPort 10003 cordapps = [] } node { diff --git a/client/src/integration-test/kotlin/net/corda/client/NodeMonitorModelTest.kt b/client/src/integration-test/kotlin/net/corda/client/NodeMonitorModelTest.kt index 4847dc943d..e0a8d6b1b3 100644 --- a/client/src/integration-test/kotlin/net/corda/client/NodeMonitorModelTest.kt +++ b/client/src/integration-test/kotlin/net/corda/client/NodeMonitorModelTest.kt @@ -124,7 +124,7 @@ class NodeMonitorModelTest : DriverBasedTest() { issueRef = OpaqueBytes(ByteArray(1, { 1 })), recipient = aliceNode.legalIdentity, notary = notaryNode.notaryIdentity - )) + )).returnValue.toBlocking().first() rpc.startFlow(::CashFlow, CashCommand.PayCash( amount = Amount(100, Issued(PartyAndReference(aliceNode.legalIdentity, OpaqueBytes(ByteArray(1, { 1 }))), USD)), diff --git a/client/src/main/kotlin/net/corda/client/model/NodeMonitorModel.kt b/client/src/main/kotlin/net/corda/client/model/NodeMonitorModel.kt index df383eb4a0..8569835beb 100644 --- a/client/src/main/kotlin/net/corda/client/model/NodeMonitorModel.kt +++ b/client/src/main/kotlin/net/corda/client/model/NodeMonitorModel.kt @@ -9,6 +9,7 @@ import net.corda.core.messaging.StateMachineUpdate import net.corda.core.node.services.NetworkMapCache.MapChange import net.corda.core.node.services.StateMachineTransactionMapping import net.corda.core.node.services.Vault +import net.corda.core.seconds import net.corda.core.transactions.SignedTransaction import net.corda.node.services.config.SSLConfiguration import net.corda.node.services.messaging.CordaRPCClient @@ -52,7 +53,9 @@ class NodeMonitorModel { * TODO provide an unsubscribe mechanism */ fun register(nodeHostAndPort: HostAndPort, sslConfig: SSLConfiguration, username: String, password: String) { - val client = CordaRPCClient(nodeHostAndPort, sslConfig) + val client = CordaRPCClient(nodeHostAndPort, sslConfig){ + maxRetryInterval = 10.seconds.toMillis() + } client.start(username, password) val proxy = client.proxy() diff --git a/core/src/main/kotlin/net/corda/core/contracts/FungibleAsset.kt b/core/src/main/kotlin/net/corda/core/contracts/FungibleAsset.kt index 34b618750e..50651b1ea0 100644 --- a/core/src/main/kotlin/net/corda/core/contracts/FungibleAsset.kt +++ b/core/src/main/kotlin/net/corda/core/contracts/FungibleAsset.kt @@ -1,8 +1,9 @@ package net.corda.core.contracts import net.corda.core.crypto.CompositeKey +import net.corda.core.flows.FlowException -class InsufficientBalanceException(val amountMissing: Amount<*>) : Exception() { +class InsufficientBalanceException(val amountMissing: Amount<*>) : FlowException() { override fun toString() = "Insufficient balance, missing $amountMissing" } diff --git a/core/src/main/kotlin/net/corda/core/crypto/Party.kt b/core/src/main/kotlin/net/corda/core/crypto/Party.kt index c02983313e..a8f0dd7378 100644 --- a/core/src/main/kotlin/net/corda/core/crypto/Party.kt +++ b/core/src/main/kotlin/net/corda/core/crypto/Party.kt @@ -18,12 +18,17 @@ import java.security.PublicKey * cluster of Corda nodes. A [Party] representing a distributed service will use a composite key containing all * individual cluster nodes' public keys. Each of the nodes in the cluster will advertise the same group [Party]. * + * Note that equality is based solely on the owning key. + * * @see CompositeKey */ -data class Party(val name: String, val owningKey: CompositeKey) { +class Party(val name: String, val owningKey: CompositeKey) { /** A helper constructor that converts the given [PublicKey] in to a [CompositeKey] with a single node */ constructor(name: String, owningKey: PublicKey) : this(name, owningKey.composite) + /** Anonymised parties do not include any detail apart from owning key, so equality is dependent solely on the key */ + override fun equals(other: Any?): Boolean = other is Party && this.owningKey == other.owningKey + override fun hashCode(): Int = owningKey.hashCode() override fun toString() = name fun ref(bytes: OpaqueBytes) = PartyAndReference(this, bytes) diff --git a/core/src/main/kotlin/net/corda/core/flows/FlowException.kt b/core/src/main/kotlin/net/corda/core/flows/FlowException.kt new file mode 100644 index 0000000000..fc8014f4d4 --- /dev/null +++ b/core/src/main/kotlin/net/corda/core/flows/FlowException.kt @@ -0,0 +1,13 @@ +package net.corda.core.flows + +/** + * 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 + * [FlowLogic.receive] or [FlowLogic.sendAndReceive]. Any flow which no longer needs to do a receive, or has already ended, + * will not receive the exception (if this is required then have them wait for a confirmation message). + * + * [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. + */ +open class FlowException @JvmOverloads constructor(message: String? = null, cause: Throwable? = null) + : Exception(message, cause) diff --git a/core/src/main/kotlin/net/corda/core/flows/FlowLogic.kt b/core/src/main/kotlin/net/corda/core/flows/FlowLogic.kt index 0f7bf0a58c..519a1c0149 100644 --- a/core/src/main/kotlin/net/corda/core/flows/FlowLogic.kt +++ b/core/src/main/kotlin/net/corda/core/flows/FlowLogic.kt @@ -73,7 +73,7 @@ abstract class FlowLogic { * @returns an [UntrustworthyData] wrapper around the received object. */ @Suspendable - open fun sendAndReceive(receiveType: Class, otherParty: Party, payload: Any): UntrustworthyData { + open fun sendAndReceive(receiveType: Class, otherParty: Party, payload: Any): UntrustworthyData { return stateMachine.sendAndReceive(receiveType, otherParty, payload, sessionFlow) } @@ -92,9 +92,11 @@ abstract class FlowLogic { * Remember that when receiving data from other parties the data should not be trusted until it's been thoroughly * verified for consistency and that all expectations are satisfied, as a malicious peer may send you subtly * corrupted data in order to exploit your code. + * + * @returns an [UntrustworthyData] wrapper around the received object. */ @Suspendable - open fun receive(receiveType: Class, otherParty: Party): UntrustworthyData { + open fun receive(receiveType: Class, otherParty: Party): UntrustworthyData { return stateMachine.receive(receiveType, otherParty, sessionFlow) } @@ -116,11 +118,15 @@ abstract class FlowLogic { * @param shareParentSessions In certain situations the need arises to use the same sessions the parent flow has * already established. However this also prevents the subflow from creating new sessions with those parties. * For this reason the default value is false. + * + * @throws FlowException This is either thrown by [subLogic] itself or propagated from any of the remote + * [FlowLogic]s it communicated with. A subflow retry can be done by catching this exception. */ // TODO Rethink the default value for shareParentSessions // TODO shareParentSessions is a bit too low-level and perhaps can be expresed in a better way @Suspendable @JvmOverloads + @Throws(FlowException::class) open fun subFlow(subLogic: FlowLogic, shareParentSessions: Boolean = false): R { subLogic.stateMachine = stateMachine maybeWireUpProgressTracking(subLogic) @@ -149,6 +155,7 @@ abstract class FlowLogic { * helpful if this flow is meant to be used as a subflow. */ @Suspendable + @Throws(FlowException::class) abstract fun call(): T /** @@ -181,7 +188,6 @@ abstract class FlowLogic { private fun maybeWireUpProgressTracking(subLogic: FlowLogic<*>) { val ours = progressTracker - val theirs = subLogic.progressTracker if (ours != null && theirs != null) { if (ours.currentStep == ProgressTracker.UNSTARTED) { diff --git a/core/src/main/kotlin/net/corda/core/flows/FlowStateMachine.kt b/core/src/main/kotlin/net/corda/core/flows/FlowStateMachine.kt index fa290bfab8..25aa753a9c 100644 --- a/core/src/main/kotlin/net/corda/core/flows/FlowStateMachine.kt +++ b/core/src/main/kotlin/net/corda/core/flows/FlowStateMachine.kt @@ -40,5 +40,3 @@ interface FlowStateMachine { val id: StateMachineRunId val resultFuture: ListenableFuture } - -class FlowException(message: String) : RuntimeException(message) 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 1f657f64de..b78612cb32 100644 --- a/core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt +++ b/core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt @@ -110,11 +110,21 @@ interface CordaRPCOps : RPCOps { */ fun uploadAttachment(jar: InputStream): SecureHash + @Suppress("DEPRECATION") + @Deprecated("This service will be removed in a future milestone") + fun uploadFile(dataType: String, name: String?, file: InputStream): String + /** * Returns the node-local current time. */ fun currentNodeTime(): Instant + /** + * Returns an Observable emitting a single Unit once the node is registered with the network map. + */ + @RPCReturnsObservables + fun waitUntilRegisteredWithNetworkMap(): Observable + // TODO These need rethinking. Instead of these direct calls we should have a way of replicating a subset of // the node's state locally and query that directly. /** 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 c81f002e3e..468a8244b3 100644 --- a/core/src/main/kotlin/net/corda/core/node/NodeInfo.kt +++ b/core/src/main/kotlin/net/corda/core/node/NodeInfo.kt @@ -18,6 +18,10 @@ data class NodeInfo(val address: SingleMessageRecipient, val legalIdentity: Party, var advertisedServices: List = emptyList(), val physicalLocation: PhysicalLocation? = null) { + init { + 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 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/services/Services.kt b/core/src/main/kotlin/net/corda/core/node/services/Services.kt index 3de6b3f864..997331c1fd 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,8 @@ import net.corda.core.toFuture import net.corda.core.transactions.TransactionBuilder import net.corda.core.transactions.WireTransaction import rx.Observable +import java.io.File +import java.io.InputStream import java.security.KeyPair import java.security.PrivateKey import java.security.PublicKey @@ -216,6 +218,24 @@ interface KeyManagementService { fun freshKey(): KeyPair } +// TODO: Move to a more appropriate location +/** + * An interface that denotes a service that can accept file uploads. + */ +interface FileUploader { + /** + * Accepts the data in the given input stream, and returns some sort of useful return message that will be sent + * back to the user in the response. + */ + fun upload(file: InputStream): String + + /** + * Check if this service accepts this type of upload. For example if you are uploading interest rates this could + * be "my-service-interest-rates". Type here does not refer to file extentions or MIME types. + */ + fun accepts(type: String): Boolean +} + /** * A sketch of an interface to a simple key/value storage system. Intended for persistence of simple blobs like * transactions, serialised flow state machines and so on. Again, this isn't intended to imply lack of SQL or @@ -232,6 +252,10 @@ interface StorageService { /** Provides access to storage of arbitrary JAR files (which may contain only data, no code). */ val attachments: AttachmentStorage + @Suppress("DEPRECATION") + @Deprecated("This service will be removed in a future milestone") + val uploaders: List + val stateMachineRecordedTransactionMapping: StateMachineRecordedTransactionMappingStorage } 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 0b5c53b6f4..d02e0b35bc 100644 --- a/core/src/main/kotlin/net/corda/core/serialization/Kryo.kt +++ b/core/src/main/kotlin/net/corda/core/serialization/Kryo.kt @@ -11,6 +11,7 @@ import com.esotericsoftware.kryo.io.Output import com.esotericsoftware.kryo.serializers.JavaSerializer import com.esotericsoftware.kryo.serializers.MapSerializer import de.javakaffee.kryoserializers.ArraysAsListSerializer +import de.javakaffee.kryoserializers.UnmodifiableCollectionsSerializer import de.javakaffee.kryoserializers.guava.* import net.corda.core.contracts.* import net.corda.core.crypto.* @@ -402,12 +403,10 @@ fun createKryo(k: Kryo = Kryo()): Kryo { // serialise the Kryo object itself when suspending a fiber. That's dumb, useless AND can cause crashes, so // we avoid it here. register(Kryo::class.java, object : Serializer() { - override fun write(kryo: Kryo, output: Output, obj: Kryo) { - } - override fun read(kryo: Kryo, input: Input, type: Class): Kryo { return createKryo((Fiber.getFiberSerializer() as KryoSerializer).kryo) } + override fun write(kryo: Kryo, output: Output, obj: Kryo) {} }) register(EdDSAPublicKey::class.java, Ed25519PublicKeySerializer) @@ -441,6 +440,7 @@ fun createKryo(k: Kryo = Kryo()): Kryo { addDefaultSerializer(BufferedInputStream::class.java, InputStreamSerializer) + UnmodifiableCollectionsSerializer.registerSerializers(k) ImmutableListSerializer.registerSerializers(k) ImmutableSetSerializer.registerSerializers(k) ImmutableSortedSetSerializer.registerSerializers(k) 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 9bf8f9ff53..efde6949fd 100644 --- a/core/src/main/kotlin/net/corda/core/transactions/SignedTransaction.kt +++ b/core/src/main/kotlin/net/corda/core/transactions/SignedTransaction.kt @@ -5,9 +5,11 @@ import net.corda.core.contracts.TransactionResolutionException import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.DigitalSignature import net.corda.core.crypto.SecureHash +import net.corda.core.crypto.signWithECDSA import net.corda.core.node.ServiceHub import net.corda.core.serialization.SerializedBytes import java.io.FileNotFoundException +import java.security.KeyPair import java.security.SignatureException import java.util.* @@ -132,4 +134,13 @@ data class SignedTransaction(val txBits: SerializedBytes, */ @Throws(FileNotFoundException::class, TransactionResolutionException::class, SignaturesMissingException::class) fun toLedgerTransaction(services: ServiceHub) = verifySignatures().toLedgerTransaction(services) + + /** + * Utility to simplify the act of signing the transaction. + * + * @param keyPair the signer's public/private key pair. + * + * @return a digital signature of the transaction. + */ + fun signWithECDSA(keyPair: KeyPair) = keyPair.signWithECDSA(this.id.bytes) } diff --git a/core/src/main/kotlin/net/corda/core/utilities/UntrustworthyData.kt b/core/src/main/kotlin/net/corda/core/utilities/UntrustworthyData.kt index 2093412c0f..b220ea20ca 100644 --- a/core/src/main/kotlin/net/corda/core/utilities/UntrustworthyData.kt +++ b/core/src/main/kotlin/net/corda/core/utilities/UntrustworthyData.kt @@ -1,5 +1,7 @@ package net.corda.core.utilities +import net.corda.core.flows.FlowException + /** * A small utility to approximate taint tracking: if a method gives you back one of these, it means the data came from * a remote source that may be incentivised to pass us junk that violates basic assumptions and thus must be checked @@ -17,6 +19,7 @@ class UntrustworthyData(private val fromUntrustedWorld: T) { get() = fromUntrustedWorld @Suppress("DEPRECATION") + @Throws(FlowException::class) inline fun unwrap(validator: (T) -> R) = validator(data) @Suppress("DEPRECATION") diff --git a/core/src/main/kotlin/net/corda/flows/AbstractStateReplacementFlow.kt b/core/src/main/kotlin/net/corda/flows/AbstractStateReplacementFlow.kt index 0e353d10c6..a05f15dd1f 100644 --- a/core/src/main/kotlin/net/corda/flows/AbstractStateReplacementFlow.kt +++ b/core/src/main/kotlin/net/corda/flows/AbstractStateReplacementFlow.kt @@ -8,6 +8,7 @@ import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.DigitalSignature import net.corda.core.crypto.Party import net.corda.core.crypto.signWithECDSA +import net.corda.core.flows.FlowException import net.corda.core.flows.FlowLogic import net.corda.core.node.recordTransactions import net.corda.core.transactions.SignedTransaction @@ -27,26 +28,22 @@ import net.corda.flows.AbstractStateReplacementFlow.Instigator * Finally, [Instigator] sends the transaction containing all signatures back to each participant so they can record it and * use the new updated state for future transactions. */ -abstract class AbstractStateReplacementFlow { - interface Proposal { - val stateRef: StateRef - val modification: T - val stx: SignedTransaction - } +abstract class AbstractStateReplacementFlow { + data class Proposal(val stateRef: StateRef, val modification: T, val stx: SignedTransaction) - abstract class Instigator(val originalState: StateAndRef, - val modification: T, - override val progressTracker: ProgressTracker = tracker()) : FlowLogic>() { + abstract class Instigator( + val originalState: StateAndRef, + val modification: T, + override val progressTracker: ProgressTracker = tracker()) : FlowLogic>() { companion object { - object SIGNING : ProgressTracker.Step("Requesting signatures from other parties") - object NOTARY : ProgressTracker.Step("Requesting notary signature") fun tracker() = ProgressTracker(SIGNING, NOTARY) } @Suspendable + @Throws(StateReplacementException::class) override fun call(): StateAndRef { val (stx, participants) = assembleTx() @@ -66,7 +63,6 @@ abstract class AbstractStateReplacementFlow { return finalTx.tx.outRef(0) } - abstract protected fun assembleProposal(stateRef: StateRef, modification: T, stx: SignedTransaction): Proposal abstract protected fun assembleTx(): Pair> @Suspendable @@ -89,59 +85,55 @@ abstract class AbstractStateReplacementFlow { @Suspendable private fun getParticipantSignature(party: Party, stx: SignedTransaction): DigitalSignature.WithKey { - val proposal = assembleProposal(originalState.ref, modification, stx) - - val response = sendAndReceive(party, proposal) - val participantSignature = response.unwrap { - if (it.sig == null) throw StateReplacementException(it.error!!) - else { - check(party.owningKey.isFulfilledBy(it.sig.by)) { "Not signed by the required participant" } - it.sig.verifyWithECDSA(stx.id) - it.sig - } + val proposal = Proposal(originalState.ref, modification, stx) + val response = sendAndReceive(party, proposal) + return response.unwrap { + check(party.owningKey.isFulfilledBy(it.by)) { "Not signed by the required participant" } + it.verifyWithECDSA(stx.id) + it } - - return participantSignature } @Suspendable private fun getNotarySignature(stx: SignedTransaction): DigitalSignature.WithKey { progressTracker.currentStep = NOTARY - return subFlow(NotaryFlow.Client(stx)) + try { + return subFlow(NotaryFlow.Client(stx)) + } catch (e: NotaryException) { + throw StateReplacementException("Unable to notarise state change", e) + } } } - abstract class Acceptor(val otherSide: Party, - override val progressTracker: ProgressTracker = tracker()) : FlowLogic() { - + abstract class Acceptor(val otherSide: Party, + override val progressTracker: ProgressTracker = tracker()) : FlowLogic() { companion object { object VERIFYING : ProgressTracker.Step("Verifying state replacement proposal") - object APPROVING : ProgressTracker.Step("State replacement approved") - object REJECTING : ProgressTracker.Step("State replacement rejected") - - fun tracker() = ProgressTracker(VERIFYING, APPROVING, REJECTING) + fun tracker() = ProgressTracker(VERIFYING, APPROVING) } @Suspendable + @Throws(StateReplacementException::class) override fun call() { progressTracker.currentStep = VERIFYING val maybeProposal: UntrustworthyData> = receive(otherSide) - try { - val stx: SignedTransaction = maybeProposal.unwrap { verifyProposal(maybeProposal).stx } - verifyTx(stx) - approve(stx) - } catch(e: Exception) { - // TODO: catch only specific exceptions. However, there are numerous validation exceptions - // that might occur (tx validation/resolution, invalid proposal). Need to rethink how - // we manage exceptions and maybe introduce some platform exception hierarchy - val myIdentity = serviceHub.myInfo.legalIdentity - val state = maybeProposal.unwrap { it.stateRef } - val reason = StateReplacementRefused(myIdentity, state, e.message) - - reject(reason) + val stx: SignedTransaction = maybeProposal.unwrap { + verifyProposal(it) + verifyTx(it.stx) + it.stx } + approve(stx) + } + + @Suspendable + private fun verifyTx(stx: SignedTransaction) { + checkMySignatureRequired(stx.tx) + checkDependenciesValid(stx) + // We expect stx to have insufficient signatures, so we convert the WireTransaction to the LedgerTransaction + // here, thus bypassing the sufficient-signatures check. + stx.tx.toLedgerTransaction(serviceHub).verify() } @Suspendable @@ -149,8 +141,7 @@ abstract class AbstractStateReplacementFlow { progressTracker.currentStep = APPROVING val mySignature = sign(stx) - val response = Result.noError(mySignature) - val swapSignatures = sendAndReceive>(otherSide, response) + val swapSignatures = sendAndReceive>(otherSide, mySignature) // TODO: This step should not be necessary, as signatures are re-checked in verifySignatures. val allSignatures = swapSignatures.unwrap { signatures -> @@ -163,28 +154,13 @@ abstract class AbstractStateReplacementFlow { serviceHub.recordTransactions(finalTx) } - @Suspendable - private fun reject(e: StateReplacementRefused) { - progressTracker.currentStep = REJECTING - val response = Result.withError(e) - send(otherSide, response) - } - /** * Check the state change proposal to confirm that it's acceptable to this node. Rules for verification depend * on the change proposed, and may further depend on the node itself (for example configuration). The - * proposal is returned if acceptable, otherwise an exception is thrown. + * proposal is returned if acceptable, otherwise a [StateReplacementException] is thrown. */ - abstract protected fun verifyProposal(maybeProposal: UntrustworthyData>): Proposal - - @Suspendable - private fun verifyTx(stx: SignedTransaction) { - checkMySignatureRequired(stx.tx) - checkDependenciesValid(stx) - // We expect stx to have insufficient signatures, so we convert the WireTransaction to the LedgerTransaction - // here, thus bypassing the sufficient-signatures check. - stx.tx.toLedgerTransaction(serviceHub).verify() - } + @Throws(StateReplacementException::class) + abstract protected fun verifyProposal(proposal: Proposal) private fun checkMySignatureRequired(tx: WireTransaction) { // TODO: use keys from the keyManagementService instead @@ -202,20 +178,7 @@ abstract class AbstractStateReplacementFlow { return myKey.signWithECDSA(stx.id) } } - - // TODO: similar classes occur in other places (NotaryFlow), need to consolidate - data class Result private constructor(val sig: DigitalSignature.WithKey?, val error: StateReplacementRefused?) { - companion object { - fun withError(error: StateReplacementRefused) = Result(null, error) - fun noError(sig: DigitalSignature.WithKey) = Result(sig, null) - } - } } - -/** Thrown when a participant refuses the proposed state replacement */ -class StateReplacementRefused(val identity: Party, val state: StateRef, val detail: String?) { - override fun toString() = "A participant $identity refused to change state $state: " + (detail ?: "no reason provided") -} - -class StateReplacementException(val error: StateReplacementRefused) : Exception("State change failed - $error") +open class StateReplacementException @JvmOverloads constructor(message: String? = null, cause: Throwable? = null) + : FlowException(message, cause) diff --git a/core/src/main/kotlin/net/corda/flows/FetchDataFlow.kt b/core/src/main/kotlin/net/corda/flows/FetchDataFlow.kt index 63c4e2f1fa..0be2b1a081 100644 --- a/core/src/main/kotlin/net/corda/flows/FetchDataFlow.kt +++ b/core/src/main/kotlin/net/corda/flows/FetchDataFlow.kt @@ -4,6 +4,7 @@ import co.paralleluniverse.fibers.Suspendable import net.corda.core.contracts.NamedByHash import net.corda.core.crypto.Party import net.corda.core.crypto.SecureHash +import net.corda.core.flows.FlowException import net.corda.core.flows.FlowLogic import net.corda.core.utilities.UntrustworthyData import net.corda.flows.FetchDataFlow.DownloadedVsRequestedDataMismatch @@ -30,14 +31,15 @@ abstract class FetchDataFlow( protected val requests: Set, protected val otherSide: Party) : FlowLogic>() { - open class BadAnswer : Exception() - class HashNotFound(val requested: SecureHash) : BadAnswer() - class DownloadedVsRequestedDataMismatch(val requested: SecureHash, val got: SecureHash) : BadAnswer() + class DownloadedVsRequestedDataMismatch(val requested: SecureHash, val got: SecureHash) : IllegalArgumentException() + class DownloadedVsRequestedSizeMismatch(val requested: Int, val got: Int) : IllegalArgumentException() + class HashNotFound(val requested: SecureHash) : FlowException() data class Request(val hashes: List) data class Result(val fromDisk: List, val downloaded: List) @Suspendable + @Throws(HashNotFound::class) override fun call(): Result { // Load the items we have from disk and figure out which we're missing. val (fromDisk, toFetch) = loadWhatWeHave() @@ -48,7 +50,7 @@ abstract class FetchDataFlow( logger.trace("Requesting ${toFetch.size} dependency(s) for verification") // TODO: Support "large message" response streaming so response sizes are not limited by RAM. - val maybeItems = sendAndReceive>(otherSide, Request(toFetch)) + val maybeItems = sendAndReceive>(otherSide, Request(toFetch)) // Check for a buggy/malicious peer answering with something that we didn't ask for. val downloaded = validateFetchResponse(maybeItems, toFetch) maybeWriteToDisk(downloaded) @@ -78,22 +80,19 @@ abstract class FetchDataFlow( @Suppress("UNCHECKED_CAST") protected open fun convert(wire: W): T = wire as T - private fun validateFetchResponse(maybeItems: UntrustworthyData>, - requests: List): List = - maybeItems.unwrap { response -> - if (response.size != requests.size) - throw BadAnswer() - for ((index, resp) in response.withIndex()) { - if (resp == null) throw HashNotFound(requests[index]) - } - val answers = response.requireNoNulls().map { convert(it) } - // Check transactions actually hash to what we requested, if this fails the remote node - // is a malicious flow violator or buggy. - for ((index, item) in answers.withIndex()) - if (item.id != requests[index]) - throw DownloadedVsRequestedDataMismatch(requests[index], item.id) - - answers + private fun validateFetchResponse(maybeItems: UntrustworthyData>, + requests: List): List { + return maybeItems.unwrap { response -> + if (response.size != requests.size) + throw DownloadedVsRequestedSizeMismatch(requests.size, response.size) + val answers = response.map { convert(it) } + // Check transactions actually hash to what we requested, if this fails the remote node + // is a malicious flow violator or buggy. + for ((index, item) in answers.withIndex()) { + if (item.id != requests[index]) + throw DownloadedVsRequestedDataMismatch(requests[index], item.id) } - + answers + } + } } diff --git a/core/src/main/kotlin/net/corda/flows/FinalityFlow.kt b/core/src/main/kotlin/net/corda/flows/FinalityFlow.kt index f6556f5217..5dac3167b5 100644 --- a/core/src/main/kotlin/net/corda/flows/FinalityFlow.kt +++ b/core/src/main/kotlin/net/corda/flows/FinalityFlow.kt @@ -27,6 +27,7 @@ class FinalityFlow(val transaction: SignedTransaction, } @Suspendable + @Throws(NotaryException::class) override fun call() { // TODO: Resolve the tx here: it's probably already been done, but re-resolution is a no-op and it'll make the API more forgiving. diff --git a/core/src/main/kotlin/net/corda/flows/NotaryChangeFlow.kt b/core/src/main/kotlin/net/corda/flows/NotaryChangeFlow.kt index a677b4335a..f6cbd6f175 100644 --- a/core/src/main/kotlin/net/corda/flows/NotaryChangeFlow.kt +++ b/core/src/main/kotlin/net/corda/flows/NotaryChangeFlow.kt @@ -1,13 +1,11 @@ package net.corda.flows -import co.paralleluniverse.fibers.Suspendable import net.corda.core.contracts.* import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.TransactionBuilder import net.corda.core.utilities.ProgressTracker -import net.corda.core.utilities.UntrustworthyData import net.corda.flows.NotaryChangeFlow.Acceptor import net.corda.flows.NotaryChangeFlow.Instigator @@ -20,19 +18,12 @@ import net.corda.flows.NotaryChangeFlow.Instigator * Finally, [Instigator] sends the transaction containing all signatures back to each participant so they can record it and * use the new updated state for future transactions. */ -object NotaryChangeFlow : AbstractStateReplacementFlow() { +object NotaryChangeFlow : AbstractStateReplacementFlow() { - data class Proposal(override val stateRef: StateRef, - override val modification: Party, - override val stx: SignedTransaction) : AbstractStateReplacementFlow.Proposal - - class Instigator(originalState: StateAndRef, - newNotary: Party, - progressTracker: ProgressTracker = tracker()) - : AbstractStateReplacementFlow.Instigator(originalState, newNotary, progressTracker) { - - override fun assembleProposal(stateRef: StateRef, modification: Party, stx: SignedTransaction): AbstractStateReplacementFlow.Proposal - = Proposal(stateRef, modification, stx) + class Instigator( + originalState: StateAndRef, + newNotary: Party, + progressTracker: ProgressTracker = tracker()) : AbstractStateReplacementFlow.Instigator(originalState, newNotary, progressTracker) { override fun assembleTx(): Pair> { val state = originalState.state @@ -66,7 +57,8 @@ object NotaryChangeFlow : AbstractStateReplacementFlow() { private fun resolveEncumbrances(tx: TransactionBuilder): Iterable { val stateRef = originalState.ref val txId = stateRef.txhash - val issuingTx = serviceHub.storageService.validatedTransactions.getTransaction(txId) ?: throw IllegalStateException("Transaction $txId not found") + val issuingTx = serviceHub.storageService.validatedTransactions.getTransaction(txId) + ?: throw StateReplacementException("Transaction $txId not found") val outputs = issuingTx.tx.outputs val participants = mutableSetOf() @@ -97,8 +89,7 @@ object NotaryChangeFlow : AbstractStateReplacementFlow() { } class Acceptor(otherSide: Party, - override val progressTracker: ProgressTracker = tracker()) - : AbstractStateReplacementFlow.Acceptor(otherSide) { + override val progressTracker: ProgressTracker = tracker()) : AbstractStateReplacementFlow.Acceptor(otherSide) { /** * Check the notary change proposal. @@ -107,26 +98,28 @@ object NotaryChangeFlow : AbstractStateReplacementFlow() { * 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 */ - @Suspendable - override fun verifyProposal(maybeProposal: UntrustworthyData>): AbstractStateReplacementFlow.Proposal { - return maybeProposal.unwrap { proposal -> - val newNotary = proposal.modification - val isNotary = serviceHub.networkMapCache.notaryNodes.any { it.notaryIdentity == newNotary } - require(isNotary) { "The proposed node $newNotary does not run a Notary service " } + override fun verifyProposal(proposal: AbstractStateReplacementFlow.Proposal): Unit { + val state = proposal.stateRef + val proposedTx = proposal.stx.tx - val state = proposal.stateRef - val proposedTx = proposal.stx.tx - require(state in proposedTx.inputs) { "The proposed state $state is not in the proposed transaction inputs" } - require(proposedTx.type.javaClass == TransactionType.NotaryChange::class.java) { - "The proposed transaction is not a notary change transaction." - } - - // An example requirement - val blacklist = listOf("Evil Notary") - require(!blacklist.contains(newNotary.name)) { "The proposed new notary $newNotary is not trusted by the party" } - - proposal + if (proposedTx.type !is TransactionType.NotaryChange) { + throw StateReplacementException("The proposed transaction is not a notary change transaction.") } + + val newNotary = proposal.modification + val isNotary = serviceHub.networkMapCache.notaryNodes.any { it.notaryIdentity == newNotary } + if (!isNotary) { + throw StateReplacementException("The proposed node $newNotary does not run a Notary service") + } + if (state !in proposedTx.inputs) { + throw StateReplacementException("The proposed state $state is not in the proposed transaction inputs") + } + +// // An example requirement +// val blacklist = listOf("Evil Notary") +// checkProposal(newNotary.name !in blacklist) { +// "The proposed new notary $newNotary is not trusted by the party" +// } } } } diff --git a/core/src/main/kotlin/net/corda/flows/NotaryFlow.kt b/core/src/main/kotlin/net/corda/flows/NotaryFlow.kt index ce3ec4bd19..af6df1cf54 100644 --- a/core/src/main/kotlin/net/corda/flows/NotaryFlow.kt +++ b/core/src/main/kotlin/net/corda/flows/NotaryFlow.kt @@ -6,6 +6,7 @@ import net.corda.core.crypto.Party import net.corda.core.crypto.SignedData import net.corda.core.crypto.signWithECDSA import net.corda.core.flows.FlowLogic +import net.corda.core.flows.FlowException import net.corda.core.node.services.TimestampChecker import net.corda.core.node.services.UniquenessException import net.corda.core.node.services.UniquenessProvider @@ -13,7 +14,6 @@ import net.corda.core.serialization.serialize import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.WireTransaction import net.corda.core.utilities.ProgressTracker -import net.corda.core.utilities.UntrustworthyData object NotaryFlow { @@ -29,9 +29,7 @@ object NotaryFlow { constructor(stx: SignedTransaction) : this(stx, Client.tracker()) companion object { - object REQUESTING : ProgressTracker.Step("Requesting signature by Notary service") - object VALIDATING : ProgressTracker.Step("Validating response from Notary service") fun tracker() = ProgressTracker(REQUESTING, VALIDATING) @@ -40,6 +38,7 @@ object NotaryFlow { lateinit var notaryParty: Party @Suspendable + @Throws(NotaryException::class) override fun call(): DigitalSignature.WithKey { progressTracker.currentStep = REQUESTING val wtx = stx.tx @@ -53,27 +52,18 @@ object NotaryFlow { throw NotaryException(NotaryError.SignaturesMissing(ex)) } - val response = sendAndReceive(notaryParty, SignRequest(stx)) - - return validateResponse(response) - } - - @Throws(NotaryException::class, IllegalStateException::class) - private fun validateResponse(response: UntrustworthyData): DigitalSignature.WithKey { - return response.unwrap { notaryResult -> - progressTracker.currentStep = VALIDATING - when (notaryResult) { - is Result.Success -> { - validateSignature(notaryResult.sig, stx.id.bytes) - notaryResult.sig - } - is Result.Error -> { - if (notaryResult.error is NotaryError.Conflict) - notaryResult.error.conflict.verified() - throw NotaryException(notaryResult.error) - } - else -> throw IllegalStateException("Received invalid result from Notary service '$notaryParty'") + val response = try { + sendAndReceive(notaryParty, SignRequest(stx)) + } catch (e: NotaryException) { + if (e.error is NotaryError.Conflict) { + e.error.conflict.verified() } + throw e + } + + return response.unwrap { sig -> + validateSignature(sig, stx.id.bytes) + sig } } @@ -101,17 +91,11 @@ object NotaryFlow { val stx = receive(otherSide).unwrap { it.tx } val wtx = stx.tx - val result = try { - validateTimestamp(wtx) - beforeCommit(stx) - commitInputStates(wtx) - val sig = sign(stx.id.bytes) - Result.Success(sig) - } catch(e: NotaryException) { - Result.Error(e.error) - } - - send(otherSide, result) + validateTimestamp(wtx) + beforeCommit(stx) + commitInputStates(wtx) + val sig = sign(stx.id.bytes) + send(otherSide, sig) } private fun validateTimestamp(tx: WireTransaction) { @@ -164,15 +148,9 @@ object NotaryFlow { } data class SignRequest(val tx: SignedTransaction) - - sealed class Result { - class Error(val error: NotaryError) : Result() - class Success(val sig: DigitalSignature.WithKey) : Result() - } - } -class NotaryException(val error: NotaryError) : Exception() { +class NotaryException(val error: NotaryError) : FlowException() { override fun toString() = "${super.toString()}: Error response from Notary - $error" } diff --git a/core/src/main/kotlin/net/corda/flows/ResolveTransactionsFlow.kt b/core/src/main/kotlin/net/corda/flows/ResolveTransactionsFlow.kt index 091e558f5e..07f573ab67 100644 --- a/core/src/main/kotlin/net/corda/flows/ResolveTransactionsFlow.kt +++ b/core/src/main/kotlin/net/corda/flows/ResolveTransactionsFlow.kt @@ -50,16 +50,12 @@ class ResolveTransactionsFlow(private val txHashes: Set, fun visit(transaction: SignedTransaction) { if (transaction.id !in visited) { visited.add(transaction.id) - forwardGraph[transaction.id]?.forEach { - visit(it) - } + forwardGraph[transaction.id]?.forEach(::visit) result.add(transaction) } } - transactions.forEach { - visit(it) - } + transactions.forEach(::visit) result.reverse() require(result.size == transactions.size) @@ -93,6 +89,7 @@ class ResolveTransactionsFlow(private val txHashes: Set, } @Suspendable + @Throws(FetchDataFlow.HashNotFound::class) override fun call(): List { val newTxns: Iterable = topologicalSort(downloadDependencies(txHashes)) diff --git a/docs/build/doctrees/CLI-vs-IDE.doctree b/docs/build/doctrees/CLI-vs-IDE.doctree index 5317893eb1..9069b546d6 100644 Binary files a/docs/build/doctrees/CLI-vs-IDE.doctree and b/docs/build/doctrees/CLI-vs-IDE.doctree differ diff --git a/docs/build/doctrees/azure-vm.doctree b/docs/build/doctrees/azure-vm.doctree index b96fc6170f..d6cd4e15bb 100644 Binary files a/docs/build/doctrees/azure-vm.doctree and b/docs/build/doctrees/azure-vm.doctree differ diff --git a/docs/build/doctrees/building-the-docs.doctree b/docs/build/doctrees/building-the-docs.doctree index fcc1d29a58..8af67fc757 100644 Binary files a/docs/build/doctrees/building-the-docs.doctree and b/docs/build/doctrees/building-the-docs.doctree differ diff --git a/docs/build/doctrees/clauses.doctree b/docs/build/doctrees/clauses.doctree index a26f49486a..432ec43785 100644 Binary files a/docs/build/doctrees/clauses.doctree and b/docs/build/doctrees/clauses.doctree differ diff --git a/docs/build/doctrees/clientrpc.doctree b/docs/build/doctrees/clientrpc.doctree index 401a17ce27..1c04f89401 100644 Binary files a/docs/build/doctrees/clientrpc.doctree and b/docs/build/doctrees/clientrpc.doctree differ diff --git a/docs/build/doctrees/codestyle.doctree b/docs/build/doctrees/codestyle.doctree index 3209cd4517..d6f1ad5343 100644 Binary files a/docs/build/doctrees/codestyle.doctree and b/docs/build/doctrees/codestyle.doctree differ diff --git a/docs/build/doctrees/consensus.doctree b/docs/build/doctrees/consensus.doctree deleted file mode 100644 index 03d8aeb9ee..0000000000 Binary files a/docs/build/doctrees/consensus.doctree and /dev/null differ diff --git a/docs/build/doctrees/contract-catalogue.doctree b/docs/build/doctrees/contract-catalogue.doctree index d307aef67a..4bb787fcd5 100644 Binary files a/docs/build/doctrees/contract-catalogue.doctree and b/docs/build/doctrees/contract-catalogue.doctree differ diff --git a/docs/build/doctrees/contract-irs.doctree b/docs/build/doctrees/contract-irs.doctree index 5a8273aeb4..8dd966511d 100644 Binary files a/docs/build/doctrees/contract-irs.doctree and b/docs/build/doctrees/contract-irs.doctree differ diff --git a/docs/build/doctrees/corda-configuration-file.doctree b/docs/build/doctrees/corda-configuration-file.doctree index 28b379bfcf..39d48630b5 100644 Binary files a/docs/build/doctrees/corda-configuration-file.doctree and b/docs/build/doctrees/corda-configuration-file.doctree differ diff --git a/docs/build/doctrees/corda-plugins.doctree b/docs/build/doctrees/corda-plugins.doctree index 168c513f79..1f95083b0b 100644 Binary files a/docs/build/doctrees/corda-plugins.doctree and b/docs/build/doctrees/corda-plugins.doctree differ diff --git a/docs/build/doctrees/creating-a-cordapp.doctree b/docs/build/doctrees/creating-a-cordapp.doctree index aed89ff94b..1720e5bc64 100644 Binary files a/docs/build/doctrees/creating-a-cordapp.doctree and b/docs/build/doctrees/creating-a-cordapp.doctree differ diff --git a/docs/build/doctrees/data-model.doctree b/docs/build/doctrees/data-model.doctree deleted file mode 100644 index 8fce0e064a..0000000000 Binary files a/docs/build/doctrees/data-model.doctree and /dev/null differ diff --git a/docs/build/doctrees/environment.pickle b/docs/build/doctrees/environment.pickle index aecf8ec83b..9004233c1d 100644 Binary files a/docs/build/doctrees/environment.pickle and b/docs/build/doctrees/environment.pickle differ diff --git a/docs/build/doctrees/event-scheduling.doctree b/docs/build/doctrees/event-scheduling.doctree index 0c01831b11..c8aa842d11 100644 Binary files a/docs/build/doctrees/event-scheduling.doctree and b/docs/build/doctrees/event-scheduling.doctree differ diff --git a/docs/build/doctrees/flow-state-machines.doctree b/docs/build/doctrees/flow-state-machines.doctree index 1770ae15ec..b476444a61 100644 Binary files a/docs/build/doctrees/flow-state-machines.doctree and b/docs/build/doctrees/flow-state-machines.doctree differ diff --git a/docs/build/doctrees/flow-testing.doctree b/docs/build/doctrees/flow-testing.doctree index 407e63d344..c2dfa7decf 100644 Binary files a/docs/build/doctrees/flow-testing.doctree and b/docs/build/doctrees/flow-testing.doctree differ diff --git a/docs/build/doctrees/further-notes-on-kotlin.doctree b/docs/build/doctrees/further-notes-on-kotlin.doctree index 79ca2b7ffc..ad69f01acd 100644 Binary files a/docs/build/doctrees/further-notes-on-kotlin.doctree and b/docs/build/doctrees/further-notes-on-kotlin.doctree differ diff --git a/docs/build/doctrees/getting-set-up-fault-finding.doctree b/docs/build/doctrees/getting-set-up-fault-finding.doctree index 85c155e26c..2959cff02f 100644 Binary files a/docs/build/doctrees/getting-set-up-fault-finding.doctree and b/docs/build/doctrees/getting-set-up-fault-finding.doctree differ diff --git a/docs/build/doctrees/getting-set-up.doctree b/docs/build/doctrees/getting-set-up.doctree index f029d98b82..623f9465c3 100644 Binary files a/docs/build/doctrees/getting-set-up.doctree and b/docs/build/doctrees/getting-set-up.doctree differ diff --git a/docs/build/doctrees/glossary.doctree b/docs/build/doctrees/glossary.doctree index 04fbdeb1c6..523ac83864 100644 Binary files a/docs/build/doctrees/glossary.doctree and b/docs/build/doctrees/glossary.doctree differ diff --git a/docs/build/doctrees/index.doctree b/docs/build/doctrees/index.doctree index 65e416f888..0b1d734ddf 100644 Binary files a/docs/build/doctrees/index.doctree and b/docs/build/doctrees/index.doctree differ diff --git a/docs/build/doctrees/inthebox.doctree b/docs/build/doctrees/inthebox.doctree index 91abd6905e..18d18f3345 100644 Binary files a/docs/build/doctrees/inthebox.doctree and b/docs/build/doctrees/inthebox.doctree differ diff --git a/docs/build/doctrees/key-concepts-consensus-notaries.doctree b/docs/build/doctrees/key-concepts-consensus-notaries.doctree new file mode 100644 index 0000000000..e1b023aee0 Binary files /dev/null and b/docs/build/doctrees/key-concepts-consensus-notaries.doctree differ diff --git a/docs/build/doctrees/key-concepts-core-types.doctree b/docs/build/doctrees/key-concepts-core-types.doctree new file mode 100644 index 0000000000..f92d96dd57 Binary files /dev/null and b/docs/build/doctrees/key-concepts-core-types.doctree differ diff --git a/docs/build/doctrees/key-concepts-data-model.doctree b/docs/build/doctrees/key-concepts-data-model.doctree new file mode 100644 index 0000000000..1c126da18d Binary files /dev/null and b/docs/build/doctrees/key-concepts-data-model.doctree differ diff --git a/docs/build/doctrees/key-concepts-ecosystem.doctree b/docs/build/doctrees/key-concepts-ecosystem.doctree new file mode 100644 index 0000000000..8c7496e86e Binary files /dev/null and b/docs/build/doctrees/key-concepts-ecosystem.doctree differ diff --git a/docs/build/doctrees/key-concepts-financial-model.doctree b/docs/build/doctrees/key-concepts-financial-model.doctree new file mode 100644 index 0000000000..9f1ff69d4f Binary files /dev/null and b/docs/build/doctrees/key-concepts-financial-model.doctree differ diff --git a/docs/build/doctrees/key-concepts-flow-framework.doctree b/docs/build/doctrees/key-concepts-flow-framework.doctree new file mode 100644 index 0000000000..1872daf41d Binary files /dev/null and b/docs/build/doctrees/key-concepts-flow-framework.doctree differ diff --git a/docs/build/doctrees/key-concepts-security-model.doctree b/docs/build/doctrees/key-concepts-security-model.doctree new file mode 100644 index 0000000000..839ccc4725 Binary files /dev/null and b/docs/build/doctrees/key-concepts-security-model.doctree differ diff --git a/docs/build/doctrees/key-concepts-vault.doctree b/docs/build/doctrees/key-concepts-vault.doctree new file mode 100644 index 0000000000..e7154c30f2 Binary files /dev/null and b/docs/build/doctrees/key-concepts-vault.doctree differ diff --git a/docs/build/doctrees/key-concepts.doctree b/docs/build/doctrees/key-concepts.doctree new file mode 100644 index 0000000000..83b9c4adfc Binary files /dev/null and b/docs/build/doctrees/key-concepts.doctree differ diff --git a/docs/build/doctrees/loadtesting.doctree b/docs/build/doctrees/loadtesting.doctree index 63bfa43a51..31f3b639f9 100644 Binary files a/docs/build/doctrees/loadtesting.doctree and b/docs/build/doctrees/loadtesting.doctree differ diff --git a/docs/build/doctrees/merkle-trees.doctree b/docs/build/doctrees/merkle-trees.doctree index 93f6b08684..c566fb7141 100644 Binary files a/docs/build/doctrees/merkle-trees.doctree and b/docs/build/doctrees/merkle-trees.doctree differ diff --git a/docs/build/doctrees/messaging.doctree b/docs/build/doctrees/messaging.doctree index 6f0d690ffe..6c1123bc20 100644 Binary files a/docs/build/doctrees/messaging.doctree and b/docs/build/doctrees/messaging.doctree differ diff --git a/docs/build/doctrees/network-simulator.doctree b/docs/build/doctrees/network-simulator.doctree index 1c5bd7a599..91f6bb5fdd 100644 Binary files a/docs/build/doctrees/network-simulator.doctree and b/docs/build/doctrees/network-simulator.doctree differ diff --git a/docs/build/doctrees/node-administration.doctree b/docs/build/doctrees/node-administration.doctree index 7b7f1c4468..ea48bac307 100644 Binary files a/docs/build/doctrees/node-administration.doctree and b/docs/build/doctrees/node-administration.doctree differ diff --git a/docs/build/doctrees/node-explorer.doctree b/docs/build/doctrees/node-explorer.doctree index a4cb95a96a..bb03e25d0f 100644 Binary files a/docs/build/doctrees/node-explorer.doctree and b/docs/build/doctrees/node-explorer.doctree differ diff --git a/docs/build/doctrees/node-services.doctree b/docs/build/doctrees/node-services.doctree index a66b36edce..45316a8f5d 100644 Binary files a/docs/build/doctrees/node-services.doctree and b/docs/build/doctrees/node-services.doctree differ diff --git a/docs/build/doctrees/oracles.doctree b/docs/build/doctrees/oracles.doctree index 4f218cd32a..44cf26e9b8 100644 Binary files a/docs/build/doctrees/oracles.doctree and b/docs/build/doctrees/oracles.doctree differ diff --git a/docs/build/doctrees/permissioning.doctree b/docs/build/doctrees/permissioning.doctree index b2f12f5cef..700bf0b205 100644 Binary files a/docs/build/doctrees/permissioning.doctree and b/docs/build/doctrees/permissioning.doctree differ diff --git a/docs/build/doctrees/persistence.doctree b/docs/build/doctrees/persistence.doctree index a977ca5d5c..8bc5f38a34 100644 Binary files a/docs/build/doctrees/persistence.doctree and b/docs/build/doctrees/persistence.doctree differ diff --git a/docs/build/doctrees/publishing-corda.doctree b/docs/build/doctrees/publishing-corda.doctree index 4d0000d604..6a38926527 100644 Binary files a/docs/build/doctrees/publishing-corda.doctree and b/docs/build/doctrees/publishing-corda.doctree differ diff --git a/docs/build/doctrees/release-notes.doctree b/docs/build/doctrees/release-notes.doctree index 1fd3944742..00dda1b451 100644 Binary files a/docs/build/doctrees/release-notes.doctree and b/docs/build/doctrees/release-notes.doctree differ diff --git a/docs/build/doctrees/release-process.doctree b/docs/build/doctrees/release-process.doctree index 73f1f7092c..91952ff5bb 100644 Binary files a/docs/build/doctrees/release-process.doctree and b/docs/build/doctrees/release-process.doctree differ diff --git a/docs/build/doctrees/running-a-notary.doctree b/docs/build/doctrees/running-a-notary.doctree index e19bd7eb65..acbf9b1a6f 100644 Binary files a/docs/build/doctrees/running-a-notary.doctree and b/docs/build/doctrees/running-a-notary.doctree differ diff --git a/docs/build/doctrees/running-the-demos.doctree b/docs/build/doctrees/running-the-demos.doctree index 423c4cfec3..55c450d797 100644 Binary files a/docs/build/doctrees/running-the-demos.doctree and b/docs/build/doctrees/running-the-demos.doctree differ diff --git a/docs/build/doctrees/secure-coding-guidelines.doctree b/docs/build/doctrees/secure-coding-guidelines.doctree index 87506f879d..fc763af662 100644 Binary files a/docs/build/doctrees/secure-coding-guidelines.doctree and b/docs/build/doctrees/secure-coding-guidelines.doctree differ diff --git a/docs/build/doctrees/setting-up-a-corda-network.doctree b/docs/build/doctrees/setting-up-a-corda-network.doctree index b0b80be91b..ef1eb12d65 100644 Binary files a/docs/build/doctrees/setting-up-a-corda-network.doctree and b/docs/build/doctrees/setting-up-a-corda-network.doctree differ diff --git a/docs/build/doctrees/transaction-data-types.doctree b/docs/build/doctrees/transaction-data-types.doctree deleted file mode 100644 index a2785bfc2b..0000000000 Binary files a/docs/build/doctrees/transaction-data-types.doctree and /dev/null differ diff --git a/docs/build/doctrees/tutorial-attachments.doctree b/docs/build/doctrees/tutorial-attachments.doctree index 1bde09c6af..3e5423aa7d 100644 Binary files a/docs/build/doctrees/tutorial-attachments.doctree and b/docs/build/doctrees/tutorial-attachments.doctree differ diff --git a/docs/build/doctrees/tutorial-building-transactions.doctree b/docs/build/doctrees/tutorial-building-transactions.doctree index 59a02ca6be..3e3ff409a7 100644 Binary files a/docs/build/doctrees/tutorial-building-transactions.doctree and b/docs/build/doctrees/tutorial-building-transactions.doctree differ diff --git a/docs/build/doctrees/tutorial-clientrpc-api.doctree b/docs/build/doctrees/tutorial-clientrpc-api.doctree index fd04332ad4..ee7f6a0d9e 100644 Binary files a/docs/build/doctrees/tutorial-clientrpc-api.doctree and b/docs/build/doctrees/tutorial-clientrpc-api.doctree differ diff --git a/docs/build/doctrees/tutorial-contract-clauses.doctree b/docs/build/doctrees/tutorial-contract-clauses.doctree index a95b5e164e..2c33eccac6 100644 Binary files a/docs/build/doctrees/tutorial-contract-clauses.doctree and b/docs/build/doctrees/tutorial-contract-clauses.doctree differ diff --git a/docs/build/doctrees/tutorial-contract.doctree b/docs/build/doctrees/tutorial-contract.doctree index 588a4f435e..f0aae6bdd6 100644 Binary files a/docs/build/doctrees/tutorial-contract.doctree and b/docs/build/doctrees/tutorial-contract.doctree differ diff --git a/docs/build/doctrees/tutorial-cordapp.doctree b/docs/build/doctrees/tutorial-cordapp.doctree index d1aa4a984e..661d3eda1a 100644 Binary files a/docs/build/doctrees/tutorial-cordapp.doctree and b/docs/build/doctrees/tutorial-cordapp.doctree differ diff --git a/docs/build/doctrees/tutorial-integration-testing.doctree b/docs/build/doctrees/tutorial-integration-testing.doctree index 8aab6869e5..1e69431b52 100644 Binary files a/docs/build/doctrees/tutorial-integration-testing.doctree and b/docs/build/doctrees/tutorial-integration-testing.doctree differ diff --git a/docs/build/doctrees/tutorial-test-dsl.doctree b/docs/build/doctrees/tutorial-test-dsl.doctree index fb5d02fec4..cc5538bfb1 100644 Binary files a/docs/build/doctrees/tutorial-test-dsl.doctree and b/docs/build/doctrees/tutorial-test-dsl.doctree differ diff --git a/docs/build/doctrees/using-a-notary.doctree b/docs/build/doctrees/using-a-notary.doctree index f70853b97e..236787ed2b 100644 Binary files a/docs/build/doctrees/using-a-notary.doctree and b/docs/build/doctrees/using-a-notary.doctree differ diff --git a/docs/build/html/.buildinfo b/docs/build/html/.buildinfo index 4e8710d66d..8966c7ddfb 100644 --- a/docs/build/html/.buildinfo +++ b/docs/build/html/.buildinfo @@ -1,4 +1,4 @@ # Sphinx build info version 1 # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. -config: caa85c0cfb7660f75ff8985c07fa3b0c +config: 1768caf6e5e802b716b72241d5bd1c76 tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/docs/build/html/CLI-vs-IDE.html b/docs/build/html/CLI-vs-IDE.html index 0edbc3e065..747a6b9141 100644 --- a/docs/build/html/CLI-vs-IDE.html +++ b/docs/build/html/CLI-vs-IDE.html @@ -34,8 +34,11 @@ + + - + @@ -116,11 +119,15 @@ API reference: Kotlin/ Key concepts

CorDapps

    @@ -158,6 +165,8 @@ API reference: Kotlin/ Other

    Component library

    @@ -290,7 +300,7 @@ they are listed in the driver DSL configuration.

     
    getCashStates() - Method in class net.corda.client.model.ContractStateModel
     
    +
    getCause() - Method in class net.corda.flows.NotaryError.SignaturesMissing
    +
     
    getCertificate() - Method in class net.corda.core.crypto.X509Utilities.CACertAndKey
     
    getCertificatesDirectory() - Method in class net.corda.node.services.config.FullNodeConfiguration
    @@ -5081,7 +5085,7 @@ which we have no cash evaluate to null (not present in map), not 0.
     
    getCertificatesDirectory() - Method in interface net.corda.node.services.config.NodeConfiguration
     
    -
    getCertificatesDirectory() - Method in interface net.corda.node.services.config.NodeSSLConfiguration
    +
    getCertificatesDirectory() - Method in interface net.corda.node.services.config.SSLConfiguration
     
    getCertService() - Method in class net.corda.node.utilities.certsigning.CertificateSigner
     
    @@ -5959,17 +5963,17 @@ owner to sign, some (i.e. cash) also require the issuer.
     
    getKEYSTORE_TYPE() - Method in class net.corda.core.crypto.X509Utilities
     
    +
    getKeyStoreFile() - Method in class net.corda.node.services.config.FullNodeConfiguration
    +
     
    +
    getKeyStoreFile($this) - Static method in class net.corda.node.services.config.NodeConfiguration.DefaultImpls
    +
     
    +
    getKeyStoreFile($this) - Static method in class net.corda.node.services.config.SSLConfiguration.DefaultImpls
    +
     
    +
    getKeyStoreFile() - Method in interface net.corda.node.services.config.SSLConfiguration
    +
     
    getKeyStorePassword() - Method in class net.corda.node.services.config.FullNodeConfiguration
     
    -
    getKeyStorePassword() - Method in interface net.corda.node.services.config.NodeSSLConfiguration
    -
     
    -
    getKeyStorePath() - Method in class net.corda.node.services.config.FullNodeConfiguration
    -
     
    -
    getKeyStorePath($this) - Static method in class net.corda.node.services.config.NodeConfiguration.DefaultImpls
    -
     
    -
    getKeyStorePath($this) - Static method in class net.corda.node.services.config.NodeSSLConfiguration.DefaultImpls
    -
     
    -
    getKeyStorePath() - Method in interface net.corda.node.services.config.NodeSSLConfiguration
    +
    getKeyStorePassword() - Method in interface net.corda.node.services.config.SSLConfiguration
     
    getKlass() - Method in class net.corda.client.model.TrackedDelegate
     
    @@ -6207,8 +6211,6 @@ except at issuance/termination.
     
    getMissing() - Method in exception net.corda.core.transactions.SignedTransaction.SignaturesMissingException
     
    -
    getMissingSigners() - Method in class net.corda.flows.NotaryError.SignaturesMissing
    -
     
    getModification() - Method in class net.corda.flows.AbstractStateReplacementFlow.Instigator
     
    getModification() - Method in interface net.corda.flows.AbstractStateReplacementFlow.Proposal
    @@ -6219,6 +6221,10 @@ except at issuance/termination.
     
    getMoveCashGenerator() - Method in class net.corda.client.mock.EventGenerator
     
    +
    getMsg() - Method in class net.corda.flows.NotaryError.SignaturesInvalid
    +
     
    +
    getMsg() - Method in class net.corda.flows.NotaryError.TransactionInvalid
    +
     
    getMultilateralNetState() - Method in class net.corda.contracts.asset.Obligation.State
    Returns an object used to determine if two states can be subject to close-out netting. If two states return @@ -7654,17 +7660,17 @@ simple, totally non-extensible binary (sub)format.
     
    getTransactions() - Method in class net.corda.node.services.persistence.DBTransactionStorage
     
    +
    getTrustStoreFile() - Method in class net.corda.node.services.config.FullNodeConfiguration
    +
     
    +
    getTrustStoreFile($this) - Static method in class net.corda.node.services.config.NodeConfiguration.DefaultImpls
    +
     
    +
    getTrustStoreFile($this) - Static method in class net.corda.node.services.config.SSLConfiguration.DefaultImpls
    +
     
    +
    getTrustStoreFile() - Method in interface net.corda.node.services.config.SSLConfiguration
    +
     
    getTrustStorePassword() - Method in class net.corda.node.services.config.FullNodeConfiguration
     
    -
    getTrustStorePassword() - Method in interface net.corda.node.services.config.NodeSSLConfiguration
    -
     
    -
    getTrustStorePath() - Method in class net.corda.node.services.config.FullNodeConfiguration
    -
     
    -
    getTrustStorePath($this) - Static method in class net.corda.node.services.config.NodeConfiguration.DefaultImpls
    -
     
    -
    getTrustStorePath($this) - Static method in class net.corda.node.services.config.NodeSSLConfiguration.DefaultImpls
    -
     
    -
    getTrustStorePath() - Method in interface net.corda.node.services.config.NodeSSLConfiguration
    +
    getTrustStorePassword() - Method in interface net.corda.node.services.config.SSLConfiguration
     
    getTx() - Method in exception net.corda.core.contracts.TransactionVerificationException
     
    @@ -10064,10 +10070,6 @@ that also encompasses the Vault observer for processing transact
    Most basic implementation of interface SchemaService.
    -
    NodeSSLConfiguration - Interface in net.corda.node.services.config
    -
     
    -
    NodeSSLConfiguration.DefaultImpls - Class in net.corda.node.services.config
    -
     
    NodeVaultService - Class in net.corda.node.services.vault
    Currently, the node vault service is a very simple RDBMS backed implementation. It will change significantly when @@ -10162,6 +10164,8 @@ must point to the same notary.
     
    NotaryError.Conflict - Class in net.corda.flows
     
    +
    NotaryError.SignaturesInvalid - Class in net.corda.flows
    +
     
    NotaryError.SignaturesMissing - Class in net.corda.flows
     
    NotaryError.TimestampInvalid - Class in net.corda.flows
    @@ -12029,7 +12033,9 @@ state object to the beneficiary. If this reduces the balance to zero, the state
     
    SignaturesFromSeller(sellerSig, notarySig) - Constructor for class net.corda.flows.TwoPartyTradeFlow.SignaturesFromSeller
     
    -
    SignaturesMissing(missingSigners) - Constructor for class net.corda.flows.NotaryError.SignaturesMissing
    +
    SignaturesInvalid(msg) - Constructor for class net.corda.flows.NotaryError.SignaturesInvalid
    +
     
    +
    SignaturesMissing(cause) - Constructor for class net.corda.flows.NotaryError.SignaturesMissing
     
    SignaturesMissingException(missing, descriptions, id) - Constructor for exception net.corda.core.transactions.SignedTransaction.SignaturesMissingException
     
    @@ -12192,6 +12198,10 @@ Points at which polynomial pieces connect are known as knots.
     
    sqlType() - Method in class net.corda.node.utilities.UUIDStringColumnType
     
    +
    SSLConfiguration - Interface in net.corda.node.services.config
    +
     
    +
    SSLConfiguration.DefaultImpls - Class in net.corda.node.services.config
    +
     
    StackSnapshot - Exception in net.corda.node.services.statemachine
     
    StackSnapshot() - Constructor for exception net.corda.node.services.statemachine.StackSnapshot
    @@ -13370,7 +13380,7 @@ the starting point down in order to find transactions that match the given query
    TransactionGraphSearch.Query - Class in net.corda.core.contracts
     
    -
    TransactionInvalid() - Constructor for class net.corda.flows.NotaryError.TransactionInvalid
    +
    TransactionInvalid(msg) - Constructor for class net.corda.flows.NotaryError.TransactionInvalid
     
    TransactionMissingEncumbranceException(tx, missing, inOut) - Constructor for exception net.corda.core.contracts.TransactionVerificationException.TransactionMissingEncumbranceException
     
    diff --git a/docs/build/html/api/javadoc/index.html b/docs/build/html/api/javadoc/index.html index b6a0cc0b85..aecb94cb69 100644 --- a/docs/build/html/api/javadoc/index.html +++ b/docs/build/html/api/javadoc/index.html @@ -2,7 +2,7 @@ - + Generated Documentation (Untitled) diff --git a/docs/build/html/api/javadoc/net/corda/client/fxutils/package-summary.html b/docs/build/html/api/javadoc/net/corda/client/fxutils/package-summary.html index 61d755f295..2cec564074 100644 --- a/docs/build/html/api/javadoc/net/corda/client/fxutils/package-summary.html +++ b/docs/build/html/api/javadoc/net/corda/client/fxutils/package-summary.html @@ -2,10 +2,10 @@ - + net.corda.client.fxutils - + diff --git a/docs/build/html/api/javadoc/net/corda/client/fxutils/package-tree.html b/docs/build/html/api/javadoc/net/corda/client/fxutils/package-tree.html index 833d893561..21d0a48ae2 100644 --- a/docs/build/html/api/javadoc/net/corda/client/fxutils/package-tree.html +++ b/docs/build/html/api/javadoc/net/corda/client/fxutils/package-tree.html @@ -2,10 +2,10 @@ - + net.corda.client.fxutils Class Hierarchy - + diff --git a/docs/build/html/api/javadoc/net/corda/client/mock/EventGenerator.html b/docs/build/html/api/javadoc/net/corda/client/mock/EventGenerator.html index dfd9207ce2..e3577b4a82 100644 --- a/docs/build/html/api/javadoc/net/corda/client/mock/EventGenerator.html +++ b/docs/build/html/api/javadoc/net/corda/client/mock/EventGenerator.html @@ -2,10 +2,10 @@ - + EventGenerator - + diff --git a/docs/build/html/api/javadoc/net/corda/client/mock/Generator.Companion.html b/docs/build/html/api/javadoc/net/corda/client/mock/Generator.Companion.html index 51e03b7e95..949f3953d1 100644 --- a/docs/build/html/api/javadoc/net/corda/client/mock/Generator.Companion.html +++ b/docs/build/html/api/javadoc/net/corda/client/mock/Generator.Companion.html @@ -2,10 +2,10 @@ - + Generator.Companion - + diff --git a/docs/build/html/api/javadoc/net/corda/client/mock/Generator.html b/docs/build/html/api/javadoc/net/corda/client/mock/Generator.html index 352da7b116..58ee099f50 100644 --- a/docs/build/html/api/javadoc/net/corda/client/mock/Generator.html +++ b/docs/build/html/api/javadoc/net/corda/client/mock/Generator.html @@ -2,10 +2,10 @@ - + Generator - + diff --git a/docs/build/html/api/javadoc/net/corda/client/mock/GeneratorKt.html b/docs/build/html/api/javadoc/net/corda/client/mock/GeneratorKt.html index 7de3f9dcc9..cb35a5ec7e 100644 --- a/docs/build/html/api/javadoc/net/corda/client/mock/GeneratorKt.html +++ b/docs/build/html/api/javadoc/net/corda/client/mock/GeneratorKt.html @@ -2,10 +2,10 @@ - + GeneratorKt - + diff --git a/docs/build/html/api/javadoc/net/corda/client/mock/GeneratorsKt.html b/docs/build/html/api/javadoc/net/corda/client/mock/GeneratorsKt.html index 9f2ecc18ba..c549e7d0e1 100644 --- a/docs/build/html/api/javadoc/net/corda/client/mock/GeneratorsKt.html +++ b/docs/build/html/api/javadoc/net/corda/client/mock/GeneratorsKt.html @@ -2,10 +2,10 @@ - + GeneratorsKt - + diff --git a/docs/build/html/api/javadoc/net/corda/client/mock/package-frame.html b/docs/build/html/api/javadoc/net/corda/client/mock/package-frame.html index 2400e0f24b..3344021c55 100644 --- a/docs/build/html/api/javadoc/net/corda/client/mock/package-frame.html +++ b/docs/build/html/api/javadoc/net/corda/client/mock/package-frame.html @@ -2,10 +2,10 @@ - + net.corda.client.mock - + diff --git a/docs/build/html/api/javadoc/net/corda/client/mock/package-summary.html b/docs/build/html/api/javadoc/net/corda/client/mock/package-summary.html index 6158968a1e..d161d4248e 100644 --- a/docs/build/html/api/javadoc/net/corda/client/mock/package-summary.html +++ b/docs/build/html/api/javadoc/net/corda/client/mock/package-summary.html @@ -2,10 +2,10 @@ - + net.corda.client.mock - + diff --git a/docs/build/html/api/javadoc/net/corda/client/mock/package-tree.html b/docs/build/html/api/javadoc/net/corda/client/mock/package-tree.html index 6b90877039..777fb878c3 100644 --- a/docs/build/html/api/javadoc/net/corda/client/mock/package-tree.html +++ b/docs/build/html/api/javadoc/net/corda/client/mock/package-tree.html @@ -2,10 +2,10 @@ - + net.corda.client.mock Class Hierarchy - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/ContractStateModel.Companion.html b/docs/build/html/api/javadoc/net/corda/client/model/ContractStateModel.Companion.html index 7d270d4fba..991314008d 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/ContractStateModel.Companion.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/ContractStateModel.Companion.html @@ -2,10 +2,10 @@ - + ContractStateModel.Companion - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/ContractStateModel.html b/docs/build/html/api/javadoc/net/corda/client/model/ContractStateModel.html index 143225d86f..4466234d77 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/ContractStateModel.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/ContractStateModel.html @@ -2,10 +2,10 @@ - + ContractStateModel - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/Diff.html b/docs/build/html/api/javadoc/net/corda/client/model/Diff.html index 62363437ed..0f6ba6a950 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/Diff.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/Diff.html @@ -2,10 +2,10 @@ - + Diff - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/ExchangeRate.html b/docs/build/html/api/javadoc/net/corda/client/model/ExchangeRate.html index 55e78ff6eb..fe720fcc6d 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/ExchangeRate.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/ExchangeRate.html @@ -2,10 +2,10 @@ - + ExchangeRate - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/ExchangeRateModel.html b/docs/build/html/api/javadoc/net/corda/client/model/ExchangeRateModel.html index 456c36a852..bc265e6b40 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/ExchangeRateModel.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/ExchangeRateModel.html @@ -2,10 +2,10 @@ - + ExchangeRateModel - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/ExchangeRateModelKt.html b/docs/build/html/api/javadoc/net/corda/client/model/ExchangeRateModelKt.html index ca313d5436..14df2257bd 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/ExchangeRateModelKt.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/ExchangeRateModelKt.html @@ -2,10 +2,10 @@ - + ExchangeRateModelKt - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/FlowStatus.html b/docs/build/html/api/javadoc/net/corda/client/model/FlowStatus.html index 5d02d4d90d..85eb3b0964 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/FlowStatus.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/FlowStatus.html @@ -2,10 +2,10 @@ - + FlowStatus - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/GatheredTransactionData.html b/docs/build/html/api/javadoc/net/corda/client/model/GatheredTransactionData.html index 2280bc334d..6b027e30e5 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/GatheredTransactionData.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/GatheredTransactionData.html @@ -2,10 +2,10 @@ - + GatheredTransactionData - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/InputResolution.Resolved.html b/docs/build/html/api/javadoc/net/corda/client/model/InputResolution.Resolved.html index af71b087f5..53a2e229ca 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/InputResolution.Resolved.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/InputResolution.Resolved.html @@ -2,10 +2,10 @@ - + InputResolution.Resolved - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/InputResolution.Unresolved.html b/docs/build/html/api/javadoc/net/corda/client/model/InputResolution.Unresolved.html index ca52fbd9f2..3bd1addc32 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/InputResolution.Unresolved.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/InputResolution.Unresolved.html @@ -2,10 +2,10 @@ - + InputResolution.Unresolved - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/Models.html b/docs/build/html/api/javadoc/net/corda/client/model/Models.html index 6fcdbb347f..f1e5b01c11 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/Models.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/Models.html @@ -2,10 +2,10 @@ - + Models - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/ModelsKt.html b/docs/build/html/api/javadoc/net/corda/client/model/ModelsKt.html index a54e18faf6..0c030773f3 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/ModelsKt.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/ModelsKt.html @@ -2,10 +2,10 @@ - + ModelsKt - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/NetworkIdentityModel.html b/docs/build/html/api/javadoc/net/corda/client/model/NetworkIdentityModel.html index a08b754160..548c348c4f 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/NetworkIdentityModel.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/NetworkIdentityModel.html @@ -2,10 +2,10 @@ - + NetworkIdentityModel - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/NodeMonitorModel.html b/docs/build/html/api/javadoc/net/corda/client/model/NodeMonitorModel.html index efcf2eb05b..11841f263a 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/NodeMonitorModel.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/NodeMonitorModel.html @@ -2,10 +2,10 @@ - + NodeMonitorModel - + @@ -183,7 +183,7 @@ var activeTableTab = "activeTableTab"; void register(com.google.common.net.HostAndPort nodeHostAndPort, - NodeSSLConfiguration sslConfig, + SSLConfiguration sslConfig, java.lang.String username, java.lang.String password)
    Register for updates to/from a given vault. @@ -293,7 +293,7 @@ TODO provide an unsubscribe mechanism
  • register

    public void register(com.google.common.net.HostAndPort nodeHostAndPort,
    -                     NodeSSLConfiguration sslConfig,
    +                     SSLConfiguration sslConfig,
                          java.lang.String username,
                          java.lang.String password)

    Register for updates to/from a given vault. diff --git a/docs/build/html/api/javadoc/net/corda/client/model/PartiallyResolvedTransaction.Companion.html b/docs/build/html/api/javadoc/net/corda/client/model/PartiallyResolvedTransaction.Companion.html index 1209fc0779..619e1a1180 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/PartiallyResolvedTransaction.Companion.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/PartiallyResolvedTransaction.Companion.html @@ -2,10 +2,10 @@ - + PartiallyResolvedTransaction.Companion - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/PartiallyResolvedTransaction.InputResolution.html b/docs/build/html/api/javadoc/net/corda/client/model/PartiallyResolvedTransaction.InputResolution.html index ea573417e7..eec8f117d3 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/PartiallyResolvedTransaction.InputResolution.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/PartiallyResolvedTransaction.InputResolution.html @@ -2,10 +2,10 @@ - + PartiallyResolvedTransaction.InputResolution - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/PartiallyResolvedTransaction.html b/docs/build/html/api/javadoc/net/corda/client/model/PartiallyResolvedTransaction.html index a779ea05f3..fdea66debf 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/PartiallyResolvedTransaction.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/PartiallyResolvedTransaction.html @@ -2,10 +2,10 @@ - + PartiallyResolvedTransaction - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/ProgressTrackingEvent.Companion.html b/docs/build/html/api/javadoc/net/corda/client/model/ProgressTrackingEvent.Companion.html index 95d7aeb237..d7b7d0429a 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/ProgressTrackingEvent.Companion.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/ProgressTrackingEvent.Companion.html @@ -2,10 +2,10 @@ - + ProgressTrackingEvent.Companion - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/ProgressTrackingEvent.html b/docs/build/html/api/javadoc/net/corda/client/model/ProgressTrackingEvent.html index 26d717aa73..9fdd03ee56 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/ProgressTrackingEvent.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/ProgressTrackingEvent.html @@ -2,10 +2,10 @@ - + ProgressTrackingEvent - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/StateMachineData.html b/docs/build/html/api/javadoc/net/corda/client/model/StateMachineData.html index 933f1116f1..42a4bc03cd 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/StateMachineData.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/StateMachineData.html @@ -2,10 +2,10 @@ - + StateMachineData - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/StateMachineStatus.Added.html b/docs/build/html/api/javadoc/net/corda/client/model/StateMachineStatus.Added.html index d1f09df731..cb72ec86fc 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/StateMachineStatus.Added.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/StateMachineStatus.Added.html @@ -2,10 +2,10 @@ - + StateMachineStatus.Added - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/StateMachineStatus.Removed.html b/docs/build/html/api/javadoc/net/corda/client/model/StateMachineStatus.Removed.html index 5c1b3df7a5..2dc94a8970 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/StateMachineStatus.Removed.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/StateMachineStatus.Removed.html @@ -2,10 +2,10 @@ - + StateMachineStatus.Removed - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/StateMachineStatus.html b/docs/build/html/api/javadoc/net/corda/client/model/StateMachineStatus.html index a831ace0a9..c1ebecbee4 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/StateMachineStatus.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/StateMachineStatus.html @@ -2,10 +2,10 @@ - + StateMachineStatus - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.EventSinkDelegate.html b/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.EventSinkDelegate.html index 16c66e5774..708c18d0e3 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.EventSinkDelegate.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.EventSinkDelegate.html @@ -2,10 +2,10 @@ - + TrackedDelegate.EventSinkDelegate - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.EventStreamDelegate.html b/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.EventStreamDelegate.html index 85a2769617..e3357070f5 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.EventStreamDelegate.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.EventStreamDelegate.html @@ -2,10 +2,10 @@ - + TrackedDelegate.EventStreamDelegate - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.ObjectPropertyDelegate.html b/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.ObjectPropertyDelegate.html index 67ae2c1dae..8b16c768bb 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.ObjectPropertyDelegate.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.ObjectPropertyDelegate.html @@ -2,10 +2,10 @@ - + TrackedDelegate.ObjectPropertyDelegate - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.ObservableDelegate.html b/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.ObservableDelegate.html index cb014204d3..9c4357bd02 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.ObservableDelegate.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.ObservableDelegate.html @@ -2,10 +2,10 @@ - + TrackedDelegate.ObservableDelegate - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.ObservableListDelegate.html b/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.ObservableListDelegate.html index 7b696489e8..a094f23c8d 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.ObservableListDelegate.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.ObservableListDelegate.html @@ -2,10 +2,10 @@ - + TrackedDelegate.ObservableListDelegate - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.ObservableListReadOnlyDelegate.html b/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.ObservableListReadOnlyDelegate.html index 310c6ba993..15c861221b 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.ObservableListReadOnlyDelegate.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.ObservableListReadOnlyDelegate.html @@ -2,10 +2,10 @@ - + TrackedDelegate.ObservableListReadOnlyDelegate - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.ObservableValueDelegate.html b/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.ObservableValueDelegate.html index 02624cbd1a..c8d60454c1 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.ObservableValueDelegate.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.ObservableValueDelegate.html @@ -2,10 +2,10 @@ - + TrackedDelegate.ObservableValueDelegate - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.ObserverDelegate.html b/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.ObserverDelegate.html index 34130c662c..aad985bea0 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.ObserverDelegate.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.ObserverDelegate.html @@ -2,10 +2,10 @@ - + TrackedDelegate.ObserverDelegate - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.SubjectDelegate.html b/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.SubjectDelegate.html index 9da96d08b8..e3385f0b96 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.SubjectDelegate.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.SubjectDelegate.html @@ -2,10 +2,10 @@ - + TrackedDelegate.SubjectDelegate - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.WritableValueDelegate.html b/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.WritableValueDelegate.html index 1b1d5219c5..d82719aff9 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.WritableValueDelegate.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.WritableValueDelegate.html @@ -2,10 +2,10 @@ - + TrackedDelegate.WritableValueDelegate - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.html b/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.html index 149f95ce23..0d17c9a2f5 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/TrackedDelegate.html @@ -2,10 +2,10 @@ - + TrackedDelegate - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/TransactionCreateStatus.Failed.html b/docs/build/html/api/javadoc/net/corda/client/model/TransactionCreateStatus.Failed.html index 4cc0cc3fbd..15a252553a 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/TransactionCreateStatus.Failed.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/TransactionCreateStatus.Failed.html @@ -2,10 +2,10 @@ - + TransactionCreateStatus.Failed - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/TransactionCreateStatus.Started.html b/docs/build/html/api/javadoc/net/corda/client/model/TransactionCreateStatus.Started.html index 9eefe659ba..eb6ef066c4 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/TransactionCreateStatus.Started.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/TransactionCreateStatus.Started.html @@ -2,10 +2,10 @@ - + TransactionCreateStatus.Started - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/TransactionCreateStatus.html b/docs/build/html/api/javadoc/net/corda/client/model/TransactionCreateStatus.html index 1f2f5a38f0..fef6131c2b 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/TransactionCreateStatus.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/TransactionCreateStatus.html @@ -2,10 +2,10 @@ - + TransactionCreateStatus - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/TransactionDataModel.html b/docs/build/html/api/javadoc/net/corda/client/model/TransactionDataModel.html index 1c9cd83a97..78c4e50948 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/TransactionDataModel.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/TransactionDataModel.html @@ -2,10 +2,10 @@ - + TransactionDataModel - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/package-frame.html b/docs/build/html/api/javadoc/net/corda/client/model/package-frame.html index 3414d0636e..3cef586274 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/package-frame.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/package-frame.html @@ -2,10 +2,10 @@ - + net.corda.client.model - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/package-summary.html b/docs/build/html/api/javadoc/net/corda/client/model/package-summary.html index 9510eeff99..4577530655 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/package-summary.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/package-summary.html @@ -2,10 +2,10 @@ - + net.corda.client.model - + diff --git a/docs/build/html/api/javadoc/net/corda/client/model/package-tree.html b/docs/build/html/api/javadoc/net/corda/client/model/package-tree.html index 1f681ba9e3..b92367f2f0 100644 --- a/docs/build/html/api/javadoc/net/corda/client/model/package-tree.html +++ b/docs/build/html/api/javadoc/net/corda/client/model/package-tree.html @@ -2,10 +2,10 @@ - + net.corda.client.model Class Hierarchy - + @@ -110,13 +110,13 @@

  • net.corda.client.model.StateMachineStatus.Removed
-
  • net.corda.client.model.ProgressTrackingEvent
  • net.corda.client.model.TransactionCreateStatus
  • +
  • net.corda.client.model.ProgressTrackingEvent
  • net.corda.client.model.ModelsKt
  • net.corda.client.model.ExchangeRateModelKt
  • net.corda.client.model.NetworkIdentityModel
  • diff --git a/docs/build/html/api/javadoc/net/corda/contracts/Clauses.Group.html b/docs/build/html/api/javadoc/net/corda/contracts/Clauses.Group.html index e61f92db65..a420fc6448 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/Clauses.Group.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/Clauses.Group.html @@ -2,10 +2,10 @@ - + Clauses.Group - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/Clauses.Issue.html b/docs/build/html/api/javadoc/net/corda/contracts/Clauses.Issue.html index 0283d2521c..92941700b2 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/Clauses.Issue.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/Clauses.Issue.html @@ -2,10 +2,10 @@ - + Clauses.Issue - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/Clauses.Move.html b/docs/build/html/api/javadoc/net/corda/contracts/Clauses.Move.html index b6e8a99e1e..0832e39dac 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/Clauses.Move.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/Clauses.Move.html @@ -2,10 +2,10 @@ - + Clauses.Move - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/Clauses.Redeem.html b/docs/build/html/api/javadoc/net/corda/contracts/Clauses.Redeem.html index bf5c029dbe..e0e3f739f4 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/Clauses.Redeem.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/Clauses.Redeem.html @@ -2,10 +2,10 @@ - + Clauses.Redeem - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/Commands.Issue.html b/docs/build/html/api/javadoc/net/corda/contracts/Commands.Issue.html index 665b465ed8..8820dc86a6 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/Commands.Issue.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/Commands.Issue.html @@ -2,10 +2,10 @@ - + Commands.Issue - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/Commands.Move.html b/docs/build/html/api/javadoc/net/corda/contracts/Commands.Move.html index 4c156009ac..e82e66835a 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/Commands.Move.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/Commands.Move.html @@ -2,10 +2,10 @@ - + Commands.Move - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/Commands.Redeem.html b/docs/build/html/api/javadoc/net/corda/contracts/Commands.Redeem.html index 54217a376b..293c339fcb 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/Commands.Redeem.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/Commands.Redeem.html @@ -2,10 +2,10 @@ - + Commands.Redeem - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaper.Clauses.html b/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaper.Clauses.html index dd22e2bff6..07b7019ae1 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaper.Clauses.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaper.Clauses.html @@ -2,10 +2,10 @@ - + CommercialPaper.Clauses - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaper.Commands.html b/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaper.Commands.html index d8cf8d74dd..6d5afce637 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaper.Commands.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaper.Commands.html @@ -2,10 +2,10 @@ - + CommercialPaper.Commands - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaper.State.html b/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaper.State.html index 284b534761..7a59dd6a0a 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaper.State.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaper.State.html @@ -2,10 +2,10 @@ - + CommercialPaper.State - + @@ -259,15 +259,15 @@ implements toString()  -net.corda.contracts.ICommercialPaperState +NonExistentClass withFaceValue(Amount<net.corda.core.contracts.Issued> newFaceValue)  -net.corda.contracts.ICommercialPaperState +NonExistentClass withIssuance(PartyAndReference newIssuance)  -net.corda.contracts.ICommercialPaperState +NonExistentClass withMaturityDate(java.time.Instant newMaturityDate)  @@ -277,7 +277,7 @@ implements -net.corda.contracts.ICommercialPaperState +NonExistentClass withOwner(CompositeKey newOwner)  @@ -417,7 +417,7 @@ list should just contain the owner.

    • withOwner

      -
      public net.corda.contracts.ICommercialPaperState withOwner(CompositeKey newOwner)
      +
      public NonExistentClass withOwner(CompositeKey newOwner)
    @@ -426,7 +426,7 @@ list should just contain the owner.

    @@ -435,7 +435,7 @@ list should just contain the owner.

    @@ -444,7 +444,7 @@ list should just contain the owner.

    • withMaturityDate

      -
      public net.corda.contracts.ICommercialPaperState withMaturityDate(java.time.Instant newMaturityDate)
      +
      public NonExistentClass withMaturityDate(java.time.Instant newMaturityDate)
    diff --git a/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaper.Terms.html b/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaper.Terms.html index 87a6ad5291..1d977d0cae 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaper.Terms.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaper.Terms.html @@ -2,10 +2,10 @@ - + CommercialPaper.Terms - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaper.html b/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaper.html index 58276b26b0..a8f3dfff2f 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaper.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaper.html @@ -2,10 +2,10 @@ - + CommercialPaper - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaperKt.html b/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaperKt.html index bd75ae2687..9e5d8e9523 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaperKt.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaperKt.html @@ -2,10 +2,10 @@ - + CommercialPaperKt - + @@ -143,8 +143,8 @@ is adjusted as if the paper was redeemed and immediately repurchased, but withou CompositeKey owner)  -static net.corda.contracts.ICommercialPaperState -owned by(net.corda.contracts.ICommercialPaperState $receiver, +static NonExistentClass +owned by(NonExistentClass $receiver, CompositeKey newOwner)  @@ -213,8 +213,8 @@ the prototyping phase. It is thus very incomplete.

    Open issues:

    • owned by

      -
      public static net.corda.contracts.ICommercialPaperState owned by(net.corda.contracts.ICommercialPaperState $receiver,
      -                                                                 CompositeKey newOwner)
      +
      public static NonExistentClass owned by(NonExistentClass $receiver,
      +                                        CompositeKey newOwner)
    diff --git a/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaperLegacy.Commands.html b/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaperLegacy.Commands.html index 59ba8c4506..a612d15a5d 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaperLegacy.Commands.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaperLegacy.Commands.html @@ -2,10 +2,10 @@ - + CommercialPaperLegacy.Commands - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaperLegacy.State.html b/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaperLegacy.State.html index a904582e44..1dea84ea0c 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaperLegacy.State.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaperLegacy.State.html @@ -2,10 +2,10 @@ - + CommercialPaperLegacy.State - + @@ -241,15 +241,15 @@ implements toString()  -net.corda.contracts.ICommercialPaperState +NonExistentClass withFaceValue(Amount<net.corda.core.contracts.Issued> newFaceValue)  -net.corda.contracts.ICommercialPaperState +NonExistentClass withIssuance(PartyAndReference newIssuance)  -net.corda.contracts.ICommercialPaperState +NonExistentClass withMaturityDate(java.time.Instant newMaturityDate)  @@ -259,7 +259,7 @@ implements -net.corda.contracts.ICommercialPaperState +NonExistentClass withOwner(CompositeKey newOwner)  @@ -396,7 +396,7 @@ list should just contain the owner.

    • withOwner

      -
      public net.corda.contracts.ICommercialPaperState withOwner(CompositeKey newOwner)
      +
      public NonExistentClass withOwner(CompositeKey newOwner)
    @@ -405,7 +405,7 @@ list should just contain the owner.

    @@ -414,7 +414,7 @@ list should just contain the owner.

    @@ -423,7 +423,7 @@ list should just contain the owner.

    • withMaturityDate

      -
      public net.corda.contracts.ICommercialPaperState withMaturityDate(java.time.Instant newMaturityDate)
      +
      public NonExistentClass withMaturityDate(java.time.Instant newMaturityDate)
    diff --git a/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaperLegacy.html b/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaperLegacy.html index 9179ca21cc..8849605237 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaperLegacy.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaperLegacy.html @@ -2,10 +2,10 @@ - + CommercialPaperLegacy - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaperLegacyKt.html b/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaperLegacyKt.html index 76e35628a0..00c440b631 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaperLegacyKt.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/CommercialPaperLegacyKt.html @@ -2,10 +2,10 @@ - + CommercialPaperLegacyKt - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/asset/Cash.Clauses.html b/docs/build/html/api/javadoc/net/corda/contracts/asset/Cash.Clauses.html index 35c9b6ea26..589d5fc9ab 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/asset/Cash.Clauses.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/asset/Cash.Clauses.html @@ -2,10 +2,10 @@ - + Cash.Clauses - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/asset/Cash.Commands.html b/docs/build/html/api/javadoc/net/corda/contracts/asset/Cash.Commands.html index 3d7318e1cb..8eacb7b5fa 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/asset/Cash.Commands.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/asset/Cash.Commands.html @@ -2,10 +2,10 @@ - + Cash.Commands - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/asset/Cash.State.html b/docs/build/html/api/javadoc/net/corda/contracts/asset/Cash.State.html index 02184c1c24..da310e23d6 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/asset/Cash.State.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/asset/Cash.State.html @@ -2,10 +2,10 @@ - + Cash.State - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/asset/Cash.html b/docs/build/html/api/javadoc/net/corda/contracts/asset/Cash.html index c00aa30918..678ecfb160 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/asset/Cash.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/asset/Cash.html @@ -2,10 +2,10 @@ - + Cash - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/asset/CashKt.html b/docs/build/html/api/javadoc/net/corda/contracts/asset/CashKt.html index f1e21de0cd..a2717fb0b7 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/asset/CashKt.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/asset/CashKt.html @@ -2,10 +2,10 @@ - + CashKt - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/asset/Clauses.ConserveAmount.html b/docs/build/html/api/javadoc/net/corda/contracts/asset/Clauses.ConserveAmount.html index 5bf0713c5a..af70fef9e7 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/asset/Clauses.ConserveAmount.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/asset/Clauses.ConserveAmount.html @@ -2,10 +2,10 @@ - + Clauses.ConserveAmount - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/asset/Clauses.Group.html b/docs/build/html/api/javadoc/net/corda/contracts/asset/Clauses.Group.html index d42cc946b9..2d9ef32716 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/asset/Clauses.Group.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/asset/Clauses.Group.html @@ -2,10 +2,10 @@ - + Clauses.Group - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/asset/Clauses.Issue.html b/docs/build/html/api/javadoc/net/corda/contracts/asset/Clauses.Issue.html index 00caf72a6e..d5dea0e276 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/asset/Clauses.Issue.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/asset/Clauses.Issue.html @@ -2,10 +2,10 @@ - + Clauses.Issue - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/asset/Clauses.Net.html b/docs/build/html/api/javadoc/net/corda/contracts/asset/Clauses.Net.html index 41e859c1f1..86852e087d 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/asset/Clauses.Net.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/asset/Clauses.Net.html @@ -2,10 +2,10 @@ - + Clauses.Net - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/asset/Clauses.SetLifecycle.html b/docs/build/html/api/javadoc/net/corda/contracts/asset/Clauses.SetLifecycle.html index 9579857398..3c1936b677 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/asset/Clauses.SetLifecycle.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/asset/Clauses.SetLifecycle.html @@ -2,10 +2,10 @@ - + Clauses.SetLifecycle - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/asset/Clauses.Settle.html b/docs/build/html/api/javadoc/net/corda/contracts/asset/Clauses.Settle.html index 8ed3249a35..af563a2330 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/asset/Clauses.Settle.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/asset/Clauses.Settle.html @@ -2,10 +2,10 @@ - + Clauses.Settle - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/asset/Clauses.VerifyLifecycle.html b/docs/build/html/api/javadoc/net/corda/contracts/asset/Clauses.VerifyLifecycle.html index a25a080198..58935fba12 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/asset/Clauses.VerifyLifecycle.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/asset/Clauses.VerifyLifecycle.html @@ -2,10 +2,10 @@ - + Clauses.VerifyLifecycle - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/asset/Commands.Exit.html b/docs/build/html/api/javadoc/net/corda/contracts/asset/Commands.Exit.html index fb10c38d90..d832d453bd 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/asset/Commands.Exit.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/asset/Commands.Exit.html @@ -2,10 +2,10 @@ - + Commands.Exit - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/asset/Commands.Issue.html b/docs/build/html/api/javadoc/net/corda/contracts/asset/Commands.Issue.html index 08e236073a..45e44e5ffb 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/asset/Commands.Issue.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/asset/Commands.Issue.html @@ -2,10 +2,10 @@ - + Commands.Issue - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/asset/Commands.Move.html b/docs/build/html/api/javadoc/net/corda/contracts/asset/Commands.Move.html index 8702f9856c..fec4bd9a2c 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/asset/Commands.Move.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/asset/Commands.Move.html @@ -2,10 +2,10 @@ - + Commands.Move - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/asset/Commands.Net.html b/docs/build/html/api/javadoc/net/corda/contracts/asset/Commands.Net.html index 60bfc50d4b..1bb2061bec 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/asset/Commands.Net.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/asset/Commands.Net.html @@ -2,10 +2,10 @@ - + Commands.Net - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/asset/Commands.SetLifecycle.html b/docs/build/html/api/javadoc/net/corda/contracts/asset/Commands.SetLifecycle.html index aca82570ea..c52e892bd3 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/asset/Commands.SetLifecycle.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/asset/Commands.SetLifecycle.html @@ -2,10 +2,10 @@ - + Commands.SetLifecycle - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/asset/Commands.Settle.html b/docs/build/html/api/javadoc/net/corda/contracts/asset/Commands.Settle.html index 946f0417e3..8825b4c12b 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/asset/Commands.Settle.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/asset/Commands.Settle.html @@ -2,10 +2,10 @@ - + Commands.Settle - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/asset/CommodityContract.Clauses.html b/docs/build/html/api/javadoc/net/corda/contracts/asset/CommodityContract.Clauses.html index b3ab8235c3..1ba8493557 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/asset/CommodityContract.Clauses.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/asset/CommodityContract.Clauses.html @@ -2,10 +2,10 @@ - + CommodityContract.Clauses - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/asset/CommodityContract.Commands.html b/docs/build/html/api/javadoc/net/corda/contracts/asset/CommodityContract.Commands.html index 70f88fb6ec..2e78d2856e 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/asset/CommodityContract.Commands.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/asset/CommodityContract.Commands.html @@ -2,10 +2,10 @@ - + CommodityContract.Commands - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/asset/CommodityContract.State.html b/docs/build/html/api/javadoc/net/corda/contracts/asset/CommodityContract.State.html index 6740bac3b3..46a52721a4 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/asset/CommodityContract.State.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/asset/CommodityContract.State.html @@ -2,10 +2,10 @@ - + CommodityContract.State - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/asset/CommodityContract.html b/docs/build/html/api/javadoc/net/corda/contracts/asset/CommodityContract.html index 457273a565..f661225dc9 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/asset/CommodityContract.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/asset/CommodityContract.html @@ -2,10 +2,10 @@ - + CommodityContract - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/asset/CommodityContractKt.html b/docs/build/html/api/javadoc/net/corda/contracts/asset/CommodityContractKt.html index c1ddfde8b0..b41d7cf8ab 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/asset/CommodityContractKt.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/asset/CommodityContractKt.html @@ -2,10 +2,10 @@ - + CommodityContractKt - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/asset/Obligation.Clauses.html b/docs/build/html/api/javadoc/net/corda/contracts/asset/Obligation.Clauses.html index 3cf0844e4b..264fa94d10 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/asset/Obligation.Clauses.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/asset/Obligation.Clauses.html @@ -2,10 +2,10 @@ - + Obligation.Clauses - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/asset/Obligation.Commands.html b/docs/build/html/api/javadoc/net/corda/contracts/asset/Obligation.Commands.html index 7470955a47..01e276d4a2 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/asset/Obligation.Commands.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/asset/Obligation.Commands.html @@ -2,10 +2,10 @@ - + Obligation.Commands - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/asset/Obligation.Lifecycle.html b/docs/build/html/api/javadoc/net/corda/contracts/asset/Obligation.Lifecycle.html index a9309acd38..a1d3f1744c 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/asset/Obligation.Lifecycle.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/asset/Obligation.Lifecycle.html @@ -2,10 +2,10 @@ - + Obligation.Lifecycle - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/asset/Obligation.State.html b/docs/build/html/api/javadoc/net/corda/contracts/asset/Obligation.State.html index 848c00830f..7670da4f54 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/asset/Obligation.State.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/asset/Obligation.State.html @@ -2,10 +2,10 @@ - + Obligation.State - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/asset/Obligation.Terms.html b/docs/build/html/api/javadoc/net/corda/contracts/asset/Obligation.Terms.html index 56c1e2700f..163cc82322 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/asset/Obligation.Terms.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/asset/Obligation.Terms.html @@ -2,10 +2,10 @@ - + Obligation.Terms - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/asset/Obligation.html b/docs/build/html/api/javadoc/net/corda/contracts/asset/Obligation.html index d5e2c12451..687e1344e7 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/asset/Obligation.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/asset/Obligation.html @@ -2,10 +2,10 @@ - + Obligation - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/asset/ObligationKt.html b/docs/build/html/api/javadoc/net/corda/contracts/asset/ObligationKt.html index acaa8d2f6a..5c5f4f987e 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/asset/ObligationKt.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/asset/ObligationKt.html @@ -2,10 +2,10 @@ - + ObligationKt - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/asset/OnLedgerAsset.html b/docs/build/html/api/javadoc/net/corda/contracts/asset/OnLedgerAsset.html index 2a70f9d578..12774238e0 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/asset/OnLedgerAsset.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/asset/OnLedgerAsset.html @@ -2,10 +2,10 @@ - + OnLedgerAsset - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/asset/package-frame.html b/docs/build/html/api/javadoc/net/corda/contracts/asset/package-frame.html index 9b9a5cab97..58f048670a 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/asset/package-frame.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/asset/package-frame.html @@ -2,10 +2,10 @@ - + net.corda.contracts.asset - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/asset/package-summary.html b/docs/build/html/api/javadoc/net/corda/contracts/asset/package-summary.html index 221cf5ecf6..563bec86e3 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/asset/package-summary.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/asset/package-summary.html @@ -2,10 +2,10 @@ - + net.corda.contracts.asset - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/asset/package-tree.html b/docs/build/html/api/javadoc/net/corda/contracts/asset/package-tree.html index 4693c5fecb..bad02069c8 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/asset/package-tree.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/asset/package-tree.html @@ -2,10 +2,10 @@ - + net.corda.contracts.asset Class Hierarchy - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/clause/AbstractConserveAmount.html b/docs/build/html/api/javadoc/net/corda/contracts/clause/AbstractConserveAmount.html index 0ae5239ea4..162868c994 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/clause/AbstractConserveAmount.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/clause/AbstractConserveAmount.html @@ -2,10 +2,10 @@ - + AbstractConserveAmount - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/clause/AbstractIssue.html b/docs/build/html/api/javadoc/net/corda/contracts/clause/AbstractIssue.html index 1e785a00ae..d753adb645 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/clause/AbstractIssue.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/clause/AbstractIssue.html @@ -2,10 +2,10 @@ - + AbstractIssue - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/clause/BilateralNetState.html b/docs/build/html/api/javadoc/net/corda/contracts/clause/BilateralNetState.html index 7e60d67ffe..a6fe8e5ee9 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/clause/BilateralNetState.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/clause/BilateralNetState.html @@ -2,10 +2,10 @@ - + BilateralNetState - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/clause/MultilateralNetState.html b/docs/build/html/api/javadoc/net/corda/contracts/clause/MultilateralNetState.html index 616ffc8664..2593d17eca 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/clause/MultilateralNetState.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/clause/MultilateralNetState.html @@ -2,10 +2,10 @@ - + MultilateralNetState - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/clause/NetClause.html b/docs/build/html/api/javadoc/net/corda/contracts/clause/NetClause.html index 3bec2b590b..6b45af3330 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/clause/NetClause.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/clause/NetClause.html @@ -2,10 +2,10 @@ - + NetClause - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/clause/NetState.html b/docs/build/html/api/javadoc/net/corda/contracts/clause/NetState.html index 639a78d081..7d4beab93f 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/clause/NetState.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/clause/NetState.html @@ -2,10 +2,10 @@ - + NetState - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/clause/NoZeroSizedOutputs.html b/docs/build/html/api/javadoc/net/corda/contracts/clause/NoZeroSizedOutputs.html index 82f1cb13ac..7ccc173634 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/clause/NoZeroSizedOutputs.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/clause/NoZeroSizedOutputs.html @@ -2,10 +2,10 @@ - + NoZeroSizedOutputs - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/clause/package-frame.html b/docs/build/html/api/javadoc/net/corda/contracts/clause/package-frame.html index c3089cfd21..14faf4739e 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/clause/package-frame.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/clause/package-frame.html @@ -2,10 +2,10 @@ - + net.corda.contracts.clause - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/clause/package-summary.html b/docs/build/html/api/javadoc/net/corda/contracts/clause/package-summary.html index 7027be02df..5ef9ce00a7 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/clause/package-summary.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/clause/package-summary.html @@ -2,10 +2,10 @@ - + net.corda.contracts.clause - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/clause/package-tree.html b/docs/build/html/api/javadoc/net/corda/contracts/clause/package-tree.html index b2ef38ec17..89381019ec 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/clause/package-tree.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/clause/package-tree.html @@ -2,10 +2,10 @@ - + net.corda.contracts.clause Class Hierarchy - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/package-frame.html b/docs/build/html/api/javadoc/net/corda/contracts/package-frame.html index 1b4b83b625..c61c02dd61 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/package-frame.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/package-frame.html @@ -2,10 +2,10 @@ - + net.corda.contracts - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/package-summary.html b/docs/build/html/api/javadoc/net/corda/contracts/package-summary.html index 4168422dff..b85620a96f 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/package-summary.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/package-summary.html @@ -2,10 +2,10 @@ - + net.corda.contracts - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/package-tree.html b/docs/build/html/api/javadoc/net/corda/contracts/package-tree.html index d7f2b7bf7d..3074a12ad1 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/package-tree.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/package-tree.html @@ -2,10 +2,10 @@ - + net.corda.contracts Class Hierarchy - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/testing/CommandDataGenerator.html b/docs/build/html/api/javadoc/net/corda/contracts/testing/CommandDataGenerator.html index 876c7ddd8d..2dae96d9e6 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/testing/CommandDataGenerator.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/testing/CommandDataGenerator.html @@ -2,10 +2,10 @@ - + CommandDataGenerator - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/testing/CommandGenerator.html b/docs/build/html/api/javadoc/net/corda/contracts/testing/CommandGenerator.html index 949446ec22..4702f3b4cf 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/testing/CommandGenerator.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/testing/CommandGenerator.html @@ -2,10 +2,10 @@ - + CommandGenerator - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/testing/ContractStateGenerator.html b/docs/build/html/api/javadoc/net/corda/contracts/testing/ContractStateGenerator.html index 14acb35b1c..ebac1edf1c 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/testing/ContractStateGenerator.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/testing/ContractStateGenerator.html @@ -2,10 +2,10 @@ - + ContractStateGenerator - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/testing/ExitGenerator.html b/docs/build/html/api/javadoc/net/corda/contracts/testing/ExitGenerator.html index 77ed88a3a8..c6215bc1f1 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/testing/ExitGenerator.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/testing/ExitGenerator.html @@ -2,10 +2,10 @@ - + ExitGenerator - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/testing/IssueGenerator.html b/docs/build/html/api/javadoc/net/corda/contracts/testing/IssueGenerator.html index d91b926c6c..5fdd265299 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/testing/IssueGenerator.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/testing/IssueGenerator.html @@ -2,10 +2,10 @@ - + IssueGenerator - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/testing/MoveGenerator.html b/docs/build/html/api/javadoc/net/corda/contracts/testing/MoveGenerator.html index 960e139674..1e1068a92c 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/testing/MoveGenerator.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/testing/MoveGenerator.html @@ -2,10 +2,10 @@ - + MoveGenerator - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/testing/SignedTransactionGenerator.html b/docs/build/html/api/javadoc/net/corda/contracts/testing/SignedTransactionGenerator.html index 390f739314..f59fe4bb00 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/testing/SignedTransactionGenerator.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/testing/SignedTransactionGenerator.html @@ -2,10 +2,10 @@ - + SignedTransactionGenerator - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/testing/VaultFiller.html b/docs/build/html/api/javadoc/net/corda/contracts/testing/VaultFiller.html index daf9e3e152..f47ca73740 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/testing/VaultFiller.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/testing/VaultFiller.html @@ -2,10 +2,10 @@ - + VaultFiller - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/testing/WiredTransactionGenerator.html b/docs/build/html/api/javadoc/net/corda/contracts/testing/WiredTransactionGenerator.html index 6e2946496f..34a16375b7 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/testing/WiredTransactionGenerator.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/testing/WiredTransactionGenerator.html @@ -2,10 +2,10 @@ - + WiredTransactionGenerator - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/testing/package-frame.html b/docs/build/html/api/javadoc/net/corda/contracts/testing/package-frame.html index 0fd56220cf..d9ead28c54 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/testing/package-frame.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/testing/package-frame.html @@ -2,10 +2,10 @@ - + net.corda.contracts.testing - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/testing/package-summary.html b/docs/build/html/api/javadoc/net/corda/contracts/testing/package-summary.html index cca8286afa..e37409541e 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/testing/package-summary.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/testing/package-summary.html @@ -2,10 +2,10 @@ - + net.corda.contracts.testing - + diff --git a/docs/build/html/api/javadoc/net/corda/contracts/testing/package-tree.html b/docs/build/html/api/javadoc/net/corda/contracts/testing/package-tree.html index 8640b1af2b..6032d3c8d6 100644 --- a/docs/build/html/api/javadoc/net/corda/contracts/testing/package-tree.html +++ b/docs/build/html/api/javadoc/net/corda/contracts/testing/package-tree.html @@ -2,10 +2,10 @@ - + net.corda.contracts.testing Class Hierarchy - + diff --git a/docs/build/html/api/javadoc/net/corda/core/ErrorOr.Companion.html b/docs/build/html/api/javadoc/net/corda/core/ErrorOr.Companion.html index c56145a725..578b305506 100644 --- a/docs/build/html/api/javadoc/net/corda/core/ErrorOr.Companion.html +++ b/docs/build/html/api/javadoc/net/corda/core/ErrorOr.Companion.html @@ -2,10 +2,10 @@ - + ErrorOr.Companion - + diff --git a/docs/build/html/api/javadoc/net/corda/core/ErrorOr.html b/docs/build/html/api/javadoc/net/corda/core/ErrorOr.html index 57a8534e75..867077001d 100644 --- a/docs/build/html/api/javadoc/net/corda/core/ErrorOr.html +++ b/docs/build/html/api/javadoc/net/corda/core/ErrorOr.html @@ -2,10 +2,10 @@ - + ErrorOr - + diff --git a/docs/build/html/api/javadoc/net/corda/core/RetryableException.html b/docs/build/html/api/javadoc/net/corda/core/RetryableException.html index 30e37aa300..868ae70c6e 100644 --- a/docs/build/html/api/javadoc/net/corda/core/RetryableException.html +++ b/docs/build/html/api/javadoc/net/corda/core/RetryableException.html @@ -2,10 +2,10 @@ - + RetryableException - + diff --git a/docs/build/html/api/javadoc/net/corda/core/ThreadBox.html b/docs/build/html/api/javadoc/net/corda/core/ThreadBox.html index 7e37b1e320..28dcdfb033 100644 --- a/docs/build/html/api/javadoc/net/corda/core/ThreadBox.html +++ b/docs/build/html/api/javadoc/net/corda/core/ThreadBox.html @@ -2,10 +2,10 @@ - + ThreadBox - + diff --git a/docs/build/html/api/javadoc/net/corda/core/TransientProperty.html b/docs/build/html/api/javadoc/net/corda/core/TransientProperty.html index 2212b5c6be..b40d9b2ef1 100644 --- a/docs/build/html/api/javadoc/net/corda/core/TransientProperty.html +++ b/docs/build/html/api/javadoc/net/corda/core/TransientProperty.html @@ -2,10 +2,10 @@ - + TransientProperty - + diff --git a/docs/build/html/api/javadoc/net/corda/core/Utils.html b/docs/build/html/api/javadoc/net/corda/core/Utils.html index ff1bb5405a..bbbcc33652 100644 --- a/docs/build/html/api/javadoc/net/corda/core/Utils.html +++ b/docs/build/html/api/javadoc/net/corda/core/Utils.html @@ -2,10 +2,10 @@ - + Utils - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/AccrualAdjustment.html b/docs/build/html/api/javadoc/net/corda/core/contracts/AccrualAdjustment.html index f1997fbc1f..f892bb0b9a 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/AccrualAdjustment.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/AccrualAdjustment.html @@ -2,10 +2,10 @@ - + AccrualAdjustment - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/Amount.Companion.html b/docs/build/html/api/javadoc/net/corda/core/contracts/Amount.Companion.html index 7702f666aa..56e07864b8 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/Amount.Companion.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/Amount.Companion.html @@ -2,10 +2,10 @@ - + Amount.Companion - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/Amount.html b/docs/build/html/api/javadoc/net/corda/core/contracts/Amount.html index 66191ffc19..305cf397f2 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/Amount.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/Amount.html @@ -2,10 +2,10 @@ - + Amount - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/Attachment.DefaultImpls.html b/docs/build/html/api/javadoc/net/corda/core/contracts/Attachment.DefaultImpls.html index fe69a9c243..d4c8360c7b 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/Attachment.DefaultImpls.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/Attachment.DefaultImpls.html @@ -2,10 +2,10 @@ - + Attachment.DefaultImpls - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/Attachment.html b/docs/build/html/api/javadoc/net/corda/core/contracts/Attachment.html index 3ce04c7a9d..12e0b790c7 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/Attachment.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/Attachment.html @@ -2,10 +2,10 @@ - + Attachment - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/AuthenticatedObject.html b/docs/build/html/api/javadoc/net/corda/core/contracts/AuthenticatedObject.html index 18e3d5edf2..4596f579d1 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/AuthenticatedObject.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/AuthenticatedObject.html @@ -2,10 +2,10 @@ - + AuthenticatedObject - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/BilateralNettableState.html b/docs/build/html/api/javadoc/net/corda/core/contracts/BilateralNettableState.html index a96e12a854..9fa909c2e3 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/BilateralNettableState.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/BilateralNettableState.html @@ -2,10 +2,10 @@ - + BilateralNettableState - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/BusinessCalendar.Companion.html b/docs/build/html/api/javadoc/net/corda/core/contracts/BusinessCalendar.Companion.html index 043f3c2226..943f3d2394 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/BusinessCalendar.Companion.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/BusinessCalendar.Companion.html @@ -2,10 +2,10 @@ - + BusinessCalendar.Companion - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/BusinessCalendar.UnknownCalendar.html b/docs/build/html/api/javadoc/net/corda/core/contracts/BusinessCalendar.UnknownCalendar.html index a558b69c5e..4c679b02c2 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/BusinessCalendar.UnknownCalendar.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/BusinessCalendar.UnknownCalendar.html @@ -2,10 +2,10 @@ - + BusinessCalendar.UnknownCalendar - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/BusinessCalendar.html b/docs/build/html/api/javadoc/net/corda/core/contracts/BusinessCalendar.html index 6214f75846..547c6ceeed 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/BusinessCalendar.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/BusinessCalendar.html @@ -2,10 +2,10 @@ - + BusinessCalendar - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/Command.html b/docs/build/html/api/javadoc/net/corda/core/contracts/Command.html index 2eda807d5b..a5515fa532 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/Command.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/Command.html @@ -2,10 +2,10 @@ - + Command - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/CommandData.html b/docs/build/html/api/javadoc/net/corda/core/contracts/CommandData.html index 6d559a4565..91e3aa743c 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/CommandData.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/CommandData.html @@ -2,10 +2,10 @@ - + CommandData - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/Commands.Create.html b/docs/build/html/api/javadoc/net/corda/core/contracts/Commands.Create.html index 15991ac21d..f87aada74c 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/Commands.Create.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/Commands.Create.html @@ -2,10 +2,10 @@ - + Commands.Create - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/Commands.Exit.html b/docs/build/html/api/javadoc/net/corda/core/contracts/Commands.Exit.html index 289f9e985a..b6e5984691 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/Commands.Exit.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/Commands.Exit.html @@ -2,10 +2,10 @@ - + Commands.Exit - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/Commands.Issue.html b/docs/build/html/api/javadoc/net/corda/core/contracts/Commands.Issue.html index 1a909128ee..96810110c0 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/Commands.Issue.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/Commands.Issue.html @@ -2,10 +2,10 @@ - + Commands.Issue - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/Commands.Move.html b/docs/build/html/api/javadoc/net/corda/core/contracts/Commands.Move.html index d5283cb035..f9bd4b6423 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/Commands.Move.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/Commands.Move.html @@ -2,10 +2,10 @@ - + Commands.Move - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/Commodity.Companion.html b/docs/build/html/api/javadoc/net/corda/core/contracts/Commodity.Companion.html index 868cf1c7a7..179c9a427a 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/Commodity.Companion.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/Commodity.Companion.html @@ -2,10 +2,10 @@ - + Commodity.Companion - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/Commodity.html b/docs/build/html/api/javadoc/net/corda/core/contracts/Commodity.html index 4b5cdec630..f1a2d998b9 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/Commodity.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/Commodity.html @@ -2,10 +2,10 @@ - + Commodity - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/Contract.html b/docs/build/html/api/javadoc/net/corda/core/contracts/Contract.html index 372765c497..c74466dd67 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/Contract.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/Contract.html @@ -2,10 +2,10 @@ - + Contract - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/ContractState.html b/docs/build/html/api/javadoc/net/corda/core/contracts/ContractState.html index c32fc0a2a0..b11cdfc6e7 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/ContractState.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/ContractState.html @@ -2,10 +2,10 @@ - + ContractState - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/ContractsDSL.html b/docs/build/html/api/javadoc/net/corda/core/contracts/ContractsDSL.html index b0bd6d0f92..2762cff71e 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/ContractsDSL.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/ContractsDSL.html @@ -2,10 +2,10 @@ - + ContractsDSL - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/DateRollConvention.Actual.html b/docs/build/html/api/javadoc/net/corda/core/contracts/DateRollConvention.Actual.html index 9754b9e7cc..d9331b89e6 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/DateRollConvention.Actual.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/DateRollConvention.Actual.html @@ -2,10 +2,10 @@ - + DateRollConvention.Actual - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/DateRollConvention.Following.html b/docs/build/html/api/javadoc/net/corda/core/contracts/DateRollConvention.Following.html index 3f51206f9e..9d056a316a 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/DateRollConvention.Following.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/DateRollConvention.Following.html @@ -2,10 +2,10 @@ - + DateRollConvention.Following - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/DateRollConvention.ModifiedFollowing.html b/docs/build/html/api/javadoc/net/corda/core/contracts/DateRollConvention.ModifiedFollowing.html index 9ffa44f371..32a7dc2c89 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/DateRollConvention.ModifiedFollowing.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/DateRollConvention.ModifiedFollowing.html @@ -2,10 +2,10 @@ - + DateRollConvention.ModifiedFollowing - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/DateRollConvention.ModifiedPrevious.html b/docs/build/html/api/javadoc/net/corda/core/contracts/DateRollConvention.ModifiedPrevious.html index db0ad55ce9..48a2ed18a4 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/DateRollConvention.ModifiedPrevious.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/DateRollConvention.ModifiedPrevious.html @@ -2,10 +2,10 @@ - + DateRollConvention.ModifiedPrevious - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/DateRollConvention.Previous.html b/docs/build/html/api/javadoc/net/corda/core/contracts/DateRollConvention.Previous.html index 4d6ab42083..dee6b534c1 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/DateRollConvention.Previous.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/DateRollConvention.Previous.html @@ -2,10 +2,10 @@ - + DateRollConvention.Previous - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/DateRollConvention.html b/docs/build/html/api/javadoc/net/corda/core/contracts/DateRollConvention.html index 6d368972e0..8e02692305 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/DateRollConvention.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/DateRollConvention.html @@ -2,10 +2,10 @@ - + DateRollConvention - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/DateRollDirection.html b/docs/build/html/api/javadoc/net/corda/core/contracts/DateRollDirection.html index b7b229c437..0a6a383f74 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/DateRollDirection.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/DateRollDirection.html @@ -2,10 +2,10 @@ - + DateRollDirection - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/DayCountBasisDay.html b/docs/build/html/api/javadoc/net/corda/core/contracts/DayCountBasisDay.html index c1bd3bd9ce..4f66324827 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/DayCountBasisDay.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/DayCountBasisDay.html @@ -2,10 +2,10 @@ - + DayCountBasisDay - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/DayCountBasisYear.html b/docs/build/html/api/javadoc/net/corda/core/contracts/DayCountBasisYear.html index faa528bc37..bcc6301181 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/DayCountBasisYear.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/DayCountBasisYear.html @@ -2,10 +2,10 @@ - + DayCountBasisYear - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/DealState.html b/docs/build/html/api/javadoc/net/corda/core/contracts/DealState.html index 8451e4fbac..5c02f6f7cf 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/DealState.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/DealState.html @@ -2,10 +2,10 @@ - + DealState - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/DummyContract.Commands.html b/docs/build/html/api/javadoc/net/corda/core/contracts/DummyContract.Commands.html index d0b5135303..15d161f3b7 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/DummyContract.Commands.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/DummyContract.Commands.html @@ -2,10 +2,10 @@ - + DummyContract.Commands - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/DummyContract.Companion.html b/docs/build/html/api/javadoc/net/corda/core/contracts/DummyContract.Companion.html index 76539fd530..b2de2290e9 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/DummyContract.Companion.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/DummyContract.Companion.html @@ -2,10 +2,10 @@ - + DummyContract.Companion - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/DummyContract.MultiOwnerState.html b/docs/build/html/api/javadoc/net/corda/core/contracts/DummyContract.MultiOwnerState.html index 8bf26f7abf..cb697b5641 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/DummyContract.MultiOwnerState.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/DummyContract.MultiOwnerState.html @@ -2,10 +2,10 @@ - + DummyContract.MultiOwnerState - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/DummyContract.SingleOwnerState.html b/docs/build/html/api/javadoc/net/corda/core/contracts/DummyContract.SingleOwnerState.html index d6ab0af9e7..40d6281168 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/DummyContract.SingleOwnerState.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/DummyContract.SingleOwnerState.html @@ -2,10 +2,10 @@ - + DummyContract.SingleOwnerState - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/DummyContract.State.html b/docs/build/html/api/javadoc/net/corda/core/contracts/DummyContract.State.html index 4e2c4895d1..2036efefcb 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/DummyContract.State.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/DummyContract.State.html @@ -2,10 +2,10 @@ - + DummyContract.State - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/DummyContract.html b/docs/build/html/api/javadoc/net/corda/core/contracts/DummyContract.html index 924fdf91ae..2b9248f690 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/DummyContract.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/DummyContract.html @@ -2,10 +2,10 @@ - + DummyContract - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/DummyContractKt.html b/docs/build/html/api/javadoc/net/corda/core/contracts/DummyContractKt.html index 62854dca6a..ede297b1f1 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/DummyContractKt.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/DummyContractKt.html @@ -2,10 +2,10 @@ - + DummyContractKt - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/DummyState.html b/docs/build/html/api/javadoc/net/corda/core/contracts/DummyState.html index 88d21a47b4..c172d75ba8 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/DummyState.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/DummyState.html @@ -2,10 +2,10 @@ - + DummyState - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/Expression.html b/docs/build/html/api/javadoc/net/corda/core/contracts/Expression.html index 0ad9226c82..36263e1759 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/Expression.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/Expression.html @@ -2,10 +2,10 @@ - + Expression - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/ExpressionDeserializer.html b/docs/build/html/api/javadoc/net/corda/core/contracts/ExpressionDeserializer.html index 503ae8ea64..4145629f64 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/ExpressionDeserializer.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/ExpressionDeserializer.html @@ -2,10 +2,10 @@ - + ExpressionDeserializer - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/ExpressionSerializer.html b/docs/build/html/api/javadoc/net/corda/core/contracts/ExpressionSerializer.html index 5e743c82a3..8ac26cb8de 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/ExpressionSerializer.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/ExpressionSerializer.html @@ -2,10 +2,10 @@ - + ExpressionSerializer - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/FinanceTypesKt.html b/docs/build/html/api/javadoc/net/corda/core/contracts/FinanceTypesKt.html index 1a6c730027..3ccbe47d5e 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/FinanceTypesKt.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/FinanceTypesKt.html @@ -2,10 +2,10 @@ - + FinanceTypesKt - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/Fix.html b/docs/build/html/api/javadoc/net/corda/core/contracts/Fix.html index cedb5a44f1..7006d0a5d4 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/Fix.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/Fix.html @@ -2,10 +2,10 @@ - + Fix - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/FixOf.html b/docs/build/html/api/javadoc/net/corda/core/contracts/FixOf.html index ec6c1abc81..fc2b66132b 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/FixOf.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/FixOf.html @@ -2,10 +2,10 @@ - + FixOf - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/FixableDealState.html b/docs/build/html/api/javadoc/net/corda/core/contracts/FixableDealState.html index ca4decd662..19f0060675 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/FixableDealState.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/FixableDealState.html @@ -2,10 +2,10 @@ - + FixableDealState - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/Frequency.Annual.html b/docs/build/html/api/javadoc/net/corda/core/contracts/Frequency.Annual.html index 651c7462e1..bd5263a6b9 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/Frequency.Annual.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/Frequency.Annual.html @@ -2,10 +2,10 @@ - + Frequency.Annual - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/Frequency.BiWeekly.html b/docs/build/html/api/javadoc/net/corda/core/contracts/Frequency.BiWeekly.html index 3da061cd97..b32c38daa4 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/Frequency.BiWeekly.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/Frequency.BiWeekly.html @@ -2,10 +2,10 @@ - + Frequency.BiWeekly - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/Frequency.Daily.html b/docs/build/html/api/javadoc/net/corda/core/contracts/Frequency.Daily.html index a77c3915fd..7fa798147d 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/Frequency.Daily.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/Frequency.Daily.html @@ -2,10 +2,10 @@ - + Frequency.Daily - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/Frequency.Monthly.html b/docs/build/html/api/javadoc/net/corda/core/contracts/Frequency.Monthly.html index c317268156..8f60a0cfba 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/Frequency.Monthly.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/Frequency.Monthly.html @@ -2,10 +2,10 @@ - + Frequency.Monthly - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/Frequency.Quarterly.html b/docs/build/html/api/javadoc/net/corda/core/contracts/Frequency.Quarterly.html index 0a25b94642..0dce0e9fdd 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/Frequency.Quarterly.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/Frequency.Quarterly.html @@ -2,10 +2,10 @@ - + Frequency.Quarterly - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/Frequency.SemiAnnual.html b/docs/build/html/api/javadoc/net/corda/core/contracts/Frequency.SemiAnnual.html index 688727d4ca..0937d8fc0e 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/Frequency.SemiAnnual.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/Frequency.SemiAnnual.html @@ -2,10 +2,10 @@ - + Frequency.SemiAnnual - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/Frequency.Weekly.html b/docs/build/html/api/javadoc/net/corda/core/contracts/Frequency.Weekly.html index babb8544aa..735e7af22b 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/Frequency.Weekly.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/Frequency.Weekly.html @@ -2,10 +2,10 @@ - + Frequency.Weekly - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/Frequency.html b/docs/build/html/api/javadoc/net/corda/core/contracts/Frequency.html index 59b506cd7e..352a10cf77 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/Frequency.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/Frequency.html @@ -2,10 +2,10 @@ - + Frequency - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/FungibleAsset.Commands.html b/docs/build/html/api/javadoc/net/corda/core/contracts/FungibleAsset.Commands.html index 6e443e31cc..f9ec49314e 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/FungibleAsset.Commands.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/FungibleAsset.Commands.html @@ -2,10 +2,10 @@ - + FungibleAsset.Commands - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/FungibleAsset.html b/docs/build/html/api/javadoc/net/corda/core/contracts/FungibleAsset.html index e32cc627a7..89fd4caa88 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/FungibleAsset.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/FungibleAsset.html @@ -2,10 +2,10 @@ - + FungibleAsset - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/FungibleAssetKt.html b/docs/build/html/api/javadoc/net/corda/core/contracts/FungibleAssetKt.html index 52e7bc2fd6..6fe6ec7032 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/FungibleAssetKt.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/FungibleAssetKt.html @@ -2,10 +2,10 @@ - + FungibleAssetKt - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/General.Builder.html b/docs/build/html/api/javadoc/net/corda/core/contracts/General.Builder.html index 46c9ddd190..6a1ab735d6 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/General.Builder.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/General.Builder.html @@ -2,10 +2,10 @@ - + General.Builder - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/InsufficientBalanceException.html b/docs/build/html/api/javadoc/net/corda/core/contracts/InsufficientBalanceException.html index 375a45ff1e..6797c01f05 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/InsufficientBalanceException.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/InsufficientBalanceException.html @@ -2,10 +2,10 @@ - + InsufficientBalanceException - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/IssuanceDefinition.html b/docs/build/html/api/javadoc/net/corda/core/contracts/IssuanceDefinition.html index a2190f85ed..0526c1b308 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/IssuanceDefinition.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/IssuanceDefinition.html @@ -2,10 +2,10 @@ - + IssuanceDefinition - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/IssueCommand.html b/docs/build/html/api/javadoc/net/corda/core/contracts/IssueCommand.html index 9988853061..8a8c2a639f 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/IssueCommand.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/IssueCommand.html @@ -2,10 +2,10 @@ - + IssueCommand - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/Issued.html b/docs/build/html/api/javadoc/net/corda/core/contracts/Issued.html index 609262c494..9511ac6fb8 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/Issued.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/Issued.html @@ -2,10 +2,10 @@ - + Issued - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/LinearState.ClauseVerifier.html b/docs/build/html/api/javadoc/net/corda/core/contracts/LinearState.ClauseVerifier.html index 4a4672a9a1..f921195b26 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/LinearState.ClauseVerifier.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/LinearState.ClauseVerifier.html @@ -2,10 +2,10 @@ - + LinearState.ClauseVerifier - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/LinearState.html b/docs/build/html/api/javadoc/net/corda/core/contracts/LinearState.html index b1db60475d..7c0ba87ccb 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/LinearState.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/LinearState.html @@ -2,10 +2,10 @@ - + LinearState - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/MoveCommand.html b/docs/build/html/api/javadoc/net/corda/core/contracts/MoveCommand.html index 41fd6fe67d..44a237e4d0 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/MoveCommand.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/MoveCommand.html @@ -2,10 +2,10 @@ - + MoveCommand - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/MultilateralNettableState.html b/docs/build/html/api/javadoc/net/corda/core/contracts/MultilateralNettableState.html index 7d7aeecfa3..9025754979 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/MultilateralNettableState.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/MultilateralNettableState.html @@ -2,10 +2,10 @@ - + MultilateralNettableState - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/NamedByHash.html b/docs/build/html/api/javadoc/net/corda/core/contracts/NamedByHash.html index 074ca31e82..d2cb19ee13 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/NamedByHash.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/NamedByHash.html @@ -2,10 +2,10 @@ - + NamedByHash - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/NetCommand.html b/docs/build/html/api/javadoc/net/corda/core/contracts/NetCommand.html index 0d2f949c27..824c8c6a41 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/NetCommand.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/NetCommand.html @@ -2,10 +2,10 @@ - + NetCommand - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/NetType.html b/docs/build/html/api/javadoc/net/corda/core/contracts/NetType.html index 35381ef94f..80ef5a1371 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/NetType.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/NetType.html @@ -2,10 +2,10 @@ - + NetType - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/NettableState.html b/docs/build/html/api/javadoc/net/corda/core/contracts/NettableState.html index 7a56c079dd..bdb5afa66c 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/NettableState.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/NettableState.html @@ -2,10 +2,10 @@ - + NettableState - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/NotaryChange.Builder.html b/docs/build/html/api/javadoc/net/corda/core/contracts/NotaryChange.Builder.html index 3ba76fe230..f43a149307 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/NotaryChange.Builder.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/NotaryChange.Builder.html @@ -2,10 +2,10 @@ - + NotaryChange.Builder - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/OwnableState.html b/docs/build/html/api/javadoc/net/corda/core/contracts/OwnableState.html index 8956802807..bf7897565b 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/OwnableState.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/OwnableState.html @@ -2,10 +2,10 @@ - + OwnableState - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/PartyAndReference.html b/docs/build/html/api/javadoc/net/corda/core/contracts/PartyAndReference.html index 515077e7de..e2768226d5 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/PartyAndReference.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/PartyAndReference.html @@ -2,10 +2,10 @@ - + PartyAndReference - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/PaymentRule.html b/docs/build/html/api/javadoc/net/corda/core/contracts/PaymentRule.html index 8efc805a87..9fbe931cae 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/PaymentRule.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/PaymentRule.html @@ -2,10 +2,10 @@ - + PaymentRule - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/Requirements.html b/docs/build/html/api/javadoc/net/corda/core/contracts/Requirements.html index 52ee8a1211..fbac4aea2b 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/Requirements.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/Requirements.html @@ -2,10 +2,10 @@ - + Requirements - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/SchedulableState.html b/docs/build/html/api/javadoc/net/corda/core/contracts/SchedulableState.html index 612ed2a6e3..596a22bb2a 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/SchedulableState.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/SchedulableState.html @@ -2,10 +2,10 @@ - + SchedulableState - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/Scheduled.html b/docs/build/html/api/javadoc/net/corda/core/contracts/Scheduled.html index cf11fdae87..e4f60a0885 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/Scheduled.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/Scheduled.html @@ -2,10 +2,10 @@ - + Scheduled - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/ScheduledActivity.html b/docs/build/html/api/javadoc/net/corda/core/contracts/ScheduledActivity.html index 69cabf1884..933c7d1bb0 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/ScheduledActivity.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/ScheduledActivity.html @@ -2,10 +2,10 @@ - + ScheduledActivity - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/ScheduledStateRef.html b/docs/build/html/api/javadoc/net/corda/core/contracts/ScheduledStateRef.html index a3d5bfacc6..6f2b95bd89 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/ScheduledStateRef.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/ScheduledStateRef.html @@ -2,10 +2,10 @@ - + ScheduledStateRef - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/StateAndRef.html b/docs/build/html/api/javadoc/net/corda/core/contracts/StateAndRef.html index cdc1bc0138..02e9559958 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/StateAndRef.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/StateAndRef.html @@ -2,10 +2,10 @@ - + StateAndRef - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/StateRef.html b/docs/build/html/api/javadoc/net/corda/core/contracts/StateRef.html index 10ecdcbc1a..bb82599809 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/StateRef.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/StateRef.html @@ -2,10 +2,10 @@ - + StateRef - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/StructuresKt.html b/docs/build/html/api/javadoc/net/corda/core/contracts/StructuresKt.html index 353243aaee..32a0c91e6d 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/StructuresKt.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/StructuresKt.html @@ -2,10 +2,10 @@ - + StructuresKt - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/Tenor.TimeUnit.html b/docs/build/html/api/javadoc/net/corda/core/contracts/Tenor.TimeUnit.html index 2e2f476e2a..1adf0f40b7 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/Tenor.TimeUnit.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/Tenor.TimeUnit.html @@ -2,10 +2,10 @@ - + Tenor.TimeUnit - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/Tenor.html b/docs/build/html/api/javadoc/net/corda/core/contracts/Tenor.html index 7d88c51bc8..219813b385 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/Tenor.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/Tenor.html @@ -2,10 +2,10 @@ - + Tenor - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/Timestamp.html b/docs/build/html/api/javadoc/net/corda/core/contracts/Timestamp.html index 351a4a84da..a863a69993 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/Timestamp.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/Timestamp.html @@ -2,10 +2,10 @@ - + Timestamp - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionConflictException.html b/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionConflictException.html index 0d3712652c..d438c3630a 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionConflictException.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionConflictException.html @@ -2,10 +2,10 @@ - + TransactionConflictException - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionForContract.InOutGroup.html b/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionForContract.InOutGroup.html index f058caacfe..f1d032f063 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionForContract.InOutGroup.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionForContract.InOutGroup.html @@ -2,10 +2,10 @@ - + TransactionForContract.InOutGroup - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionForContract.html b/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionForContract.html index 05164ba7ed..ee6fb81cf9 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionForContract.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionForContract.html @@ -2,10 +2,10 @@ - + TransactionForContract - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionGraphSearch.Query.html b/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionGraphSearch.Query.html index e5129bb099..f350dba279 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionGraphSearch.Query.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionGraphSearch.Query.html @@ -2,10 +2,10 @@ - + TransactionGraphSearch.Query - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionGraphSearch.html b/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionGraphSearch.html index 5e646510ac..6472fb0333 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionGraphSearch.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionGraphSearch.html @@ -2,10 +2,10 @@ - + TransactionGraphSearch - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionResolutionException.html b/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionResolutionException.html index 7d53a67f2f..8a44668ae5 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionResolutionException.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionResolutionException.html @@ -2,10 +2,10 @@ - + TransactionResolutionException - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionState.html b/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionState.html index 2de6483e9f..570b11c75d 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionState.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionState.html @@ -2,10 +2,10 @@ - + TransactionState - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionType.General.html b/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionType.General.html index 624e6aa8ef..4717abecec 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionType.General.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionType.General.html @@ -2,10 +2,10 @@ - + TransactionType.General - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionType.NotaryChange.html b/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionType.NotaryChange.html index b1ca4be4ab..5f7f4ca8b4 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionType.NotaryChange.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionType.NotaryChange.html @@ -2,10 +2,10 @@ - + TransactionType.NotaryChange - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionType.html b/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionType.html index 0ca30ffe7a..d329fe94bc 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionType.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionType.html @@ -2,10 +2,10 @@ - + TransactionType - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionVerificationException.ContractRejection.html b/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionVerificationException.ContractRejection.html index 855c08b9e2..f53a6ca4eb 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionVerificationException.ContractRejection.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionVerificationException.ContractRejection.html @@ -2,10 +2,10 @@ - + TransactionVerificationException.ContractRejection - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionVerificationException.Direction.html b/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionVerificationException.Direction.html index c20feeaa0c..2abe478180 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionVerificationException.Direction.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionVerificationException.Direction.html @@ -2,10 +2,10 @@ - + TransactionVerificationException.Direction - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionVerificationException.DuplicateInputStates.html b/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionVerificationException.DuplicateInputStates.html index ecbc7db244..57fba3e979 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionVerificationException.DuplicateInputStates.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionVerificationException.DuplicateInputStates.html @@ -2,10 +2,10 @@ - + TransactionVerificationException.DuplicateInputStates - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionVerificationException.InvalidNotaryChange.html b/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionVerificationException.InvalidNotaryChange.html index f7a877dad0..46549ba097 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionVerificationException.InvalidNotaryChange.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionVerificationException.InvalidNotaryChange.html @@ -2,10 +2,10 @@ - + TransactionVerificationException.InvalidNotaryChange - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionVerificationException.MoreThanOneNotary.html b/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionVerificationException.MoreThanOneNotary.html index 89df31402d..3d6917152e 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionVerificationException.MoreThanOneNotary.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionVerificationException.MoreThanOneNotary.html @@ -2,10 +2,10 @@ - + TransactionVerificationException.MoreThanOneNotary - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionVerificationException.NotaryChangeInWrongTransactionType.html b/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionVerificationException.NotaryChangeInWrongTransactionType.html index c50551f0c1..7fd5ca0dbd 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionVerificationException.NotaryChangeInWrongTransactionType.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionVerificationException.NotaryChangeInWrongTransactionType.html @@ -2,10 +2,10 @@ - + TransactionVerificationException.NotaryChangeInWrongTransactionType - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionVerificationException.SignersMissing.html b/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionVerificationException.SignersMissing.html index 667d1a20f4..087a7523be 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionVerificationException.SignersMissing.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionVerificationException.SignersMissing.html @@ -2,10 +2,10 @@ - + TransactionVerificationException.SignersMissing - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionVerificationException.TransactionMissingEncumbranceException.html b/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionVerificationException.TransactionMissingEncumbranceException.html index bb60f10378..d81a832445 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionVerificationException.TransactionMissingEncumbranceException.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionVerificationException.TransactionMissingEncumbranceException.html @@ -2,10 +2,10 @@ - + TransactionVerificationException.TransactionMissingEncumbranceException - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionVerificationException.html b/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionVerificationException.html index 9b5b62b569..590adfe289 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionVerificationException.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/TransactionVerificationException.html @@ -2,10 +2,10 @@ - + TransactionVerificationException - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/TypeOnlyCommandData.html b/docs/build/html/api/javadoc/net/corda/core/contracts/TypeOnlyCommandData.html index 5003fe8d46..a3b45b691a 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/TypeOnlyCommandData.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/TypeOnlyCommandData.html @@ -2,10 +2,10 @@ - + TypeOnlyCommandData - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/UniqueIdentifier.Companion.html b/docs/build/html/api/javadoc/net/corda/core/contracts/UniqueIdentifier.Companion.html index c88dc18917..1f63cc075b 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/UniqueIdentifier.Companion.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/UniqueIdentifier.Companion.html @@ -2,10 +2,10 @@ - + UniqueIdentifier.Companion - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/UniqueIdentifier.html b/docs/build/html/api/javadoc/net/corda/core/contracts/UniqueIdentifier.html index 5b68fcbc5e..eaddccb371 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/UniqueIdentifier.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/UniqueIdentifier.html @@ -2,10 +2,10 @@ - + UniqueIdentifier - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/AllComposition.html b/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/AllComposition.html index 8eadf82c72..2f09e8f367 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/AllComposition.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/AllComposition.html @@ -2,10 +2,10 @@ - + AllComposition - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/AllOf.html b/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/AllOf.html index 91ce5ae6e4..02b3eb5c04 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/AllOf.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/AllOf.html @@ -2,10 +2,10 @@ - + AllOf - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/AnyComposition.html b/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/AnyComposition.html index 3b1072b7c4..a242a1bec6 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/AnyComposition.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/AnyComposition.html @@ -2,10 +2,10 @@ - + AnyComposition - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/AnyOf.html b/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/AnyOf.html index 8c5f634251..896690538f 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/AnyOf.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/AnyOf.html @@ -2,10 +2,10 @@ - + AnyOf - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/Clause.Companion.html b/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/Clause.Companion.html index 42bc88609f..b8b43a96e0 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/Clause.Companion.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/Clause.Companion.html @@ -2,10 +2,10 @@ - + Clause.Companion - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/Clause.html b/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/Clause.html index 169db35f3c..ca9f16900a 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/Clause.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/Clause.html @@ -2,10 +2,10 @@ - + Clause - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/ClauseKt.html b/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/ClauseKt.html index 02d1a7c839..8a20ea88b1 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/ClauseKt.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/ClauseKt.html @@ -2,10 +2,10 @@ - + ClauseKt - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/ClauseVerifier.html b/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/ClauseVerifier.html index bc3f10d9a8..aaa79e331e 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/ClauseVerifier.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/ClauseVerifier.html @@ -2,10 +2,10 @@ - + ClauseVerifier - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/CompositeClause.html b/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/CompositeClause.html index be1fae3bbf..56ff006b28 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/CompositeClause.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/CompositeClause.html @@ -2,10 +2,10 @@ - + CompositeClause - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/FilterOn.html b/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/FilterOn.html index 4644ef8256..03559abdc0 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/FilterOn.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/FilterOn.html @@ -2,10 +2,10 @@ - + FilterOn - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/FirstComposition.Companion.html b/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/FirstComposition.Companion.html index f22e75a9ba..d4449c1e72 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/FirstComposition.Companion.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/FirstComposition.Companion.html @@ -2,10 +2,10 @@ - + FirstComposition.Companion - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/FirstComposition.html b/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/FirstComposition.html index 453d42f3a2..c64487762b 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/FirstComposition.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/FirstComposition.html @@ -2,10 +2,10 @@ - + FirstComposition - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/FirstOf.Companion.html b/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/FirstOf.Companion.html index 4d29f2a280..afdcce9c15 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/FirstOf.Companion.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/FirstOf.Companion.html @@ -2,10 +2,10 @@ - + FirstOf.Companion - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/FirstOf.html b/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/FirstOf.html index 8c2284b00f..bc2ef49206 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/FirstOf.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/FirstOf.html @@ -2,10 +2,10 @@ - + FirstOf - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/GroupClauseVerifier.html b/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/GroupClauseVerifier.html index d254ceaf4d..35db5b915f 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/GroupClauseVerifier.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/GroupClauseVerifier.html @@ -2,10 +2,10 @@ - + GroupClauseVerifier - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/package-frame.html b/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/package-frame.html index 7079cf076c..4219b353e7 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/package-frame.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/package-frame.html @@ -2,10 +2,10 @@ - + net.corda.core.contracts.clauses - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/package-summary.html b/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/package-summary.html index aa0664693d..e1512d083d 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/package-summary.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/package-summary.html @@ -2,10 +2,10 @@ - + net.corda.core.contracts.clauses - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/package-tree.html b/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/package-tree.html index 7505ec6b62..c922396e89 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/package-tree.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/clauses/package-tree.html @@ -2,10 +2,10 @@ - + net.corda.core.contracts.clauses Class Hierarchy - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/package-frame.html b/docs/build/html/api/javadoc/net/corda/core/contracts/package-frame.html index 6e656eb991..fb282c02b7 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/package-frame.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/package-frame.html @@ -2,10 +2,10 @@ - + net.corda.core.contracts - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/package-summary.html b/docs/build/html/api/javadoc/net/corda/core/contracts/package-summary.html index ede92b9186..b4f1a05e0b 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/package-summary.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/package-summary.html @@ -2,10 +2,10 @@ - + net.corda.core.contracts - + diff --git a/docs/build/html/api/javadoc/net/corda/core/contracts/package-tree.html b/docs/build/html/api/javadoc/net/corda/core/contracts/package-tree.html index b03161e454..01dd869137 100644 --- a/docs/build/html/api/javadoc/net/corda/core/contracts/package-tree.html +++ b/docs/build/html/api/javadoc/net/corda/core/contracts/package-tree.html @@ -2,10 +2,10 @@ - + net.corda.core.contracts Class Hierarchy - + @@ -142,8 +142,8 @@
  • net.corda.core.contracts.Command
  • net.corda.core.contracts.BusinessCalendar
  • net.corda.core.contracts.StructuresKt
  • -
  • net.corda.core.contracts.Tenor
  • net.corda.core.contracts.TransactionState<T>
  • +
  • net.corda.core.contracts.Tenor
  • net.corda.core.contracts.DummyContractKt
  • net.corda.core.contracts.DummyContract.Companion
  • net.corda.core.contracts.Frequency.BiWeekly
  • diff --git a/docs/build/html/api/javadoc/net/corda/core/crypto/CertificateStream.html b/docs/build/html/api/javadoc/net/corda/core/crypto/CertificateStream.html index 90ad4e9608..a7305520ff 100644 --- a/docs/build/html/api/javadoc/net/corda/core/crypto/CertificateStream.html +++ b/docs/build/html/api/javadoc/net/corda/core/crypto/CertificateStream.html @@ -2,10 +2,10 @@ - + CertificateStream - + diff --git a/docs/build/html/api/javadoc/net/corda/core/crypto/CompositeKey.Builder.html b/docs/build/html/api/javadoc/net/corda/core/crypto/CompositeKey.Builder.html index 476839ec59..aa3dc59756 100644 --- a/docs/build/html/api/javadoc/net/corda/core/crypto/CompositeKey.Builder.html +++ b/docs/build/html/api/javadoc/net/corda/core/crypto/CompositeKey.Builder.html @@ -2,10 +2,10 @@ - + CompositeKey.Builder - + diff --git a/docs/build/html/api/javadoc/net/corda/core/crypto/CompositeKey.Companion.html b/docs/build/html/api/javadoc/net/corda/core/crypto/CompositeKey.Companion.html index 036b555a0f..173c18044f 100644 --- a/docs/build/html/api/javadoc/net/corda/core/crypto/CompositeKey.Companion.html +++ b/docs/build/html/api/javadoc/net/corda/core/crypto/CompositeKey.Companion.html @@ -2,10 +2,10 @@ - + CompositeKey.Companion - + @@ -130,7 +130,7 @@ var activeTableTab = "activeTableTab"; Method and Description -CompositeKey +NonExistentClass parseFromBase58(java.lang.String encoded)  @@ -154,7 +154,7 @@ var activeTableTab = "activeTableTab";
    • parseFromBase58

      -
      public CompositeKey parseFromBase58(java.lang.String encoded)
      +
      public NonExistentClass parseFromBase58(java.lang.String encoded)
    diff --git a/docs/build/html/api/javadoc/net/corda/core/crypto/CompositeKey.Leaf.html b/docs/build/html/api/javadoc/net/corda/core/crypto/CompositeKey.Leaf.html index 9fe459629d..2d3684476b 100644 --- a/docs/build/html/api/javadoc/net/corda/core/crypto/CompositeKey.Leaf.html +++ b/docs/build/html/api/javadoc/net/corda/core/crypto/CompositeKey.Leaf.html @@ -2,10 +2,10 @@ - + CompositeKey.Leaf - + diff --git a/docs/build/html/api/javadoc/net/corda/core/crypto/CompositeKey.Node.html b/docs/build/html/api/javadoc/net/corda/core/crypto/CompositeKey.Node.html index 331e4cd53c..0f3d983d8b 100644 --- a/docs/build/html/api/javadoc/net/corda/core/crypto/CompositeKey.Node.html +++ b/docs/build/html/api/javadoc/net/corda/core/crypto/CompositeKey.Node.html @@ -2,10 +2,10 @@ - + CompositeKey.Node - + diff --git a/docs/build/html/api/javadoc/net/corda/core/crypto/CompositeKey.html b/docs/build/html/api/javadoc/net/corda/core/crypto/CompositeKey.html index e53e8e9295..176fdf856d 100644 --- a/docs/build/html/api/javadoc/net/corda/core/crypto/CompositeKey.html +++ b/docs/build/html/api/javadoc/net/corda/core/crypto/CompositeKey.html @@ -2,10 +2,10 @@ - + CompositeKey - + diff --git a/docs/build/html/api/javadoc/net/corda/core/crypto/CompositeKeyKt.html b/docs/build/html/api/javadoc/net/corda/core/crypto/CompositeKeyKt.html index 86270b1298..ad6642eabd 100644 --- a/docs/build/html/api/javadoc/net/corda/core/crypto/CompositeKeyKt.html +++ b/docs/build/html/api/javadoc/net/corda/core/crypto/CompositeKeyKt.html @@ -2,10 +2,10 @@ - + CompositeKeyKt - + diff --git a/docs/build/html/api/javadoc/net/corda/core/crypto/CryptoUtilities.html b/docs/build/html/api/javadoc/net/corda/core/crypto/CryptoUtilities.html index 69ca71985e..409a5689e8 100644 --- a/docs/build/html/api/javadoc/net/corda/core/crypto/CryptoUtilities.html +++ b/docs/build/html/api/javadoc/net/corda/core/crypto/CryptoUtilities.html @@ -2,10 +2,10 @@ - + CryptoUtilities - + @@ -184,7 +184,7 @@ you want hard-coded private keys. newSecureRandom()  -static net.i2p.crypto.eddsa.EdDSAPublicKey +static NonExistentClass parsePublicKeyBase58(java.lang.String base58String)  @@ -223,7 +223,7 @@ you want hard-coded private keys. Party party)
      -static java.lang.String +static NonExistentClass toBase58String(java.security.PublicKey $receiver)  @@ -310,7 +310,7 @@ you want hard-coded private keys.
    • parsePublicKeyBase58

      -
      public static net.i2p.crypto.eddsa.EdDSAPublicKey parsePublicKeyBase58(java.lang.String base58String)
      +
      public static NonExistentClass parsePublicKeyBase58(java.lang.String base58String)
    @@ -319,7 +319,7 @@ you want hard-coded private keys.
    • toBase58String

      -
      public static java.lang.String toBase58String(java.security.PublicKey $receiver)
      +
      public static NonExistentClass toBase58String(java.security.PublicKey $receiver)
    diff --git a/docs/build/html/api/javadoc/net/corda/core/crypto/DigitalSignature.LegallyIdentifiable.html b/docs/build/html/api/javadoc/net/corda/core/crypto/DigitalSignature.LegallyIdentifiable.html index 6596f96894..73ded1b8cc 100644 --- a/docs/build/html/api/javadoc/net/corda/core/crypto/DigitalSignature.LegallyIdentifiable.html +++ b/docs/build/html/api/javadoc/net/corda/core/crypto/DigitalSignature.LegallyIdentifiable.html @@ -2,10 +2,10 @@ - + DigitalSignature.LegallyIdentifiable - + diff --git a/docs/build/html/api/javadoc/net/corda/core/crypto/DigitalSignature.WithKey.html b/docs/build/html/api/javadoc/net/corda/core/crypto/DigitalSignature.WithKey.html index 403ea0b849..d9c19971ce 100644 --- a/docs/build/html/api/javadoc/net/corda/core/crypto/DigitalSignature.WithKey.html +++ b/docs/build/html/api/javadoc/net/corda/core/crypto/DigitalSignature.WithKey.html @@ -2,10 +2,10 @@ - + DigitalSignature.WithKey - + diff --git a/docs/build/html/api/javadoc/net/corda/core/crypto/DigitalSignature.html b/docs/build/html/api/javadoc/net/corda/core/crypto/DigitalSignature.html index 030728f2e4..84f8e8d23f 100644 --- a/docs/build/html/api/javadoc/net/corda/core/crypto/DigitalSignature.html +++ b/docs/build/html/api/javadoc/net/corda/core/crypto/DigitalSignature.html @@ -2,10 +2,10 @@ - + DigitalSignature - + diff --git a/docs/build/html/api/javadoc/net/corda/core/crypto/DummyPublicKey.html b/docs/build/html/api/javadoc/net/corda/core/crypto/DummyPublicKey.html index e73d4aa270..1c7368a6ec 100644 --- a/docs/build/html/api/javadoc/net/corda/core/crypto/DummyPublicKey.html +++ b/docs/build/html/api/javadoc/net/corda/core/crypto/DummyPublicKey.html @@ -2,10 +2,10 @@ - + DummyPublicKey - + diff --git a/docs/build/html/api/javadoc/net/corda/core/crypto/MerkleTreeException.html b/docs/build/html/api/javadoc/net/corda/core/crypto/MerkleTreeException.html index d65c1a9b95..a11e51039e 100644 --- a/docs/build/html/api/javadoc/net/corda/core/crypto/MerkleTreeException.html +++ b/docs/build/html/api/javadoc/net/corda/core/crypto/MerkleTreeException.html @@ -2,10 +2,10 @@ - + MerkleTreeException - + diff --git a/docs/build/html/api/javadoc/net/corda/core/crypto/NullPublicKey.html b/docs/build/html/api/javadoc/net/corda/core/crypto/NullPublicKey.html index 2a43d2a949..5e29e4cf3c 100644 --- a/docs/build/html/api/javadoc/net/corda/core/crypto/NullPublicKey.html +++ b/docs/build/html/api/javadoc/net/corda/core/crypto/NullPublicKey.html @@ -2,10 +2,10 @@ - + NullPublicKey - + diff --git a/docs/build/html/api/javadoc/net/corda/core/crypto/NullSignature.html b/docs/build/html/api/javadoc/net/corda/core/crypto/NullSignature.html index 900ee26c7e..ae030ff8e4 100644 --- a/docs/build/html/api/javadoc/net/corda/core/crypto/NullSignature.html +++ b/docs/build/html/api/javadoc/net/corda/core/crypto/NullSignature.html @@ -2,10 +2,10 @@ - + NullSignature - + diff --git a/docs/build/html/api/javadoc/net/corda/core/crypto/PartialMerkleTree.Companion.html b/docs/build/html/api/javadoc/net/corda/core/crypto/PartialMerkleTree.Companion.html index ae846d956f..27d0862482 100644 --- a/docs/build/html/api/javadoc/net/corda/core/crypto/PartialMerkleTree.Companion.html +++ b/docs/build/html/api/javadoc/net/corda/core/crypto/PartialMerkleTree.Companion.html @@ -2,10 +2,10 @@ - + PartialMerkleTree.Companion - + diff --git a/docs/build/html/api/javadoc/net/corda/core/crypto/PartialMerkleTree.PartialTree.html b/docs/build/html/api/javadoc/net/corda/core/crypto/PartialMerkleTree.PartialTree.html index 9cbd47457a..9917e929e2 100644 --- a/docs/build/html/api/javadoc/net/corda/core/crypto/PartialMerkleTree.PartialTree.html +++ b/docs/build/html/api/javadoc/net/corda/core/crypto/PartialMerkleTree.PartialTree.html @@ -2,10 +2,10 @@ - + PartialMerkleTree.PartialTree - + diff --git a/docs/build/html/api/javadoc/net/corda/core/crypto/PartialMerkleTree.html b/docs/build/html/api/javadoc/net/corda/core/crypto/PartialMerkleTree.html index ee416d9d61..d385143d3e 100644 --- a/docs/build/html/api/javadoc/net/corda/core/crypto/PartialMerkleTree.html +++ b/docs/build/html/api/javadoc/net/corda/core/crypto/PartialMerkleTree.html @@ -2,10 +2,10 @@ - + PartialMerkleTree - + diff --git a/docs/build/html/api/javadoc/net/corda/core/crypto/PartialTree.IncludedLeaf.html b/docs/build/html/api/javadoc/net/corda/core/crypto/PartialTree.IncludedLeaf.html index 20a4264a2d..0a7961cce7 100644 --- a/docs/build/html/api/javadoc/net/corda/core/crypto/PartialTree.IncludedLeaf.html +++ b/docs/build/html/api/javadoc/net/corda/core/crypto/PartialTree.IncludedLeaf.html @@ -2,10 +2,10 @@ - + PartialTree.IncludedLeaf - + diff --git a/docs/build/html/api/javadoc/net/corda/core/crypto/PartialTree.Leaf.html b/docs/build/html/api/javadoc/net/corda/core/crypto/PartialTree.Leaf.html index 9f7c5c3a08..82a17bd378 100644 --- a/docs/build/html/api/javadoc/net/corda/core/crypto/PartialTree.Leaf.html +++ b/docs/build/html/api/javadoc/net/corda/core/crypto/PartialTree.Leaf.html @@ -2,10 +2,10 @@ - + PartialTree.Leaf - + diff --git a/docs/build/html/api/javadoc/net/corda/core/crypto/PartialTree.Node.html b/docs/build/html/api/javadoc/net/corda/core/crypto/PartialTree.Node.html index 83fdc7f5b4..1d3a0736b3 100644 --- a/docs/build/html/api/javadoc/net/corda/core/crypto/PartialTree.Node.html +++ b/docs/build/html/api/javadoc/net/corda/core/crypto/PartialTree.Node.html @@ -2,10 +2,10 @@ - + PartialTree.Node - + diff --git a/docs/build/html/api/javadoc/net/corda/core/crypto/Party.html b/docs/build/html/api/javadoc/net/corda/core/crypto/Party.html index 32c2f3f6b2..137f5911ce 100644 --- a/docs/build/html/api/javadoc/net/corda/core/crypto/Party.html +++ b/docs/build/html/api/javadoc/net/corda/core/crypto/Party.html @@ -2,10 +2,10 @@ - + Party - + diff --git a/docs/build/html/api/javadoc/net/corda/core/crypto/SecureHash.Companion.html b/docs/build/html/api/javadoc/net/corda/core/crypto/SecureHash.Companion.html index 36ad024d62..ab53d41a1a 100644 --- a/docs/build/html/api/javadoc/net/corda/core/crypto/SecureHash.Companion.html +++ b/docs/build/html/api/javadoc/net/corda/core/crypto/SecureHash.Companion.html @@ -2,10 +2,10 @@ - + SecureHash.Companion - + diff --git a/docs/build/html/api/javadoc/net/corda/core/crypto/SecureHash.SHA256.html b/docs/build/html/api/javadoc/net/corda/core/crypto/SecureHash.SHA256.html index 7bf9fe5a41..5b78b8b243 100644 --- a/docs/build/html/api/javadoc/net/corda/core/crypto/SecureHash.SHA256.html +++ b/docs/build/html/api/javadoc/net/corda/core/crypto/SecureHash.SHA256.html @@ -2,10 +2,10 @@ - + SecureHash.SHA256 - + diff --git a/docs/build/html/api/javadoc/net/corda/core/crypto/SecureHash.html b/docs/build/html/api/javadoc/net/corda/core/crypto/SecureHash.html index 28d4684f69..237f87b55c 100644 --- a/docs/build/html/api/javadoc/net/corda/core/crypto/SecureHash.html +++ b/docs/build/html/api/javadoc/net/corda/core/crypto/SecureHash.html @@ -2,10 +2,10 @@ - + SecureHash - + diff --git a/docs/build/html/api/javadoc/net/corda/core/crypto/SecureHashKt.html b/docs/build/html/api/javadoc/net/corda/core/crypto/SecureHashKt.html index 780bbd0225..87ef19b617 100644 --- a/docs/build/html/api/javadoc/net/corda/core/crypto/SecureHashKt.html +++ b/docs/build/html/api/javadoc/net/corda/core/crypto/SecureHashKt.html @@ -2,10 +2,10 @@ - + SecureHashKt - + diff --git a/docs/build/html/api/javadoc/net/corda/core/crypto/SignedData.html b/docs/build/html/api/javadoc/net/corda/core/crypto/SignedData.html index 30bb0872e0..4b9aa544dc 100644 --- a/docs/build/html/api/javadoc/net/corda/core/crypto/SignedData.html +++ b/docs/build/html/api/javadoc/net/corda/core/crypto/SignedData.html @@ -2,10 +2,10 @@ - + SignedData - + diff --git a/docs/build/html/api/javadoc/net/corda/core/crypto/X509Utilities.CACertAndKey.html b/docs/build/html/api/javadoc/net/corda/core/crypto/X509Utilities.CACertAndKey.html index 0b2aecdb55..91ef3f0efa 100644 --- a/docs/build/html/api/javadoc/net/corda/core/crypto/X509Utilities.CACertAndKey.html +++ b/docs/build/html/api/javadoc/net/corda/core/crypto/X509Utilities.CACertAndKey.html @@ -2,10 +2,10 @@ - + X509Utilities.CACertAndKey - + diff --git a/docs/build/html/api/javadoc/net/corda/core/crypto/X509Utilities.html b/docs/build/html/api/javadoc/net/corda/core/crypto/X509Utilities.html index 5cac1c1acf..4756ee16b3 100644 --- a/docs/build/html/api/javadoc/net/corda/core/crypto/X509Utilities.html +++ b/docs/build/html/api/javadoc/net/corda/core/crypto/X509Utilities.html @@ -2,10 +2,10 @@ - + X509Utilities - + diff --git a/docs/build/html/api/javadoc/net/corda/core/crypto/X509UtilitiesKt.html b/docs/build/html/api/javadoc/net/corda/core/crypto/X509UtilitiesKt.html index 913364cc2f..07eee79170 100644 --- a/docs/build/html/api/javadoc/net/corda/core/crypto/X509UtilitiesKt.html +++ b/docs/build/html/api/javadoc/net/corda/core/crypto/X509UtilitiesKt.html @@ -2,10 +2,10 @@ - + X509UtilitiesKt - + diff --git a/docs/build/html/api/javadoc/net/corda/core/crypto/package-frame.html b/docs/build/html/api/javadoc/net/corda/core/crypto/package-frame.html index 9ee4b53f2f..7d37b008a3 100644 --- a/docs/build/html/api/javadoc/net/corda/core/crypto/package-frame.html +++ b/docs/build/html/api/javadoc/net/corda/core/crypto/package-frame.html @@ -2,10 +2,10 @@ - + net.corda.core.crypto - + diff --git a/docs/build/html/api/javadoc/net/corda/core/crypto/package-summary.html b/docs/build/html/api/javadoc/net/corda/core/crypto/package-summary.html index 3422ab9b38..22cad8e338 100644 --- a/docs/build/html/api/javadoc/net/corda/core/crypto/package-summary.html +++ b/docs/build/html/api/javadoc/net/corda/core/crypto/package-summary.html @@ -2,10 +2,10 @@ - + net.corda.core.crypto - + diff --git a/docs/build/html/api/javadoc/net/corda/core/crypto/package-tree.html b/docs/build/html/api/javadoc/net/corda/core/crypto/package-tree.html index 0a28fff8a6..72a1cbd121 100644 --- a/docs/build/html/api/javadoc/net/corda/core/crypto/package-tree.html +++ b/docs/build/html/api/javadoc/net/corda/core/crypto/package-tree.html @@ -2,10 +2,10 @@ - + net.corda.core.crypto Class Hierarchy - + @@ -98,6 +98,7 @@
  • net.corda.core.crypto.SecureHashKt
  • net.corda.core.crypto.PartialMerkleTree.Companion
  • net.corda.core.crypto.CompositeKey.Companion
  • +
  • net.corda.core.crypto.Party
  • net.corda.core.serialization.OpaqueBytes
  • -
  • net.corda.core.crypto.Party
  • net.corda.core.crypto.SignedData<T>
  • net.corda.core.crypto.X509UtilitiesKt
  • -
  • net.corda.core.crypto.NullPublicKey
  • net.corda.core.crypto.SecureHash.Companion
  • +
  • net.corda.core.crypto.NullPublicKey
  • net.corda.core.crypto.PartialMerkleTree
  • net.corda.core.crypto.CompositeKey.Builder
  • net.corda.core.crypto.CryptoUtilities
  • diff --git a/docs/build/html/api/javadoc/net/corda/core/flows/AppContext.html b/docs/build/html/api/javadoc/net/corda/core/flows/AppContext.html index 1a9e4b52cd..6af7d6830d 100644 --- a/docs/build/html/api/javadoc/net/corda/core/flows/AppContext.html +++ b/docs/build/html/api/javadoc/net/corda/core/flows/AppContext.html @@ -2,10 +2,10 @@ - + AppContext - + diff --git a/docs/build/html/api/javadoc/net/corda/core/flows/FlowException.html b/docs/build/html/api/javadoc/net/corda/core/flows/FlowException.html index de00a4246e..76079037fa 100644 --- a/docs/build/html/api/javadoc/net/corda/core/flows/FlowException.html +++ b/docs/build/html/api/javadoc/net/corda/core/flows/FlowException.html @@ -2,10 +2,10 @@ - + FlowException - + diff --git a/docs/build/html/api/javadoc/net/corda/core/flows/FlowLogic.html b/docs/build/html/api/javadoc/net/corda/core/flows/FlowLogic.html index 80d8a306f3..be72df8a3b 100644 --- a/docs/build/html/api/javadoc/net/corda/core/flows/FlowLogic.html +++ b/docs/build/html/api/javadoc/net/corda/core/flows/FlowLogic.html @@ -2,10 +2,10 @@ - + FlowLogic - + diff --git a/docs/build/html/api/javadoc/net/corda/core/flows/FlowLogicRef.html b/docs/build/html/api/javadoc/net/corda/core/flows/FlowLogicRef.html index 0136a41b7b..97b08a6b58 100644 --- a/docs/build/html/api/javadoc/net/corda/core/flows/FlowLogicRef.html +++ b/docs/build/html/api/javadoc/net/corda/core/flows/FlowLogicRef.html @@ -2,10 +2,10 @@ - + FlowLogicRef - + diff --git a/docs/build/html/api/javadoc/net/corda/core/flows/FlowLogicRefFactory.html b/docs/build/html/api/javadoc/net/corda/core/flows/FlowLogicRefFactory.html index c07ffd1e57..f40123479f 100644 --- a/docs/build/html/api/javadoc/net/corda/core/flows/FlowLogicRefFactory.html +++ b/docs/build/html/api/javadoc/net/corda/core/flows/FlowLogicRefFactory.html @@ -2,10 +2,10 @@ - + FlowLogicRefFactory - + diff --git a/docs/build/html/api/javadoc/net/corda/core/flows/FlowStateMachine.html b/docs/build/html/api/javadoc/net/corda/core/flows/FlowStateMachine.html index 3e8c091197..0f2846eb8a 100644 --- a/docs/build/html/api/javadoc/net/corda/core/flows/FlowStateMachine.html +++ b/docs/build/html/api/javadoc/net/corda/core/flows/FlowStateMachine.html @@ -2,10 +2,10 @@ - + FlowStateMachine - + diff --git a/docs/build/html/api/javadoc/net/corda/core/flows/IllegalFlowLogicException.html b/docs/build/html/api/javadoc/net/corda/core/flows/IllegalFlowLogicException.html index ea7eb1cc91..18c69a5ceb 100644 --- a/docs/build/html/api/javadoc/net/corda/core/flows/IllegalFlowLogicException.html +++ b/docs/build/html/api/javadoc/net/corda/core/flows/IllegalFlowLogicException.html @@ -2,10 +2,10 @@ - + IllegalFlowLogicException - + diff --git a/docs/build/html/api/javadoc/net/corda/core/flows/StateMachineRunId.Companion.html b/docs/build/html/api/javadoc/net/corda/core/flows/StateMachineRunId.Companion.html index 48682877cb..af82b053cb 100644 --- a/docs/build/html/api/javadoc/net/corda/core/flows/StateMachineRunId.Companion.html +++ b/docs/build/html/api/javadoc/net/corda/core/flows/StateMachineRunId.Companion.html @@ -2,10 +2,10 @@ - + StateMachineRunId.Companion - + diff --git a/docs/build/html/api/javadoc/net/corda/core/flows/StateMachineRunId.html b/docs/build/html/api/javadoc/net/corda/core/flows/StateMachineRunId.html index 0bbeb51dc5..a896c5d5a3 100644 --- a/docs/build/html/api/javadoc/net/corda/core/flows/StateMachineRunId.html +++ b/docs/build/html/api/javadoc/net/corda/core/flows/StateMachineRunId.html @@ -2,10 +2,10 @@ - + StateMachineRunId - + diff --git a/docs/build/html/api/javadoc/net/corda/core/flows/package-frame.html b/docs/build/html/api/javadoc/net/corda/core/flows/package-frame.html index a76956fb53..f280c3d747 100644 --- a/docs/build/html/api/javadoc/net/corda/core/flows/package-frame.html +++ b/docs/build/html/api/javadoc/net/corda/core/flows/package-frame.html @@ -2,10 +2,10 @@ - + net.corda.core.flows - + diff --git a/docs/build/html/api/javadoc/net/corda/core/flows/package-summary.html b/docs/build/html/api/javadoc/net/corda/core/flows/package-summary.html index 0c04845fbd..b9545e7ba1 100644 --- a/docs/build/html/api/javadoc/net/corda/core/flows/package-summary.html +++ b/docs/build/html/api/javadoc/net/corda/core/flows/package-summary.html @@ -2,10 +2,10 @@ - + net.corda.core.flows - + diff --git a/docs/build/html/api/javadoc/net/corda/core/flows/package-tree.html b/docs/build/html/api/javadoc/net/corda/core/flows/package-tree.html index 2960766f14..345663e5db 100644 --- a/docs/build/html/api/javadoc/net/corda/core/flows/package-tree.html +++ b/docs/build/html/api/javadoc/net/corda/core/flows/package-tree.html @@ -2,10 +2,10 @@ - + net.corda.core.flows Class Hierarchy - + diff --git a/docs/build/html/api/javadoc/net/corda/core/math/CubicSplineInterpolator.Factory.html b/docs/build/html/api/javadoc/net/corda/core/math/CubicSplineInterpolator.Factory.html index 86eeb906fa..fcef976977 100644 --- a/docs/build/html/api/javadoc/net/corda/core/math/CubicSplineInterpolator.Factory.html +++ b/docs/build/html/api/javadoc/net/corda/core/math/CubicSplineInterpolator.Factory.html @@ -2,10 +2,10 @@ - + CubicSplineInterpolator.Factory - + diff --git a/docs/build/html/api/javadoc/net/corda/core/math/CubicSplineInterpolator.html b/docs/build/html/api/javadoc/net/corda/core/math/CubicSplineInterpolator.html index 5a0c772b80..953d4fd2f3 100644 --- a/docs/build/html/api/javadoc/net/corda/core/math/CubicSplineInterpolator.html +++ b/docs/build/html/api/javadoc/net/corda/core/math/CubicSplineInterpolator.html @@ -2,10 +2,10 @@ - + CubicSplineInterpolator - + diff --git a/docs/build/html/api/javadoc/net/corda/core/math/Interpolator.html b/docs/build/html/api/javadoc/net/corda/core/math/Interpolator.html index bf4ee93bf1..027d314fb8 100644 --- a/docs/build/html/api/javadoc/net/corda/core/math/Interpolator.html +++ b/docs/build/html/api/javadoc/net/corda/core/math/Interpolator.html @@ -2,10 +2,10 @@ - + Interpolator - + diff --git a/docs/build/html/api/javadoc/net/corda/core/math/InterpolatorFactory.html b/docs/build/html/api/javadoc/net/corda/core/math/InterpolatorFactory.html index ba1c952c53..d338d39dbb 100644 --- a/docs/build/html/api/javadoc/net/corda/core/math/InterpolatorFactory.html +++ b/docs/build/html/api/javadoc/net/corda/core/math/InterpolatorFactory.html @@ -2,10 +2,10 @@ - + InterpolatorFactory - + diff --git a/docs/build/html/api/javadoc/net/corda/core/math/LinearInterpolator.Factory.html b/docs/build/html/api/javadoc/net/corda/core/math/LinearInterpolator.Factory.html index 38244b2209..5873795116 100644 --- a/docs/build/html/api/javadoc/net/corda/core/math/LinearInterpolator.Factory.html +++ b/docs/build/html/api/javadoc/net/corda/core/math/LinearInterpolator.Factory.html @@ -2,10 +2,10 @@ - + LinearInterpolator.Factory - + diff --git a/docs/build/html/api/javadoc/net/corda/core/math/LinearInterpolator.html b/docs/build/html/api/javadoc/net/corda/core/math/LinearInterpolator.html index 0218aafcc9..d6b2c56024 100644 --- a/docs/build/html/api/javadoc/net/corda/core/math/LinearInterpolator.html +++ b/docs/build/html/api/javadoc/net/corda/core/math/LinearInterpolator.html @@ -2,10 +2,10 @@ - + LinearInterpolator - + diff --git a/docs/build/html/api/javadoc/net/corda/core/math/Polynomial.html b/docs/build/html/api/javadoc/net/corda/core/math/Polynomial.html index f507125390..74a2baec53 100644 --- a/docs/build/html/api/javadoc/net/corda/core/math/Polynomial.html +++ b/docs/build/html/api/javadoc/net/corda/core/math/Polynomial.html @@ -2,10 +2,10 @@ - + Polynomial - + diff --git a/docs/build/html/api/javadoc/net/corda/core/math/SplineFunction.html b/docs/build/html/api/javadoc/net/corda/core/math/SplineFunction.html index 8e40bdb9c7..235888b406 100644 --- a/docs/build/html/api/javadoc/net/corda/core/math/SplineFunction.html +++ b/docs/build/html/api/javadoc/net/corda/core/math/SplineFunction.html @@ -2,10 +2,10 @@ - + SplineFunction - + diff --git a/docs/build/html/api/javadoc/net/corda/core/math/package-frame.html b/docs/build/html/api/javadoc/net/corda/core/math/package-frame.html index 1a36bebe46..28164f4aea 100644 --- a/docs/build/html/api/javadoc/net/corda/core/math/package-frame.html +++ b/docs/build/html/api/javadoc/net/corda/core/math/package-frame.html @@ -2,10 +2,10 @@ - + net.corda.core.math - + diff --git a/docs/build/html/api/javadoc/net/corda/core/math/package-summary.html b/docs/build/html/api/javadoc/net/corda/core/math/package-summary.html index 695a952573..466f986f69 100644 --- a/docs/build/html/api/javadoc/net/corda/core/math/package-summary.html +++ b/docs/build/html/api/javadoc/net/corda/core/math/package-summary.html @@ -2,10 +2,10 @@ - + net.corda.core.math - + diff --git a/docs/build/html/api/javadoc/net/corda/core/math/package-tree.html b/docs/build/html/api/javadoc/net/corda/core/math/package-tree.html index 6c7613d16f..8cf8583ae4 100644 --- a/docs/build/html/api/javadoc/net/corda/core/math/package-tree.html +++ b/docs/build/html/api/javadoc/net/corda/core/math/package-tree.html @@ -2,10 +2,10 @@ - + net.corda.core.math Class Hierarchy - + diff --git a/docs/build/html/api/javadoc/net/corda/core/messaging/Ack.html b/docs/build/html/api/javadoc/net/corda/core/messaging/Ack.html index 3974d95383..4ac03ae9ab 100644 --- a/docs/build/html/api/javadoc/net/corda/core/messaging/Ack.html +++ b/docs/build/html/api/javadoc/net/corda/core/messaging/Ack.html @@ -2,10 +2,10 @@ - + Ack - + diff --git a/docs/build/html/api/javadoc/net/corda/core/messaging/AllPossibleRecipients.html b/docs/build/html/api/javadoc/net/corda/core/messaging/AllPossibleRecipients.html index 4372cc7f9e..1710ea624e 100644 --- a/docs/build/html/api/javadoc/net/corda/core/messaging/AllPossibleRecipients.html +++ b/docs/build/html/api/javadoc/net/corda/core/messaging/AllPossibleRecipients.html @@ -2,10 +2,10 @@ - + AllPossibleRecipients - + diff --git a/docs/build/html/api/javadoc/net/corda/core/messaging/CordaRPCOps.html b/docs/build/html/api/javadoc/net/corda/core/messaging/CordaRPCOps.html index 9155aeb908..8f76c67ea9 100644 --- a/docs/build/html/api/javadoc/net/corda/core/messaging/CordaRPCOps.html +++ b/docs/build/html/api/javadoc/net/corda/core/messaging/CordaRPCOps.html @@ -2,10 +2,10 @@ - + CordaRPCOps - + diff --git a/docs/build/html/api/javadoc/net/corda/core/messaging/CordaRPCOpsKt.html b/docs/build/html/api/javadoc/net/corda/core/messaging/CordaRPCOpsKt.html index 638cfe30a9..c3e484210c 100644 --- a/docs/build/html/api/javadoc/net/corda/core/messaging/CordaRPCOpsKt.html +++ b/docs/build/html/api/javadoc/net/corda/core/messaging/CordaRPCOpsKt.html @@ -2,10 +2,10 @@ - + CordaRPCOpsKt - + diff --git a/docs/build/html/api/javadoc/net/corda/core/messaging/FlowHandle.html b/docs/build/html/api/javadoc/net/corda/core/messaging/FlowHandle.html index e370917ad8..efcc715d93 100644 --- a/docs/build/html/api/javadoc/net/corda/core/messaging/FlowHandle.html +++ b/docs/build/html/api/javadoc/net/corda/core/messaging/FlowHandle.html @@ -2,10 +2,10 @@ - + FlowHandle - + diff --git a/docs/build/html/api/javadoc/net/corda/core/messaging/Message.html b/docs/build/html/api/javadoc/net/corda/core/messaging/Message.html index 8ef32ef047..4a291de3dc 100644 --- a/docs/build/html/api/javadoc/net/corda/core/messaging/Message.html +++ b/docs/build/html/api/javadoc/net/corda/core/messaging/Message.html @@ -2,10 +2,10 @@ - + Message - + diff --git a/docs/build/html/api/javadoc/net/corda/core/messaging/MessageHandlerRegistration.html b/docs/build/html/api/javadoc/net/corda/core/messaging/MessageHandlerRegistration.html index 99883b01b6..71efc088bb 100644 --- a/docs/build/html/api/javadoc/net/corda/core/messaging/MessageHandlerRegistration.html +++ b/docs/build/html/api/javadoc/net/corda/core/messaging/MessageHandlerRegistration.html @@ -2,10 +2,10 @@ - + MessageHandlerRegistration - + diff --git a/docs/build/html/api/javadoc/net/corda/core/messaging/MessageRecipientGroup.html b/docs/build/html/api/javadoc/net/corda/core/messaging/MessageRecipientGroup.html index cc5353c6f4..bfef12d032 100644 --- a/docs/build/html/api/javadoc/net/corda/core/messaging/MessageRecipientGroup.html +++ b/docs/build/html/api/javadoc/net/corda/core/messaging/MessageRecipientGroup.html @@ -2,10 +2,10 @@ - + MessageRecipientGroup - + diff --git a/docs/build/html/api/javadoc/net/corda/core/messaging/MessageRecipients.html b/docs/build/html/api/javadoc/net/corda/core/messaging/MessageRecipients.html index 5d9d077127..b482fc7441 100644 --- a/docs/build/html/api/javadoc/net/corda/core/messaging/MessageRecipients.html +++ b/docs/build/html/api/javadoc/net/corda/core/messaging/MessageRecipients.html @@ -2,10 +2,10 @@ - + MessageRecipients - + diff --git a/docs/build/html/api/javadoc/net/corda/core/messaging/MessagingKt.html b/docs/build/html/api/javadoc/net/corda/core/messaging/MessagingKt.html index f0b8785ffa..eff119fee3 100644 --- a/docs/build/html/api/javadoc/net/corda/core/messaging/MessagingKt.html +++ b/docs/build/html/api/javadoc/net/corda/core/messaging/MessagingKt.html @@ -2,10 +2,10 @@ - + MessagingKt - + diff --git a/docs/build/html/api/javadoc/net/corda/core/messaging/MessagingService.html b/docs/build/html/api/javadoc/net/corda/core/messaging/MessagingService.html index 1a9582cc8d..b5940655c6 100644 --- a/docs/build/html/api/javadoc/net/corda/core/messaging/MessagingService.html +++ b/docs/build/html/api/javadoc/net/corda/core/messaging/MessagingService.html @@ -2,10 +2,10 @@ - + MessagingService - + diff --git a/docs/build/html/api/javadoc/net/corda/core/messaging/RPCOps.html b/docs/build/html/api/javadoc/net/corda/core/messaging/RPCOps.html index fd8eff8224..1170d579c6 100644 --- a/docs/build/html/api/javadoc/net/corda/core/messaging/RPCOps.html +++ b/docs/build/html/api/javadoc/net/corda/core/messaging/RPCOps.html @@ -2,10 +2,10 @@ - + RPCOps - + diff --git a/docs/build/html/api/javadoc/net/corda/core/messaging/RPCReturnsObservables.html b/docs/build/html/api/javadoc/net/corda/core/messaging/RPCReturnsObservables.html index f013c9824a..8484031a48 100644 --- a/docs/build/html/api/javadoc/net/corda/core/messaging/RPCReturnsObservables.html +++ b/docs/build/html/api/javadoc/net/corda/core/messaging/RPCReturnsObservables.html @@ -2,10 +2,10 @@ - + RPCReturnsObservables - + diff --git a/docs/build/html/api/javadoc/net/corda/core/messaging/ReceivedMessage.html b/docs/build/html/api/javadoc/net/corda/core/messaging/ReceivedMessage.html index c47ede7ac7..33cadc600a 100644 --- a/docs/build/html/api/javadoc/net/corda/core/messaging/ReceivedMessage.html +++ b/docs/build/html/api/javadoc/net/corda/core/messaging/ReceivedMessage.html @@ -2,10 +2,10 @@ - + ReceivedMessage - + diff --git a/docs/build/html/api/javadoc/net/corda/core/messaging/SingleMessageRecipient.html b/docs/build/html/api/javadoc/net/corda/core/messaging/SingleMessageRecipient.html index cf924a4afd..0a0c8c320e 100644 --- a/docs/build/html/api/javadoc/net/corda/core/messaging/SingleMessageRecipient.html +++ b/docs/build/html/api/javadoc/net/corda/core/messaging/SingleMessageRecipient.html @@ -2,10 +2,10 @@ - + SingleMessageRecipient - + diff --git a/docs/build/html/api/javadoc/net/corda/core/messaging/StateMachineInfo.html b/docs/build/html/api/javadoc/net/corda/core/messaging/StateMachineInfo.html index 245bb27572..8d396a6021 100644 --- a/docs/build/html/api/javadoc/net/corda/core/messaging/StateMachineInfo.html +++ b/docs/build/html/api/javadoc/net/corda/core/messaging/StateMachineInfo.html @@ -2,10 +2,10 @@ - + StateMachineInfo - + diff --git a/docs/build/html/api/javadoc/net/corda/core/messaging/StateMachineUpdate.Added.html b/docs/build/html/api/javadoc/net/corda/core/messaging/StateMachineUpdate.Added.html index 779e120d7c..786a11eb27 100644 --- a/docs/build/html/api/javadoc/net/corda/core/messaging/StateMachineUpdate.Added.html +++ b/docs/build/html/api/javadoc/net/corda/core/messaging/StateMachineUpdate.Added.html @@ -2,10 +2,10 @@ - + StateMachineUpdate.Added - + diff --git a/docs/build/html/api/javadoc/net/corda/core/messaging/StateMachineUpdate.Removed.html b/docs/build/html/api/javadoc/net/corda/core/messaging/StateMachineUpdate.Removed.html index d6c92f37c2..185ae01982 100644 --- a/docs/build/html/api/javadoc/net/corda/core/messaging/StateMachineUpdate.Removed.html +++ b/docs/build/html/api/javadoc/net/corda/core/messaging/StateMachineUpdate.Removed.html @@ -2,10 +2,10 @@ - + StateMachineUpdate.Removed - + diff --git a/docs/build/html/api/javadoc/net/corda/core/messaging/StateMachineUpdate.html b/docs/build/html/api/javadoc/net/corda/core/messaging/StateMachineUpdate.html index 4fd6dc2d8c..eefdccd8a9 100644 --- a/docs/build/html/api/javadoc/net/corda/core/messaging/StateMachineUpdate.html +++ b/docs/build/html/api/javadoc/net/corda/core/messaging/StateMachineUpdate.html @@ -2,10 +2,10 @@ - + StateMachineUpdate - + diff --git a/docs/build/html/api/javadoc/net/corda/core/messaging/TopicSession.html b/docs/build/html/api/javadoc/net/corda/core/messaging/TopicSession.html index 38dd6dc5ec..16722722c3 100644 --- a/docs/build/html/api/javadoc/net/corda/core/messaging/TopicSession.html +++ b/docs/build/html/api/javadoc/net/corda/core/messaging/TopicSession.html @@ -2,10 +2,10 @@ - + TopicSession - + diff --git a/docs/build/html/api/javadoc/net/corda/core/messaging/TopicStringValidator.html b/docs/build/html/api/javadoc/net/corda/core/messaging/TopicStringValidator.html index d458ffa8b0..58c0fa19df 100644 --- a/docs/build/html/api/javadoc/net/corda/core/messaging/TopicStringValidator.html +++ b/docs/build/html/api/javadoc/net/corda/core/messaging/TopicStringValidator.html @@ -2,10 +2,10 @@ - + TopicStringValidator - + diff --git a/docs/build/html/api/javadoc/net/corda/core/messaging/package-frame.html b/docs/build/html/api/javadoc/net/corda/core/messaging/package-frame.html index 045009b6d7..dff69c274c 100644 --- a/docs/build/html/api/javadoc/net/corda/core/messaging/package-frame.html +++ b/docs/build/html/api/javadoc/net/corda/core/messaging/package-frame.html @@ -2,10 +2,10 @@ - + net.corda.core.messaging - + diff --git a/docs/build/html/api/javadoc/net/corda/core/messaging/package-summary.html b/docs/build/html/api/javadoc/net/corda/core/messaging/package-summary.html index 14bf236859..04561d630d 100644 --- a/docs/build/html/api/javadoc/net/corda/core/messaging/package-summary.html +++ b/docs/build/html/api/javadoc/net/corda/core/messaging/package-summary.html @@ -2,10 +2,10 @@ - + net.corda.core.messaging - + diff --git a/docs/build/html/api/javadoc/net/corda/core/messaging/package-tree.html b/docs/build/html/api/javadoc/net/corda/core/messaging/package-tree.html index 534be02a33..cd6697f45c 100644 --- a/docs/build/html/api/javadoc/net/corda/core/messaging/package-tree.html +++ b/docs/build/html/api/javadoc/net/corda/core/messaging/package-tree.html @@ -2,10 +2,10 @@ - + net.corda.core.messaging Class Hierarchy - + diff --git a/docs/build/html/api/javadoc/net/corda/core/node/AttachmentsClassLoader.OverlappingAttachments.html b/docs/build/html/api/javadoc/net/corda/core/node/AttachmentsClassLoader.OverlappingAttachments.html index 05a50cbc67..cdeed51cb7 100644 --- a/docs/build/html/api/javadoc/net/corda/core/node/AttachmentsClassLoader.OverlappingAttachments.html +++ b/docs/build/html/api/javadoc/net/corda/core/node/AttachmentsClassLoader.OverlappingAttachments.html @@ -2,10 +2,10 @@ - + AttachmentsClassLoader.OverlappingAttachments - + diff --git a/docs/build/html/api/javadoc/net/corda/core/node/AttachmentsClassLoader.html b/docs/build/html/api/javadoc/net/corda/core/node/AttachmentsClassLoader.html index d40cb6cc00..05e080523c 100644 --- a/docs/build/html/api/javadoc/net/corda/core/node/AttachmentsClassLoader.html +++ b/docs/build/html/api/javadoc/net/corda/core/node/AttachmentsClassLoader.html @@ -2,10 +2,10 @@ - + AttachmentsClassLoader - + diff --git a/docs/build/html/api/javadoc/net/corda/core/node/CityDatabase.html b/docs/build/html/api/javadoc/net/corda/core/node/CityDatabase.html index 97eecf584e..4efd44302e 100644 --- a/docs/build/html/api/javadoc/net/corda/core/node/CityDatabase.html +++ b/docs/build/html/api/javadoc/net/corda/core/node/CityDatabase.html @@ -2,10 +2,10 @@ - + CityDatabase - + diff --git a/docs/build/html/api/javadoc/net/corda/core/node/CordaPluginRegistry.html b/docs/build/html/api/javadoc/net/corda/core/node/CordaPluginRegistry.html index 9573bf8f04..05f4bdbc36 100644 --- a/docs/build/html/api/javadoc/net/corda/core/node/CordaPluginRegistry.html +++ b/docs/build/html/api/javadoc/net/corda/core/node/CordaPluginRegistry.html @@ -2,10 +2,10 @@ - + CordaPluginRegistry - + diff --git a/docs/build/html/api/javadoc/net/corda/core/node/NodeInfo.html b/docs/build/html/api/javadoc/net/corda/core/node/NodeInfo.html index 88e17bb2ae..cf37ca9934 100644 --- a/docs/build/html/api/javadoc/net/corda/core/node/NodeInfo.html +++ b/docs/build/html/api/javadoc/net/corda/core/node/NodeInfo.html @@ -2,10 +2,10 @@ - + NodeInfo - + diff --git a/docs/build/html/api/javadoc/net/corda/core/node/PhysicalLocation.html b/docs/build/html/api/javadoc/net/corda/core/node/PhysicalLocation.html index 5d1b301b47..fbe616f1df 100644 --- a/docs/build/html/api/javadoc/net/corda/core/node/PhysicalLocation.html +++ b/docs/build/html/api/javadoc/net/corda/core/node/PhysicalLocation.html @@ -2,10 +2,10 @@ - + PhysicalLocation - + diff --git a/docs/build/html/api/javadoc/net/corda/core/node/PluginServiceHub.html b/docs/build/html/api/javadoc/net/corda/core/node/PluginServiceHub.html index 1ea8a4f01e..975a59ae66 100644 --- a/docs/build/html/api/javadoc/net/corda/core/node/PluginServiceHub.html +++ b/docs/build/html/api/javadoc/net/corda/core/node/PluginServiceHub.html @@ -2,10 +2,10 @@ - + PluginServiceHub - + diff --git a/docs/build/html/api/javadoc/net/corda/core/node/ServiceEntry.html b/docs/build/html/api/javadoc/net/corda/core/node/ServiceEntry.html index b0dbfd1378..591f7caf36 100644 --- a/docs/build/html/api/javadoc/net/corda/core/node/ServiceEntry.html +++ b/docs/build/html/api/javadoc/net/corda/core/node/ServiceEntry.html @@ -2,10 +2,10 @@ - + ServiceEntry - + diff --git a/docs/build/html/api/javadoc/net/corda/core/node/ServiceHub.DefaultImpls.html b/docs/build/html/api/javadoc/net/corda/core/node/ServiceHub.DefaultImpls.html index efcc59cba3..23df3ae648 100644 --- a/docs/build/html/api/javadoc/net/corda/core/node/ServiceHub.DefaultImpls.html +++ b/docs/build/html/api/javadoc/net/corda/core/node/ServiceHub.DefaultImpls.html @@ -2,10 +2,10 @@ - + ServiceHub.DefaultImpls - + diff --git a/docs/build/html/api/javadoc/net/corda/core/node/ServiceHub.html b/docs/build/html/api/javadoc/net/corda/core/node/ServiceHub.html index 80c61659fc..abbcc0603f 100644 --- a/docs/build/html/api/javadoc/net/corda/core/node/ServiceHub.html +++ b/docs/build/html/api/javadoc/net/corda/core/node/ServiceHub.html @@ -2,10 +2,10 @@ - + ServiceHub - + diff --git a/docs/build/html/api/javadoc/net/corda/core/node/ServiceHubKt.html b/docs/build/html/api/javadoc/net/corda/core/node/ServiceHubKt.html index 7d04524c8f..15a7b0cc01 100644 --- a/docs/build/html/api/javadoc/net/corda/core/node/ServiceHubKt.html +++ b/docs/build/html/api/javadoc/net/corda/core/node/ServiceHubKt.html @@ -2,10 +2,10 @@ - + ServiceHubKt - + diff --git a/docs/build/html/api/javadoc/net/corda/core/node/WorldCoordinate.html b/docs/build/html/api/javadoc/net/corda/core/node/WorldCoordinate.html index 97149a475d..3cf95bce71 100644 --- a/docs/build/html/api/javadoc/net/corda/core/node/WorldCoordinate.html +++ b/docs/build/html/api/javadoc/net/corda/core/node/WorldCoordinate.html @@ -2,10 +2,10 @@ - + WorldCoordinate - + diff --git a/docs/build/html/api/javadoc/net/corda/core/node/package-frame.html b/docs/build/html/api/javadoc/net/corda/core/node/package-frame.html index c8f8313889..50362a2c71 100644 --- a/docs/build/html/api/javadoc/net/corda/core/node/package-frame.html +++ b/docs/build/html/api/javadoc/net/corda/core/node/package-frame.html @@ -2,10 +2,10 @@ - + net.corda.core.node - + diff --git a/docs/build/html/api/javadoc/net/corda/core/node/package-summary.html b/docs/build/html/api/javadoc/net/corda/core/node/package-summary.html index cc43be734d..c6af74e8da 100644 --- a/docs/build/html/api/javadoc/net/corda/core/node/package-summary.html +++ b/docs/build/html/api/javadoc/net/corda/core/node/package-summary.html @@ -2,10 +2,10 @@ - + net.corda.core.node - + diff --git a/docs/build/html/api/javadoc/net/corda/core/node/package-tree.html b/docs/build/html/api/javadoc/net/corda/core/node/package-tree.html index a2afbc8709..26561e1764 100644 --- a/docs/build/html/api/javadoc/net/corda/core/node/package-tree.html +++ b/docs/build/html/api/javadoc/net/corda/core/node/package-tree.html @@ -2,10 +2,10 @@ - + net.corda.core.node Class Hierarchy - + diff --git a/docs/build/html/api/javadoc/net/corda/core/node/services/AttachmentStorage.html b/docs/build/html/api/javadoc/net/corda/core/node/services/AttachmentStorage.html index ec22c05148..9fa18fbaeb 100644 --- a/docs/build/html/api/javadoc/net/corda/core/node/services/AttachmentStorage.html +++ b/docs/build/html/api/javadoc/net/corda/core/node/services/AttachmentStorage.html @@ -2,10 +2,10 @@ - + AttachmentStorage - + diff --git a/docs/build/html/api/javadoc/net/corda/core/node/services/IdentityService.html b/docs/build/html/api/javadoc/net/corda/core/node/services/IdentityService.html index 79172134dc..ce62db6265 100644 --- a/docs/build/html/api/javadoc/net/corda/core/node/services/IdentityService.html +++ b/docs/build/html/api/javadoc/net/corda/core/node/services/IdentityService.html @@ -2,10 +2,10 @@ - + IdentityService - + diff --git a/docs/build/html/api/javadoc/net/corda/core/node/services/KeyManagementService.DefaultImpls.html b/docs/build/html/api/javadoc/net/corda/core/node/services/KeyManagementService.DefaultImpls.html index bdf8ed2199..c976859443 100644 --- a/docs/build/html/api/javadoc/net/corda/core/node/services/KeyManagementService.DefaultImpls.html +++ b/docs/build/html/api/javadoc/net/corda/core/node/services/KeyManagementService.DefaultImpls.html @@ -2,10 +2,10 @@ - + KeyManagementService.DefaultImpls - + @@ -52,8 +52,8 @@ var activeTableTab = "activeTableTab"; @@ -127,7 +134,7 @@ extends NotaryError

    Nested classes/interfaces inherited from class net.corda.flows.NotaryError

    -NotaryError.Conflict, NotaryError.SignaturesMissing, NotaryError.TimestampInvalid, NotaryError.TransactionInvalid +NotaryError.Conflict, NotaryError.SignaturesInvalid, NotaryError.SignaturesMissing, NotaryError.TimestampInvalid, NotaryError.TransactionInvalid @@ -143,7 +150,26 @@ extends NotaryError Constructor and Description -TransactionInvalid()  +TransactionInvalid(java.lang.String msg)  + + + + + +
      +
    • + + +

      Method Summary

      + + + + + + + + +
      All Methods Instance Methods Concrete Methods 
      Modifier and TypeMethod and Description
      java.lang.StringgetMsg() 
    • @@ -160,13 +186,30 @@ extends NotaryError

      Constructor Detail

      - +
      • TransactionInvalid

        -
        public TransactionInvalid()
        +
        public TransactionInvalid(java.lang.String msg)
        +
      • +
      + +
    + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        getMsg

        +
        public java.lang.String getMsg()
    • @@ -224,13 +267,13 @@ extends NotaryError
    • Nested | 
    • Field | 
    • Constr | 
    • -
    • Method
    • +
    • Method
    diff --git a/docs/build/html/api/javadoc/net/corda/flows/NotaryError.html b/docs/build/html/api/javadoc/net/corda/flows/NotaryError.html index 5f2cf10ea9..84950ca86a 100644 --- a/docs/build/html/api/javadoc/net/corda/flows/NotaryError.html +++ b/docs/build/html/api/javadoc/net/corda/flows/NotaryError.html @@ -2,10 +2,10 @@ - + NotaryError - + @@ -99,7 +99,7 @@
  • Direct Known Subclasses:
    -
    NotaryError.Conflict, NotaryError.SignaturesMissing, NotaryError.TimestampInvalid, NotaryError.TransactionInvalid
    +
    NotaryError.Conflict, NotaryError.SignaturesInvalid, NotaryError.SignaturesMissing, NotaryError.TimestampInvalid, NotaryError.TransactionInvalid


    @@ -128,15 +128,19 @@ static class  -NotaryError.SignaturesMissing  +NotaryError.SignaturesInvalid  static class  +NotaryError.SignaturesMissing  + + +static class  NotaryError.TimestampInvalid
    Thrown if the time specified in the timestamp command is outside the allowed tolerance
    - + static class  NotaryError.TransactionInvalid  diff --git a/docs/build/html/api/javadoc/net/corda/flows/NotaryException.html b/docs/build/html/api/javadoc/net/corda/flows/NotaryException.html index 6adab72636..c64eb72361 100644 --- a/docs/build/html/api/javadoc/net/corda/flows/NotaryException.html +++ b/docs/build/html/api/javadoc/net/corda/flows/NotaryException.html @@ -2,10 +2,10 @@ - + NotaryException - + diff --git a/docs/build/html/api/javadoc/net/corda/flows/NotaryFlow.Client.html b/docs/build/html/api/javadoc/net/corda/flows/NotaryFlow.Client.html index 249b8367e3..de6f3758a8 100644 --- a/docs/build/html/api/javadoc/net/corda/flows/NotaryFlow.Client.html +++ b/docs/build/html/api/javadoc/net/corda/flows/NotaryFlow.Client.html @@ -2,10 +2,10 @@ - + NotaryFlow.Client - + diff --git a/docs/build/html/api/javadoc/net/corda/flows/NotaryFlow.Result.html b/docs/build/html/api/javadoc/net/corda/flows/NotaryFlow.Result.html index 21da51862e..eebb78bb20 100644 --- a/docs/build/html/api/javadoc/net/corda/flows/NotaryFlow.Result.html +++ b/docs/build/html/api/javadoc/net/corda/flows/NotaryFlow.Result.html @@ -2,10 +2,10 @@ - + NotaryFlow.Result - + diff --git a/docs/build/html/api/javadoc/net/corda/flows/NotaryFlow.Service.html b/docs/build/html/api/javadoc/net/corda/flows/NotaryFlow.Service.html index a3b3a8e2fb..2d6549789d 100644 --- a/docs/build/html/api/javadoc/net/corda/flows/NotaryFlow.Service.html +++ b/docs/build/html/api/javadoc/net/corda/flows/NotaryFlow.Service.html @@ -2,10 +2,10 @@ - + NotaryFlow.Service - + diff --git a/docs/build/html/api/javadoc/net/corda/flows/NotaryFlow.SignRequest.html b/docs/build/html/api/javadoc/net/corda/flows/NotaryFlow.SignRequest.html index 0dc40535d4..52e2c76389 100644 --- a/docs/build/html/api/javadoc/net/corda/flows/NotaryFlow.SignRequest.html +++ b/docs/build/html/api/javadoc/net/corda/flows/NotaryFlow.SignRequest.html @@ -2,10 +2,10 @@ - + NotaryFlow.SignRequest - + diff --git a/docs/build/html/api/javadoc/net/corda/flows/NotaryFlow.html b/docs/build/html/api/javadoc/net/corda/flows/NotaryFlow.html index 3bea1493cf..71a161b785 100644 --- a/docs/build/html/api/javadoc/net/corda/flows/NotaryFlow.html +++ b/docs/build/html/api/javadoc/net/corda/flows/NotaryFlow.html @@ -2,10 +2,10 @@ - + NotaryFlow - + diff --git a/docs/build/html/api/javadoc/net/corda/flows/Primary.Companion.html b/docs/build/html/api/javadoc/net/corda/flows/Primary.Companion.html index 1bcff68c87..e1019fc48e 100644 --- a/docs/build/html/api/javadoc/net/corda/flows/Primary.Companion.html +++ b/docs/build/html/api/javadoc/net/corda/flows/Primary.Companion.html @@ -2,10 +2,10 @@ - + Primary.Companion - + diff --git a/docs/build/html/api/javadoc/net/corda/flows/ResolveTransactionsFlow.Companion.html b/docs/build/html/api/javadoc/net/corda/flows/ResolveTransactionsFlow.Companion.html index 900ab14881..80d80a6ac3 100644 --- a/docs/build/html/api/javadoc/net/corda/flows/ResolveTransactionsFlow.Companion.html +++ b/docs/build/html/api/javadoc/net/corda/flows/ResolveTransactionsFlow.Companion.html @@ -2,10 +2,10 @@ - + ResolveTransactionsFlow.Companion - + diff --git a/docs/build/html/api/javadoc/net/corda/flows/ResolveTransactionsFlow.ExcessivelyLargeTransactionGraph.html b/docs/build/html/api/javadoc/net/corda/flows/ResolveTransactionsFlow.ExcessivelyLargeTransactionGraph.html index 20edda1959..bcb46a9057 100644 --- a/docs/build/html/api/javadoc/net/corda/flows/ResolveTransactionsFlow.ExcessivelyLargeTransactionGraph.html +++ b/docs/build/html/api/javadoc/net/corda/flows/ResolveTransactionsFlow.ExcessivelyLargeTransactionGraph.html @@ -2,10 +2,10 @@ - + ResolveTransactionsFlow.ExcessivelyLargeTransactionGraph - + diff --git a/docs/build/html/api/javadoc/net/corda/flows/ResolveTransactionsFlow.html b/docs/build/html/api/javadoc/net/corda/flows/ResolveTransactionsFlow.html index d8739afdd1..016a21cd94 100644 --- a/docs/build/html/api/javadoc/net/corda/flows/ResolveTransactionsFlow.html +++ b/docs/build/html/api/javadoc/net/corda/flows/ResolveTransactionsFlow.html @@ -2,10 +2,10 @@ - + ResolveTransactionsFlow - + diff --git a/docs/build/html/api/javadoc/net/corda/flows/Result.Companion.html b/docs/build/html/api/javadoc/net/corda/flows/Result.Companion.html index 57d9d5b21f..cd1421324f 100644 --- a/docs/build/html/api/javadoc/net/corda/flows/Result.Companion.html +++ b/docs/build/html/api/javadoc/net/corda/flows/Result.Companion.html @@ -2,10 +2,10 @@ - + Result.Companion - + diff --git a/docs/build/html/api/javadoc/net/corda/flows/Result.Error.html b/docs/build/html/api/javadoc/net/corda/flows/Result.Error.html index 5c7ea6c114..2656d2d92a 100644 --- a/docs/build/html/api/javadoc/net/corda/flows/Result.Error.html +++ b/docs/build/html/api/javadoc/net/corda/flows/Result.Error.html @@ -2,10 +2,10 @@ - + Result.Error - + diff --git a/docs/build/html/api/javadoc/net/corda/flows/Result.Success.html b/docs/build/html/api/javadoc/net/corda/flows/Result.Success.html index 12db4b16ac..2819767274 100644 --- a/docs/build/html/api/javadoc/net/corda/flows/Result.Success.html +++ b/docs/build/html/api/javadoc/net/corda/flows/Result.Success.html @@ -2,10 +2,10 @@ - + Result.Success - + diff --git a/docs/build/html/api/javadoc/net/corda/flows/Secondary.Companion.html b/docs/build/html/api/javadoc/net/corda/flows/Secondary.Companion.html index 06db14133c..d1ed8f55f8 100644 --- a/docs/build/html/api/javadoc/net/corda/flows/Secondary.Companion.html +++ b/docs/build/html/api/javadoc/net/corda/flows/Secondary.Companion.html @@ -2,10 +2,10 @@ - + Secondary.Companion - + diff --git a/docs/build/html/api/javadoc/net/corda/flows/Seller.Companion.html b/docs/build/html/api/javadoc/net/corda/flows/Seller.Companion.html index b00ae64d44..d0ff83b933 100644 --- a/docs/build/html/api/javadoc/net/corda/flows/Seller.Companion.html +++ b/docs/build/html/api/javadoc/net/corda/flows/Seller.Companion.html @@ -2,10 +2,10 @@ - + Seller.Companion - + diff --git a/docs/build/html/api/javadoc/net/corda/flows/ServiceRequestMessage.html b/docs/build/html/api/javadoc/net/corda/flows/ServiceRequestMessage.html index 1fc80e3309..2fece74c21 100644 --- a/docs/build/html/api/javadoc/net/corda/flows/ServiceRequestMessage.html +++ b/docs/build/html/api/javadoc/net/corda/flows/ServiceRequestMessage.html @@ -2,10 +2,10 @@ - + ServiceRequestMessage - + diff --git a/docs/build/html/api/javadoc/net/corda/flows/ServiceRequestMessageKt.html b/docs/build/html/api/javadoc/net/corda/flows/ServiceRequestMessageKt.html index 78107187d1..439114e71a 100644 --- a/docs/build/html/api/javadoc/net/corda/flows/ServiceRequestMessageKt.html +++ b/docs/build/html/api/javadoc/net/corda/flows/ServiceRequestMessageKt.html @@ -2,10 +2,10 @@ - + ServiceRequestMessageKt - + diff --git a/docs/build/html/api/javadoc/net/corda/flows/StateReplacementException.html b/docs/build/html/api/javadoc/net/corda/flows/StateReplacementException.html index c5332fbad3..37b2c80a73 100644 --- a/docs/build/html/api/javadoc/net/corda/flows/StateReplacementException.html +++ b/docs/build/html/api/javadoc/net/corda/flows/StateReplacementException.html @@ -2,10 +2,10 @@ - + StateReplacementException - + diff --git a/docs/build/html/api/javadoc/net/corda/flows/StateReplacementRefused.html b/docs/build/html/api/javadoc/net/corda/flows/StateReplacementRefused.html index 3b0e2b0645..5267c93e0e 100644 --- a/docs/build/html/api/javadoc/net/corda/flows/StateReplacementRefused.html +++ b/docs/build/html/api/javadoc/net/corda/flows/StateReplacementRefused.html @@ -2,10 +2,10 @@ - + StateReplacementRefused - + diff --git a/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.Acceptor.html b/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.Acceptor.html index 5317199fe5..6b47444274 100644 --- a/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.Acceptor.html +++ b/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.Acceptor.html @@ -2,10 +2,10 @@ - + TwoPartyDealFlow.Acceptor - + diff --git a/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.AutoOffer.html b/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.AutoOffer.html index 199aa067d5..3bfae46905 100644 --- a/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.AutoOffer.html +++ b/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.AutoOffer.html @@ -2,10 +2,10 @@ - + TwoPartyDealFlow.AutoOffer - + diff --git a/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.DealMismatchException.html b/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.DealMismatchException.html index 00883488ec..59384c0ce6 100644 --- a/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.DealMismatchException.html +++ b/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.DealMismatchException.html @@ -2,10 +2,10 @@ - + TwoPartyDealFlow.DealMismatchException - + diff --git a/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.DealRefMismatchException.html b/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.DealRefMismatchException.html index ed0e982907..e6e5a954c1 100644 --- a/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.DealRefMismatchException.html +++ b/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.DealRefMismatchException.html @@ -2,10 +2,10 @@ - + TwoPartyDealFlow.DealRefMismatchException - + diff --git a/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.Handshake.html b/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.Handshake.html index 92ccb43760..5d64d78ab3 100644 --- a/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.Handshake.html +++ b/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.Handshake.html @@ -2,10 +2,10 @@ - + TwoPartyDealFlow.Handshake - + diff --git a/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.Instigator.html b/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.Instigator.html index d850bc7cdd..256c0e8dcc 100644 --- a/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.Instigator.html +++ b/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.Instigator.html @@ -2,10 +2,10 @@ - + TwoPartyDealFlow.Instigator - + diff --git a/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.MarkerForBogusRegulatorFlow.html b/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.MarkerForBogusRegulatorFlow.html index e5c943490c..f88f5331ce 100644 --- a/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.MarkerForBogusRegulatorFlow.html +++ b/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.MarkerForBogusRegulatorFlow.html @@ -2,10 +2,10 @@ - + TwoPartyDealFlow.MarkerForBogusRegulatorFlow - + diff --git a/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.Primary.html b/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.Primary.html index 89ed417b5b..88e1887510 100644 --- a/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.Primary.html +++ b/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.Primary.html @@ -2,10 +2,10 @@ - + TwoPartyDealFlow.Primary - + diff --git a/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.Secondary.html b/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.Secondary.html index c2514def3e..9fe64174e2 100644 --- a/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.Secondary.html +++ b/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.Secondary.html @@ -2,10 +2,10 @@ - + TwoPartyDealFlow.Secondary - + diff --git a/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.SignaturesFromPrimary.html b/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.SignaturesFromPrimary.html index ec6e12399a..e371cf71d4 100644 --- a/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.SignaturesFromPrimary.html +++ b/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.SignaturesFromPrimary.html @@ -2,10 +2,10 @@ - + TwoPartyDealFlow.SignaturesFromPrimary - + diff --git a/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.html b/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.html index 8cf76816ff..cf1befb2e6 100644 --- a/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.html +++ b/docs/build/html/api/javadoc/net/corda/flows/TwoPartyDealFlow.html @@ -2,10 +2,10 @@ - + TwoPartyDealFlow - + diff --git a/docs/build/html/api/javadoc/net/corda/flows/TwoPartyTradeFlow.AssetMismatchException.html b/docs/build/html/api/javadoc/net/corda/flows/TwoPartyTradeFlow.AssetMismatchException.html index f41a0367c4..82fb9c3b2d 100644 --- a/docs/build/html/api/javadoc/net/corda/flows/TwoPartyTradeFlow.AssetMismatchException.html +++ b/docs/build/html/api/javadoc/net/corda/flows/TwoPartyTradeFlow.AssetMismatchException.html @@ -2,10 +2,10 @@ - + TwoPartyTradeFlow.AssetMismatchException - + diff --git a/docs/build/html/api/javadoc/net/corda/flows/TwoPartyTradeFlow.Buyer.html b/docs/build/html/api/javadoc/net/corda/flows/TwoPartyTradeFlow.Buyer.html index 776726b30e..9c17e81268 100644 --- a/docs/build/html/api/javadoc/net/corda/flows/TwoPartyTradeFlow.Buyer.html +++ b/docs/build/html/api/javadoc/net/corda/flows/TwoPartyTradeFlow.Buyer.html @@ -2,10 +2,10 @@ - + TwoPartyTradeFlow.Buyer - + diff --git a/docs/build/html/api/javadoc/net/corda/flows/TwoPartyTradeFlow.Seller.html b/docs/build/html/api/javadoc/net/corda/flows/TwoPartyTradeFlow.Seller.html index 405da9a8da..c43fb32ee2 100644 --- a/docs/build/html/api/javadoc/net/corda/flows/TwoPartyTradeFlow.Seller.html +++ b/docs/build/html/api/javadoc/net/corda/flows/TwoPartyTradeFlow.Seller.html @@ -2,10 +2,10 @@ - + TwoPartyTradeFlow.Seller - + diff --git a/docs/build/html/api/javadoc/net/corda/flows/TwoPartyTradeFlow.SellerTradeInfo.html b/docs/build/html/api/javadoc/net/corda/flows/TwoPartyTradeFlow.SellerTradeInfo.html index 0a3fb30fce..2d70ea6cac 100644 --- a/docs/build/html/api/javadoc/net/corda/flows/TwoPartyTradeFlow.SellerTradeInfo.html +++ b/docs/build/html/api/javadoc/net/corda/flows/TwoPartyTradeFlow.SellerTradeInfo.html @@ -2,10 +2,10 @@ - + TwoPartyTradeFlow.SellerTradeInfo - + diff --git a/docs/build/html/api/javadoc/net/corda/flows/TwoPartyTradeFlow.SignaturesFromSeller.html b/docs/build/html/api/javadoc/net/corda/flows/TwoPartyTradeFlow.SignaturesFromSeller.html index c331c872be..b30fee7b88 100644 --- a/docs/build/html/api/javadoc/net/corda/flows/TwoPartyTradeFlow.SignaturesFromSeller.html +++ b/docs/build/html/api/javadoc/net/corda/flows/TwoPartyTradeFlow.SignaturesFromSeller.html @@ -2,10 +2,10 @@ - + TwoPartyTradeFlow.SignaturesFromSeller - + @@ -59,7 +59,7 @@ var activeTableTab = "activeTableTab";
  • diff --git a/docs/build/html/api/javadoc/net/corda/node/services/config/NodeConfigurationKt.html b/docs/build/html/api/javadoc/net/corda/node/services/config/NodeConfigurationKt.html index 39c3ac7ba2..a7449451fd 100644 --- a/docs/build/html/api/javadoc/net/corda/node/services/config/NodeConfigurationKt.html +++ b/docs/build/html/api/javadoc/net/corda/node/services/config/NodeConfigurationKt.html @@ -2,10 +2,10 @@ - + NodeConfigurationKt - + @@ -45,7 +45,7 @@
    • getConfig

      -
      public NodeSSLConfiguration getConfig()
      +
      public SSLConfiguration getConfig()

      The config object is used to pass in the passwords for the certificate KeyStore and TrustStore

    diff --git a/docs/build/html/api/javadoc/net/corda/node/services/messaging/ArtemisMessagingServer.Companion.html b/docs/build/html/api/javadoc/net/corda/node/services/messaging/ArtemisMessagingServer.Companion.html index 3fa0d9fbf5..49f0427767 100644 --- a/docs/build/html/api/javadoc/net/corda/node/services/messaging/ArtemisMessagingServer.Companion.html +++ b/docs/build/html/api/javadoc/net/corda/node/services/messaging/ArtemisMessagingServer.Companion.html @@ -2,10 +2,10 @@ - + ArtemisMessagingServer.Companion - + @@ -44,8 +44,8 @@
  • CordaRPCClient

    public CordaRPCClient(com.google.common.net.HostAndPort host,
    -                      NodeSSLConfiguration config)
    + SSLConfiguration config)

    An RPC client connects to the specified server and allows you to make calls to the server that perform various useful tasks. See the documentation for proxy or review the docsite to learn more about how this API works.

    @@ -525,7 +525,7 @@ Finalizers are in place to warn you if you lose a reference to an unclosed proxy
    • getConfig

      -
      public NodeSSLConfiguration getConfig()
      +
      public SSLConfiguration getConfig()

      The config object is used to pass in the passwords for the certificate KeyStore and TrustStore

    diff --git a/docs/build/html/api/javadoc/net/corda/node/services/messaging/CordaRPCClientImpl.Companion.html b/docs/build/html/api/javadoc/net/corda/node/services/messaging/CordaRPCClientImpl.Companion.html index d1ad729588..da0d5c41ff 100644 --- a/docs/build/html/api/javadoc/net/corda/node/services/messaging/CordaRPCClientImpl.Companion.html +++ b/docs/build/html/api/javadoc/net/corda/node/services/messaging/CordaRPCClientImpl.Companion.html @@ -2,10 +2,10 @@ - + CordaRPCClientImpl.Companion - + @@ -44,8 +44,8 @@ diff --git a/docs/build/html/contract-irs.html b/docs/build/html/contract-irs.html index 844c779669..43e314a22c 100644 --- a/docs/build/html/contract-irs.html +++ b/docs/build/html/contract-irs.html @@ -34,6 +34,9 @@ + + @@ -104,11 +107,15 @@ API reference: Kotlin/ Key concepts

    CorDapps

      @@ -146,6 +153,8 @@ API reference: Kotlin/ Other

      Component library

      diff --git a/docs/build/html/corda-configuration-file.html b/docs/build/html/corda-configuration-file.html index 3f8e63a939..2eef745c50 100644 --- a/docs/build/html/corda-configuration-file.html +++ b/docs/build/html/corda-configuration-file.html @@ -34,6 +34,9 @@ + + @@ -104,11 +107,15 @@ API reference: Kotlin/ Key concepts

      CorDapps

        @@ -152,6 +159,8 @@ API reference: Kotlin/ Other

        Component library

        diff --git a/docs/build/html/corda-plugins.html b/docs/build/html/corda-plugins.html index 9687bfed79..d4aee0732e 100644 --- a/docs/build/html/corda-plugins.html +++ b/docs/build/html/corda-plugins.html @@ -34,6 +34,9 @@ + + @@ -104,11 +107,15 @@ API reference: Kotlin/ Key concepts

        CorDapps

          @@ -146,6 +153,8 @@ API reference: Kotlin/ Other

          Component library

          diff --git a/docs/build/html/creating-a-cordapp.html b/docs/build/html/creating-a-cordapp.html index 68560fd2d0..78de10bc35 100644 --- a/docs/build/html/creating-a-cordapp.html +++ b/docs/build/html/creating-a-cordapp.html @@ -34,9 +34,12 @@ + + - + @@ -104,11 +107,15 @@ API reference: Kotlin/ Key concepts

          CorDapps

            @@ -163,6 +170,8 @@ API reference: Kotlin/ Other

            Component library

            @@ -459,7 +469,7 @@ one node per window.

            Next - Previous + Previous diff --git a/docs/build/html/data-model.html b/docs/build/html/data-model.html deleted file mode 100644 index f72b9f5677..0000000000 --- a/docs/build/html/data-model.html +++ /dev/null @@ -1,546 +0,0 @@ - - - - - - - - - - - - - - Data model — R3 Corda latest documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
            - - - - -
            - - - - - - -
            -
            - - - - - - -
            - -
            -
            -
            -
            - -
            -

            Data model

            -

            This article covers the data model: how states, transactions and code contracts interact with each other and -how they are represented in software.

            -
            -

            Overview

            -

            We begin with the idea of a global ledger. In our model 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 should be possible to keep the relevant data purely within that group.

            -

            To ensure consistency in a global, shared system where not all data may be visible to all participants, we rely -heavily on secure hashes like SHA-256 to identify things. The 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.

            -

            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, so states currently point at -statically created object instances. This will change in the near future.

            -
            -

            Contracts define a verify function, which is a pure function given the entire transaction as input. To be considered -valid, the transaction must be accepted by the verify function of every contract pointed to by the input and output -states.

            -

            Beyond inputs and outputs, transactions may also contain commands, small data packets that -the platform does not interpret itself but which can parameterise execution of the contracts. They can be thought of as -arguments to the verify function. Each command has a list of public keys associated with it. The platform ensures -that the transaction is signed by 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

            -

            Attachments must be opened explicitly in the current code.

            -
            -

            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, with the signature of a special kind of service called a notary. A notary is -a (very likely) decentralised service which fulfils the role that miners play in other blockchain systems: -notaries ensure only one transaction can consume any given output. Additionally they may verify a timestamping -command placed inside the transaction, which 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. Each state points to the notary that -controls it. Whilst a single transaction may only consume states if they are all controlled by the same notary, -a special type of transaction is provided that moves a state (or set of states) from one notary to another.

            -
            -

            Note

            -

            Currently the platform code will not re-assign states to a single notary as needed for you, in case of -a mismatch. This is a future planned feature.

            -
            -

            As the same terminology often crops up in different distributed ledger designs, let’s compare this to other -systems you may be familiar with. The key differences are:

            -
              -
            • Improved contract flexibility vs Bitcoin
            • -
            • Improved scalability vs Ethereum, as well as ability to keep parts of the transaction graph private (yet still uniquely addressable)
            • -
            • No reliance on proof of work
            • -
            • Re-use of existing sandboxing virtual machines
            • -
            • Use of type safe GCd implementation languages
            • -
            • Simplified auditing
            • -
            -
            -
            -

            Comparison with Bitcoin

            -

            Similarities:

            -
              -
            • The basic notion of immutable states that are consumed and created by transactions is the same.
            • -
            • The notion of transactions having multiple inputs and outputs is the same. Bitcoin sometimes refers to the ledger -as the unspent transaction output set (UTXO set) as a result.
            • -
            • Like in Bitcoin, a contract is pure function. Contracts do not have storage or the ability to interact with anything. -Given the same transaction, a contract’s accept function always yields exactly the same result.
            • -
            • Bitcoin output scripts are parameterised by the input scripts in the spending transaction. This is somewhat similar -to our notion of a command.
            • -
            • Bitcoin has a global distributed notary service; that’s the famous block chain. However, there is only one. Whilst -there is a notion of a “side chain”, this isn’t integrated with the core Bitcoin data model and thus adds large -amounts of additional complexity meaning in practice side chains are not used.
            • -
            • Bitcoin transactions, like ours, refer to the states they consume by using a (txhash, index) pair. The Bitcoin -protocol calls these “outpoints”. In our code they are known as StateRefs but the concept is identical.
            • -
            • Bitcoin transactions have an associated timestamp (the time at which they are mined).
            • -
            -

            Differences:

            -
              -
            • A Bitcoin transaction has a single, rigid data format. A “state” in Bitcoin is always a (quantity of bitcoin, script) -pair and cannot hold any other data. Some people have been known to try and hack around this limitation by embedding -data in semi-standardised places in the contract code so the data can be extracted through pattern matching, but this -is a poor approach. Our states can include arbitrary typed data.
            • -
            • A Bitcoin transaction’s acceptance is controlled only by the contract code in the consumed input states. In practice -this has proved limiting. Our transactions invoke not only input contracts but also the contracts of the outputs.
            • -
            • A Bitcoin script can only be given a fixed set of byte arrays as the input. This means there’s no way for a contract -to examine the structure of the entire transaction, which severely limits what contracts can do.
            • -
            • Our contracts are Turing-complete and can be written in any ordinary programming language that targets the JVM.
            • -
            • Our transactions and contracts get their time from an attached timestamp rather than a block. This is -important given that we use block-free conflict resolution algorithms. The timestamp can be arbitrarily precise.
            • -
            • We use the term “contract” to refer to a bundle of business logic that may handle various different tasks, beyond -transaction verification. For instance, currently our contracts also include code for creating valid transactions -(this is often called “wallet code” in Bitcoin).
            • -
            -
            -
            -

            Comparison with Ethereum

            -

            Similarities:

            -
              -
            • Like Ethereum, code runs inside a relatively powerful virtual machine and can contain complex logic. Non-assembly -based programming languages can be used for contract programming.
            • -
            • They are both intended for the modelling of many different kinds of financial contract.
            • -
            -

            Differences:

            -
              -
            • The term “contract” in Ethereum refers to an instantiation of a program that is replicated and maintained by -every participating node. This instantiation is very much like an object in an OO program: it can receive and send -messages, update local storage and so on. In contrast, we use the term “contract” to refer to a set of functions, only -one of which is a part of keeping the system synchronised (the verify function). That function is pure and -stateless i.e. it may not interact with any other part of the system whilst executing.
            • -
            • There is no notion of an “account”, as there is in Ethereum.
            • -
            • As contracts don’t have any kind of mutable storage, there is no notion of a “message” as in Ethereum.
            • -
            • Ethereum claims to be a platform not only for financial logic, but literally any kind of application at all. Our -platform considers non-financial applications to be out of scope.
            • -
            -
            -
            -

            Rationale for and tradeoffs in adopting a UTXO-style model

            -

            As discussed above, Corda uses the so-called “UTXO set” model (unspent transaction output). In this model, the database -does not track accounts or balances. Instead all database entries are immutable. An entry is either spent or not spent -but it cannot be changed. In Bitcoin, spentness is implemented simply as deletion – the inputs of an accepted transaction -are deleted and the outputs created.

            -

            This approach has some advantages and some disadvantages, which is why some platforms like Ethereum have tried -(or are trying) to abstract this choice away and support a more traditional account-like model. We have explicitly -chosen not to do this and our decision to adopt a UTXO-style model is a deliberate one. In the section below, -the rationale for this decision and its pros and cons of this choice are outlined.

            -
            -
            -

            Rationale

            -

            Corda, in common with other blockchain-like platforms, is designed to bring parties to shared sets of data into -consensus as to the existence, content and allowable evolutions of those data sets. However, Corda is designed with the -explicit aim of avoiding, to the extent possible, the scalability and privacy implications that arise from those platforms’ -decisions to adopt a global broadcast model.

            -

            Whilst the privacy implications of a global consensus model are easy to understand, the scalability implications are -perhaps more subtle, yet serious. In a consensus system, it is critical that all processors of a transaction reach -precisely the same conclusion as to its effects. In situations where two transactions may act on the same data set, -it means that the two transactions must be processed in the same order by all nodes. If this were not the case then it -would be possible to devise situations where nodes processed transactions in different orders and reached different -conclusions as to the state of the system. It is for this reason that systems like Ethereum effectively run -single-threaded, meaning the speed of the system is limited by the single-threaded performance of the slowest -machine on the network.

            -

            In Corda, we assume the data being processed represents financial agreements between identifiable parties and that these -institutions will adopt the system only if a significant number of such agreements can be managed by the platform. -As such, the system has to be able to support parallelisation of execution to the greatest extent possible, -whilst ensuring correct transaction ordering when two transactions seek to act on the same piece of shared state.

            -

            To achieve this, we must minimise the number of parties who need to receive and process copies of any given -transaction and we must minimise the extent to which two transactions seek to mutate (or supersede) any given piece -of shared state.

            -

            A key design decision, therefore, is what should be the most atomic unit of shared data in the system. This decision -also has profound privacy implications: the more coarsely defined the shared data units, the larger the set of -actors who will likely have a stake in its accuracy and who must process and observe any update to it.

            -

            This becomes most obvious when we consider two models for representing cash balances and payments.

            -

            A simple account model for cash would define a data structure that maintained a balance at a particular bank for each -“account holder”. Every holder of a balance would need a copy of this structure and would thus need to process and -validate every payment transaction, learning about everybody else’s payments and balances in the process. -All payments across that set of accounts would have to be single-threaded across the platform, limiting maximum -throughput.

            -

            A more sophisticated example might create a data structure per account holder. -But, even here, I would leak my account balance to anybody to whom I ever made -a payment and I could only ever make one payment at a time, for the same reasons above.

            -

            A UTXO model would define a data structure that represented an instance of a claim against the bank. An account -holder could hold many such instances, the aggregate of which would reveal their balance at that institution. However, -the account holder now only needs to reveal to their payee those instances consumed in making a payment to that payee. -This also means the payer could make several payments in parallel. A downside is that the model is harder to understand. -However, we consider the privacy and scalability advantages to overwhelm the modest additional cognitive load this places -on those attempting to learn the system.

            -

            In what follows, further advantages and disadvantages of this design decision are explored.

            -
            -
            -

            Pros

            -

            The UTXO model has these advantages:

            -
              -
            • Immutable ledger entries gives the usual advantages that a more functional approach brings: it’s easy to do analysis -on a static snapshot of the data and reason about the contents.
            • -
            • Because there are no accounts, it’s very easy to apply transactions in parallel even for high traffic legal entities -assuming sufficiently granular entries.
            • -
            • Transaction ordering becomes trivial: it is impossible to mis-order transactions due to the reliance on hash functions -to identify previous states. There is no need for sequence numbers or other things that are hard to provide in a -fully distributed system.
            • -
            • Conflict resolution boils down to the double spending problem, which places extremely minimal demands on consensus -algorithms (as the variable you’re trying to reach consensus on is a set of booleans).
            • -
            -
            -
            -

            Cons

            -

            It also comes with some pretty serious complexities that in practice must be abstracted from developers:

            -
              -
            • Representing numeric amounts using immutable entries is unnatural. For instance, if you receive $1000 and wish -to send someone $100, you have to consume the $1000 output and then create two more: a $100 for the recipient and -$900 back to yourself as change. The fact that this happens can leak private information to an observer.
            • -
            • Because users do need to think in terms of balances and statements, you have to layer this on top of the -underlying ledger: you can’t just read someone’s balance out of the system. Hence, the “wallet” / position manager. -Experience from those who have developed wallets for Bitcoin and other systems is that they can be complex pieces of code, -although the bulk of wallets’ complexity in public systems is handling the lack of finality (and key management).
            • -
            • Whilst transactions can be applied in parallel, it is much harder to create them in parallel due to the need to -strictly enforce a total ordering.
            • -
            -

            With respect to parallel creation, if the user is single threaded this is fine, but in a more complex situation -where you might want to be preparing multiple transactions in flight this can prove a limitation – in -the worst case where you have a single output that represents all your value, this forces you to serialise -the creation of every transaction. If transactions can be created and signed very fast that’s not a concern. -If there’s only a single user, that’s not a concern.

            -

            Both cases are typically true in the Bitcoin world, so users don’t suffer from this much. In the context of a -complex business with a large pool of shared funds, in which creation of transactions may be very slow due to the -need to get different humans to approve a tx using a signing device, this could quickly lead to frustrating -conflicts where someone approves a transaction and then discovers that it has become a double spend and -they must sign again. In the absolute worst case you could get a form of human livelock.

            -

            The tricky part about solving these problems is that the simplest way to express a payment request -(“send me $1000 to public key X”) inherently results in you receiving a single output, which then can -prove insufficiently granular to be convenient. In the Bitcoin space Mike Hearn and Gavin Andresen designed “BIP 70” -to solve this: it’s a simple binary format for requesting a payment and specifying exactly how you’d like to get paid, -including things like the shape of the transaction. It may seem that it’s an over complex approach: could you not -just immediately respend the big output back to yourself in order to split it? And yes, you could, until you hit -scenarios like “the machine requesting the payment doesn’t have the keys needed to spend it”, -which turn out to be very common. So it’s really more effective for a recipient to be able to say to the -sender, “here’s the kind of transaction I want you to send me”. The flow framework -may provide a vehicle to make such negotiations simpler.

            -

            A further challenge is privacy. Whilst our goal of not sending transactions to nodes that don’t “need to know” -helps, to verify a transaction you still need to verify all its dependencies and that can result in you receiving -lots of transactions that involve random third parties. The problems start when you have received lots of separate -payments and been careful not to make them linkable to your identity, but then you need to combine them all in a -single transaction to make a payment.

            -

            Mike Hearn wrote an article about this problem and techniques to minimise it in -this article from 2013. This article -coined the term “merge avoidance”, which has never been implemented in the Bitcoin space, -although not due to lack of practicality.

            -

            A piece of future work for the wallet implementation will be to implement automated “grooming” of the wallet -to “reshape” outputs to useful/standardised sizes, for example, and to send outputs of complex transactions -back to their issuers for reissuance to “sever” long privacy-breaching chains.

            -

            Finally, it should be noted that some of the issues described here are not really “cons” of -the UTXO model; they’re just fundamental. If you used many different anonymous accounts to preserve some privacy -and then needed to spend the contents of them all simultaneously, you’d hit the same problem, so it’s not -something that can be trivially fixed with data model changes.

            -
            -
            - - -
            -
            - - -
            -
            - -
            - -
            - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/build/html/event-scheduling.html b/docs/build/html/event-scheduling.html index 78b4b6a926..93e7858dd4 100644 --- a/docs/build/html/event-scheduling.html +++ b/docs/build/html/event-scheduling.html @@ -34,6 +34,9 @@ + + @@ -104,11 +107,15 @@ API reference: Kotlin/ Key concepts

            CorDapps

              @@ -151,6 +158,8 @@ API reference: Kotlin/ Other

              Component library

              diff --git a/docs/build/html/flow-state-machines.html b/docs/build/html/flow-state-machines.html index af0a5f53c9..277847a9d9 100644 --- a/docs/build/html/flow-state-machines.html +++ b/docs/build/html/flow-state-machines.html @@ -34,6 +34,9 @@ + + @@ -104,11 +107,15 @@ API reference: Kotlin/ Key concepts

              CorDapps

                @@ -159,6 +166,8 @@ API reference: Kotlin/ Other

                Component library

                @@ -227,9 +237,9 @@ API reference: Kotlin/

                Writing flows

                -

                This article explains our approach to modelling financial flows in code. It explains how the -platform’s state machine framework is used, and takes you through the code for a simple 2-party asset trading flow -which is included in the source.

                +

                This article explains our approach to modelling business processes and the lower level network protocols that implement +them. It explains how the platform’s flow framework is used, and takes you through the code for a simple +2-party asset trading flow which is included in the source.

                Introduction

                Shared distributed ledgers are interesting because they allow many different, mutually distrusting parties to @@ -361,7 +371,7 @@ 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 “Consensus model” for more +
                • notaryNode: NodeInfo - the entry in the network map for the chosen notary. See “consensus” for more information on notaries.
                • assetToSell: StateAndRef<OwnableState> - a pointer to the ledger entry that represents the thing being sold.
                • price: Amount<Currency> - the agreed on price that the asset is being sold for (without an issuer constraint).
                • @@ -592,97 +602,99 @@ future version of the code.

                  Implementing the buyer

                  OK, let’s do the same for the buyer side:

                  -
                          @Suspendable
                  -        override fun call(): SignedTransaction {
                  -            val tradeRequest = receiveAndValidateTradeRequest()
                  +
                  +
                  @Suspendable
                  +override fun call(): SignedTransaction {
                  +    val tradeRequest = receiveAndValidateTradeRequest()
                   
                  -            progressTracker.currentStep = SIGNING
                  -            val (ptx, cashSigningPubKeys) = assembleSharedTX(tradeRequest)
                  -            val stx = signWithOurKeys(cashSigningPubKeys, ptx)
                  +    progressTracker.currentStep = SIGNING
                  +    val (ptx, cashSigningPubKeys) = assembleSharedTX(tradeRequest)
                  +    val stx = signWithOurKeys(cashSigningPubKeys, ptx)
                   
                  -            val signatures = swapSignaturesWithSeller(stx)
                  +    val signatures = swapSignaturesWithSeller(stx)
                   
                  -            logger.trace { "Got signatures from seller, verifying ... " }
                  +    logger.trace { "Got signatures from seller, verifying ... " }
                   
                  -            val fullySigned = stx + signatures.sellerSig + signatures.notarySig
                  -            fullySigned.verifySignatures()
                  +    val fullySigned = stx + signatures.sellerSig + signatures.notarySig
                  +    fullySigned.verifySignatures()
                   
                  -            logger.trace { "Signatures received are valid. Trade complete! :-)" }
                  -            return fullySigned
                  -        }
                  +    logger.trace { "Signatures received are valid. Trade complete! :-)" }
                  +    return fullySigned
                  +}
                   
                  -        @Suspendable
                  -        private fun receiveAndValidateTradeRequest(): SellerTradeInfo {
                  -            progressTracker.currentStep = RECEIVING
                  -            // Wait for a trade request to come in from the other side
                  -            val maybeTradeRequest = receive<SellerTradeInfo>(otherParty)
                  +@Suspendable
                  +private fun receiveAndValidateTradeRequest(): SellerTradeInfo {
                  +    progressTracker.currentStep = RECEIVING
                  +    // Wait for a trade request to come in from the other side
                  +    val maybeTradeRequest = receive<SellerTradeInfo>(otherParty)
                   
                  -            progressTracker.currentStep = VERIFYING
                  -            maybeTradeRequest.unwrap {
                  -                // 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}" }
                  +    progressTracker.currentStep = VERIFYING
                  +    maybeTradeRequest.unwrap {
                  +        // 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)
                  -                if (!typeToBuy.isInstance(asset))
                  -                    throw AssetMismatchException(typeToBuy.name, assetTypeName)
                  +        if (it.price > acceptablePrice)
                  +            throw UnacceptablePriceException(it.price)
                  +        if (!typeToBuy.isInstance(asset))
                  +            throw AssetMismatchException(typeToBuy.name, assetTypeName)
                   
                  -                // Check the transaction that contains the state which is being resolved.
                  -                // We only have a hash here, so if we don't know it already, we have to ask for it.
                  -                subFlow(ResolveTransactionsFlow(setOf(it.assetForSale.ref.txhash), otherParty))
                  +        // Check the transaction that contains the state which is being resolved.
                  +        // We only have a hash here, so if we don't know it already, we have to ask for it.
                  +        subFlow(ResolveTransactionsFlow(setOf(it.assetForSale.ref.txhash), otherParty))
                   
                  -                return it
                  -            }
                  -        }
                  +        return it
                  +    }
                  +}
                   
                  -        @Suspendable
                  -        private fun swapSignaturesWithSeller(stx: SignedTransaction): SignaturesFromSeller {
                  -            progressTracker.currentStep = SWAPPING_SIGNATURES
                  -            logger.trace { "Sending partially signed transaction to seller" }
                  +@Suspendable
                  +private fun swapSignaturesWithSeller(stx: SignedTransaction): SignaturesFromSeller {
                  +    progressTracker.currentStep = SWAPPING_SIGNATURES
                  +    logger.trace { "Sending partially signed transaction to seller" }
                   
                  -            // TODO: Protect against the seller terminating here and leaving us in the lurch without the final tx.
                  +    // TODO: Protect against the seller terminating here and leaving us in the lurch without the final tx.
                   
                  -            return sendAndReceive<SignaturesFromSeller>(otherParty, stx).unwrap { it }
                  -        }
                  +    return sendAndReceive<SignaturesFromSeller>(otherParty, stx).unwrap { it }
                  +}
                   
                  -        private fun signWithOurKeys(cashSigningPubKeys: List<CompositeKey>, ptx: TransactionBuilder): SignedTransaction {
                  -            // Now sign the transaction with whatever keys we need to move the cash.
                  -            for (publicKey in cashSigningPubKeys.keys) {
                  -                val privateKey = serviceHub.keyManagementService.toPrivate(publicKey)
                  -                ptx.signWith(KeyPair(publicKey, privateKey))
                  -            }
                  +private fun signWithOurKeys(cashSigningPubKeys: List<CompositeKey>, ptx: TransactionBuilder): SignedTransaction {
                  +    // Now sign the transaction with whatever keys we need to move the cash.
                  +    for (publicKey in cashSigningPubKeys.keys) {
                  +        val privateKey = serviceHub.keyManagementService.toPrivate(publicKey)
                  +        ptx.signWith(KeyPair(publicKey, privateKey))
                  +    }
                   
                  -            return ptx.toSignedTransaction(checkSufficientSignatures = false)
                  -        }
                  +    return ptx.toSignedTransaction(checkSufficientSignatures = false)
                  +}
                   
                  -        private fun assembleSharedTX(tradeRequest: SellerTradeInfo): Pair<TransactionBuilder, List<CompositeKey>> {
                  -            val ptx = TransactionType.General.Builder(notary)
                  +private fun assembleSharedTX(tradeRequest: SellerTradeInfo): Pair<TransactionBuilder, List<CompositeKey>> {
                  +    val ptx = TransactionType.General.Builder(notary)
                   
                  -            // Add input and output states for the movement of cash, by using the Cash contract to generate the states
                  -            val (tx, cashSigningPubKeys) = serviceHub.vaultService.generateSpend(ptx, tradeRequest.price, tradeRequest.sellerOwnerKey)
                  +    // Add input and output states for the movement of cash, by using the Cash contract to generate the states
                  +    val (tx, cashSigningPubKeys) = serviceHub.vaultService.generateSpend(ptx, tradeRequest.price, tradeRequest.sellerOwnerKey)
                   
                  -            // Add inputs/outputs/a command for the movement of the asset.
                  -            tx.addInputState(tradeRequest.assetForSale)
                  +    // Add inputs/outputs/a command for the movement of the asset.
                  +    tx.addInputState(tradeRequest.assetForSale)
                   
                  -            // Just pick some new public key for now. This won't be linked with our identity in any way, which is what
                  -            // we want for privacy reasons: the key is here ONLY to manage and control ownership, it is not intended to
                  -            // reveal who the owner actually is. The key management service is expected to derive a unique key from some
                  -            // initial seed in order to provide privacy protection.
                  -            val freshKey = serviceHub.keyManagementService.freshKey()
                  -            val (command, state) = tradeRequest.assetForSale.state.data.withNewOwner(freshKey.public.composite)
                  -            tx.addOutputState(state, tradeRequest.assetForSale.state.notary)
                  -            tx.addCommand(command, tradeRequest.assetForSale.state.data.owner)
                  +    // Just pick some new public key for now. This won't be linked with our identity in any way, which is what
                  +    // we want for privacy reasons: the key is here ONLY to manage and control ownership, it is not intended to
                  +    // reveal who the owner actually is. The key management service is expected to derive a unique key from some
                  +    // initial seed in order to provide privacy protection.
                  +    val freshKey = serviceHub.keyManagementService.freshKey()
                  +    val (command, state) = tradeRequest.assetForSale.state.data.withNewOwner(freshKey.public.composite)
                  +    tx.addOutputState(state, tradeRequest.assetForSale.state.notary)
                  +    tx.addCommand(command, tradeRequest.assetForSale.state.data.owner)
                   
                  -            // And add a request for timestamping: 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)
                  -            return Pair(tx, cashSigningPubKeys)
                  -        }
                  +    // And add a request for timestamping: 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)
                  +    return Pair(tx, cashSigningPubKeys)
                  +}
                   
                  +

                  This code is longer but no more complicated. Here are some things to pay attention to:

                  1. We do some sanity checking on the received message to ensure we’re being offered what we expected to be offered.
                  2. @@ -710,15 +722,63 @@ may need to be informed. It may be rendered via an API, in a GUI, onto a termina stage in a piece of work. It is therefore typical to use singletons that subclass Step, which may be defined easily in one line when using Kotlin. Typical steps might be “Waiting for response from peer”, “Waiting for signature to be approved”, “Downloading and verifying data” etc.

                    +

                    A flow might declare some steps with code inside the flow class like this:

                    +
                    +
                    open class Buyer(val otherParty: Party,
                    +                 val notary: Party,
                    +                 val acceptablePrice: Amount<Currency>,
                    +                 val typeToBuy: Class<out OwnableState>) : FlowLogic<SignedTransaction>() {
                    +
                    +    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 SWAPPING_SIGNATURES : ProgressTracker.Step("Swapping signatures with the seller")
                    +
                    +    override val progressTracker = ProgressTracker(RECEIVING, VERIFYING, SIGNING, SWAPPING_SIGNATURES)
                    +
                    +
                    +
                    private final ProgressTracker progressTracker = new ProgressTracker(
                    +        CONSTRUCTING_OFFER,
                    +        SENDING_OFFER_AND_RECEIVING_PARTIAL_TRANSACTION,
                    +        VERIFYING
                    +);
                    +
                    +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 VERIFYING = new ProgressTracker.Step(
                    +        "Verifying signatures and contract constraints.");
                    +
                    +
                    +

                    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[step] = tracker map, a tree of steps can be created. It’s allowed to alter the hierarchy +ProgressTracker.childrenFor map, a tree of steps can be created. It’s allowed to alter the hierarchy at runtime, on the fly, and the progress renderers will adapt to that properly. This can be helpful when you don’t -fully know ahead of time what steps will be required. If you _do_ know what is required, configuring as much of the -hierarchy ahead of time is a good idea, as that will help the users see what is coming up.

                    +fully know ahead of time what steps will be required. If you do know what is required, configuring as much of the +hierarchy ahead of time is a good idea, as that will help the users see what is coming up. You can pre-configure +steps by overriding the Step class like this:

                    +
                    +
                            object NOTARY : ProgressTracker.Step("Getting notary signature") {
                    +            override fun childProgressTracker() = FinalityFlow.tracker()
                    +        }
                    +
                    +
                    +
                    private static final ProgressTracker.Step COMMITTING = new ProgressTracker.Step("Committing to the ledger.") {
                    +    @Nullable @Override public ProgressTracker childProgressTracker() {
                    +        return FinalityFlow.Companion.tracker();
                    +    }
                    +};
                    +
                    +
                    +

                    Every tracker has not only the steps given to it at construction time, but also the singleton ProgressTracker.UNSTARTED step and the ProgressTracker.DONE step. Once a tracker has become DONE its position may not be modified again (because e.g. the UI may have been removed/cleaned up), but until that point, the @@ -734,7 +794,7 @@ overriding the flowTrackerFlowLogic.subFlow method is used, then the tracker of the sub-flow will be made a child of the current step in the parent flow automatically, if the parent is using tracking in the first place. The framework will also automatically set the current step to DONE for you, when the flow is finished.

                    -

                    Because a flow may sometimes wish to configure the children in its progress hierarchy _before_ the sub-flow +

                    Because a flow may sometimes wish to configure the children in its progress hierarchy before the sub-flow is constructed, for sub-flows that always follow the same outline regardless of their parameters it’s conventional to define a companion object/static method (for Kotlin/Java respectively) that constructs a tracker, and then allow the sub-flow to have the tracker it will use be passed in as a parameter. This allows all trackers to be built diff --git a/docs/build/html/flow-testing.html b/docs/build/html/flow-testing.html index 6f247d5516..1cb8d1b918 100644 --- a/docs/build/html/flow-testing.html +++ b/docs/build/html/flow-testing.html @@ -34,6 +34,9 @@ + + @@ -104,11 +107,15 @@ API reference: Kotlin/ Key concepts

                    CorDapps

                  +
                  diff --git a/docs/build/html/genindex.html b/docs/build/html/genindex.html index c19891f696..d0154aaa3b 100644 --- a/docs/build/html/genindex.html +++ b/docs/build/html/genindex.html @@ -35,6 +35,9 @@ + + @@ -103,11 +106,15 @@ API reference: Kotlin/ Key concepts

                  CorDapps

                    @@ -145,6 +152,8 @@ API reference: Kotlin/ Other

                    Component library

                    diff --git a/docs/build/html/getting-set-up-fault-finding.html b/docs/build/html/getting-set-up-fault-finding.html index 3ee523c3ba..feb16d4858 100644 --- a/docs/build/html/getting-set-up-fault-finding.html +++ b/docs/build/html/getting-set-up-fault-finding.html @@ -34,6 +34,9 @@ + + @@ -99,21 +102,24 @@ API reference: Kotlin/ What’s included?
                  • Getting set up
                  • Troubleshooting
                      -
                    • IntelliJ issues
                        +
                      • Milestone releases
                      • +
                      • Java issues +
                      • +
                      • IDEA issues
                      • -
                      • Kotlin issues
                      • Running the demos
                      • @@ -121,11 +127,15 @@ API reference: Kotlin/ Key concepts

                        CorDapps

                          @@ -163,6 +173,8 @@ API reference: Kotlin/ Other

                          Component library

                          @@ -230,69 +243,71 @@ API reference: Kotlin/

                          Troubleshooting

                          -
                          -

                          IntelliJ issues

                          +
                          +

                          Milestone releases

                          +

                          When you clone the corda or cordapp-template repos, they will default to the master branch. The master branch is being continuously developed upon, and its features may not align with the state of Corda as described in the docs. Additionally, the master branch of the CorDapp Template may break in response to changes in the main corda repo.

                          +

                          When developing on Corda, you should always check out the latest stable branch instead, by running git checkout release-M7.

                          +
                          +
                          +

                          Java issues

                          +
                          +

                          Outdated/non-Oracle JDKs

                          +

                          Many users have faced issues when running versions of Java that are either outdated, or are produced by organisations other than Oracle (e.g. OpenJDK). The errors generated by these issues will not always clearly point to the JDK as the cause. If in doubt, check your JDK version by following the instructions here. You can download the latest version of Oracle’s JDK here.

                          +
                          +
                          +

                          “Unresolved reference: javafx”

                          +

                          JavaFX is not bundled with OpenJDK. If you are using OpenJDK and get an ‘Unresolved reference: javafx’ error, this means that you need to install OpenJFX. Do this by running sudo apt install openjfx, and possibly sudo apt install libopenjfx-jav.

                          +
                          +
                          +
                          +

                          IDEA issues

                          +
                          +

                          No source files are present

                          +

                          When opening a project in IDEA for the first time, you will need to build the project. You should see “Unlinked Gradle project?” +in a pop-up window in the top-right corner or in a popup alert window. It will also appear in the “Event Log” window which can be +opened by clicking on “Event Log” at the bottom right of the IDEA window. Find one of these links and click on “Import Gradle Project”.

                          +IDEA Gradle Prompt +

                          Wait for it to download the dependencies. You may then see another popup titled “Unindexed remote maven repositories found.” This won’t affect Corda, +so you can choose to leave them unindexed.

                          +

                          If still have problems, the JetBrains website has more information on here.

                          +

                          Run configurations are missing

                          -

                          If you opened the Corda project using “Import” from the IntelliJ splash screen rather than using “Open” and then -importing the Gradle build system from the popup bubble, then a bug in IntelliJ will cause it to wipe and recreate -the .idea directory where the run configurations are stored. The fix is simple and doesn’t require you to -re-import the project: just undelete the files! You can do that by either:

                          +

                          If you opened the Corda project by clicking “Import Project” on the IDEA splash screen rather than clicking “Open”, a bug +in IDEA will cause it to wipe and recreate the .idea directory where the run configurations are stored. The fix is +simple and doesn’t require you to re-import the project: just undelete the files! You can do that by either:

                            -
                          1. Running git checkout .idea/runConfigurations to restore that part of the tree to its normal state.
                          2. -
                          3. Using the “Version Control” pane in IntelliJ to undelete the files via the GUI.
                          4. +
                          5. Running git checkout .idea/runConfigurations to redownload the files.
                          6. +
                          7. Using the “Version Control” pane in IDEA to undelete the files via the GUI.
                          -
                          -

                          If IntelliJ complains about lack of an SDK

                          -

                          If on attempting to open the project (including importing Gradle project), IntelliJ refuses because an SDK was not selected, -you may need to fix the project structure. Do this by following these instructions. The correct JDK is often found at a path such as jdk1.8.0_xx…/Contents/Home

                          -

                          Ensure that you have the Project language level set at as 8. If you are having trouble selecting the correct JDK, the -JetBrains website offers the following guidelines.

                          +
                          +

                          IDEA complains about lack of an SDK

                          +

                          If IDEA refuses to open a project because an SDK has not been selected, you may need to fix the project structure. Do this by following these instructions. The correct JDK is often found on a path such as jdk1.8.0_xx…/Contents/Home. Ensure that you have the Project language level set at 8.

                          +

                          If you are having trouble selecting the correct JDK, the JetBrains website provides the following guidelines.

                          +
                          +
                          +

                          Kotlin plugin

                          +

                          There are two ways to configure Kotlin in IDEA:

                          +
                            +
                          1. Via the initial project opening screen, by using the Configure > Plugins tab.
                          2. +
                          3. From an open IDEA project, by clicking IDEA -> Preferences ... (on OS X) or File -> Settings (on Windows). Select the Plugins bar to confirm that Kotlin is installed and up-to-date.
                          4. +
                          +

                          If you are still having trouble installing Kotlin, first try upgrading the Kotlin plugin. At the time of writing, you can +identify the latest version of the Kotlin plugin on this page.

                          +
                          +
                          -
                          -

                          Kotlin issues

                          -
                          -

                          Installation

                          -

                          There are two ways to configure Kotlin from IntelliJ. One way is via the initial project opening screen in which you will -need to use the Configure > Plugins tab. The other way is when you are in an open project, then you will need to -configure it via (on Mac) IntelliJ -> Preferences ..., whereas on PC it is File -> Settings. Select the plugins -bar, confirm that Kotlin is installed and up to date.

                          -

                          If you are having trouble installing Kotlin, first try upgrading the Kotlin plugin. At the time of writing, you can -confirm what is the latest version of the Kotlin plugin on this page.

                          +
                          +

                          Other common issues

                          +
                          +

                          “xterm: command not found”

                          +

                          On some machines, running the samples requires xterm. You can download it here.

                          -
                          -

                          Gradle issues

                          -
                          -

                          Gradle within IntelliJ

                          -

                          After you have updated your code to the latest version from git, ensure that the gradle project is imported. Although -gradle is used via the command line, it is also integrated with IntelliJ in order for IntelliJ to determine dependencies -and index the project correctly.

                          -

                          When opening a project for the first time, you should see the “Unlinked Gradle project?” pop-up window in the IntelliJ top -right corner or in a popup alert window. If you miss this, it will also appear in the “Event Log” windows which can be -opened by clicking on “Event Log” at the bottom right of the IntelliJ window. Either way, click on “Import Gradle Project”.

                          -IntelliJ Gradle Prompt -

                          Wait for it to think and download the dependencies. After that you might have another popup titled “Unindexed remote maven repositories found.” This is a general IntelliJ question and doesn’t affect Corda, therefore you can decided to index them or not. Next click on the “green arrow” next to “All tests” pop-up on the top toolbar.

                          -

                          The code should build, the unit tests should show as all green.

                          -

                          If still have problems, the JetBrains website has more information on gradle here.

                          -
                          -
                          -

                          Gradle via the CLI

                          -

                          Gradle commands can also be run from the command line - further details of command line gradle can be found here.

                          -
                          -
                          -
                          -

                          Doing it without IntelliJ

                          -

                          If you don’t want to explore or modify the code in a local IDE, you can also just use the command line and a text editor:

                          -
                            -
                          • First run git clone https://github.com/corda/corda to download Corda core source code
                          • -
                          • Next ensure that you are in correct directory cd corda
                          • -
                          • Then you can run ./gradlew test to run the unit tests.
                          • -
                          • Finally remember to run git pull occasionally to upgrade the source code to the latest revision
                          • -
                          -
                          diff --git a/docs/build/html/getting-set-up.html b/docs/build/html/getting-set-up.html index 7bbd36fbce..47c04a59e9 100644 --- a/docs/build/html/getting-set-up.html +++ b/docs/build/html/getting-set-up.html @@ -34,6 +34,9 @@ + + @@ -98,13 +101,19 @@ API reference: Kotlin/
                        • What’s included?
                        • Getting set up
                        • Troubleshooting
                        • @@ -113,11 +122,15 @@ API reference: Kotlin/ Key concepts

                          CorDapps

                            @@ -155,6 +168,8 @@ API reference: Kotlin/ Other

                            Component library

                            @@ -222,76 +238,82 @@ API reference: Kotlin/

                            Getting set up

                            -

                            We have tried to make access to Corda as relatively simple as possible, using industry standard established tools. -Although it is possible to replace any of the recommendations below, we will find it a lot easier to support your efforts -if you follow our guidelines. Saying that, we are also interested in problems that arise due to different configurations.

                            -
                            -

                            A JVM

                            -

                            Corda runs in a JVM and is written predominantly in Kotlin with some example use cases demonstrated in Java that we have -incorporated to demonstrate that Kotlin and Java can work seamlessly together. We recommend the most recent production -version of Java 8. The JDK can be obtained from Oracle. -Other implementations of the JVM are not actively supported, but as mentioned, we are interested in finding out any issues you -do have with them.

                            -
                            -

                            Note

                            -

                            If you are using a JVM implementation other than Oracle’s you may get errors similar to Unresolved reference: javafx. -This means JavaFX is not bundled with the JVM and you will need to install it separately (e.g. OpenJFX is needed -with OpenJDK).

                            -
                            -
                            -
                            -

                            IntelliJ

                            -

                            We strongly recommend the use of IntelliJ’s Development Environment known as IDEA. Download it for free from -JetBrains. The primary reason we recommend this particular IDE is that it integrates -very well with our choice of language for Corda, “Kotlin”, as JetBrains also support the development of Kotlin.

                            -
                            -

                            Warning

                            -

                            When opening the Corda project for the first time from the IntelliJ splash screen, please use “Open” -and then agree to import the Gradle project from the popup bubble. Don’t pick “Import” on the splash screen, -because a bug in IntelliJ will cause the pre-packaged run configurations to be erased. If you see this warning -too late, it’s no problem, just use git checkout .idea/runConfiguration or the version control tab in IntelliJ -to undelete the files.

                            -
                            +
                            +

                            Software requirements

                            +

                            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’re interested to hear about any issues that arise.

                            +
                            +

                            JVM

                            +

                            Corda is written in Kotlin and runs in a JVM. We develop against Oracle JDK 8, and other JVM implementations are not actively +supported. Oracle JDK 8 can be obtained directly from +Oracle. Installation instructions are +available for Windows, +Linux and +OS X.

                            +

                            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.

                            +

                            If you do choose to use OpenJDK instead of Oracle’s JDK, you will also need to install OpenJFX.

                            +

                            Additional troubleshooting information can be found here.

                            -

                            Kotlin

                            -

                            Kotlin is available as a downloadable plugin to IntelliJ. Refer to IntelliJ’s instructions on -getting Started with Kotlin and IntelliJ. Additionally, -if you would like to start getting to grips with the Kotlin language, then we strongly recommend you work through some -of the tutorials (known as “koans”) as well. Also see our Further notes on Kotlin.

                            +

                            Kotlin

                            +

                            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 Further notes on Kotlin.

                            -
                            -

                            Version control via Git

                            -

                            We use git to version control Corda. The authoritative place to obtain git is from the main git website -but it may be the case that your operating system provides git with a supported utility (e.g. for Apple, git is provided along -with XCode - their free development environment). If this is the case, we would recommend you obtain git via that -supported route.

                            -

                            You will need the command line package installed which you can then use natively (via the command line) or via IntelliJ -(in which case you may need to configure IntelliJ to recognise where git has been installed on your system). IntelliJ and -git configuration are quite seamless although the first time you use it, you will have to configure IntelliJ the location -of your git command installation. More details regarding this can be found -on the JetBrains website

                            +
                            +

                            IDE

                            +

                            We strongly recommend the use of IntelliJ IDEA as an IDE, primarily due to the strength of its Kotlin integration. The free Community +Edition can be downloaded from JetBrains.

                            +

                            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.

                            +

                            You’ll also want to install the Kotlin IDEA plugin by following the instructions +here.

                            +

                            Additional troubleshooting information can be found here.

                            +
                            +
                            +

                            Git

                            +

                            We use git to version-control Corda. Instructions on installing git can be found +here.

                            +

                            Following these instructions will give you access to git via the command line. It can also be useful to control git via IDEA. Instructions +for doing so can be found on the JetBrains website.

                            -

                            Gradle

                            -

                            Gradle is our primary means of building Corda and managing dependencies. IntelliJ has its own view of this and occasionally -may need to be resynced from time to time. This can be done within IntelliJ by pressing the “gradle refresh” icon located -on the gradle tab (generally found on the right hand side), or by following the gradle commands specific for the task you -are performing (details expounded later). Whenever prompted about gradle, accept the defaults suggested by IntelliJ.

                            +

                            Gradle

                            +

                            We use Gradle as the build tool for Corda. However, you do not need to install Gradle itself, as a wrapper is provided.

                            +

                            The wrapper can be run from the command line by using ./gradlew [taskName] on OS X/Linux, or gradlew.bat [taskName] on Windows.

                            +

                            Corda source code

                            -

                            You can check out the Corda platform source code from this repository:

                            +

                            The Corda platform source code is available here:

                            -

                            and a template app that you can use as a basis for experimenting with app development from:

                            +

                            and a basic CorDapp that you can use as the basis for your own CorDapps is available here:

                            -

                            You can catch up with the latest code by selecting “VCS -> Update Project” in the IntelliJ menu.

                            +

                            You can clone both of these repos to your local machine by running the command git clone [repo URL].

                            +

                            By default, both repos will be on the master branch. However, this is an unstable development branch. You should check +out the latest milestone release (currently Milestone 7) instead by running git checkout release-M7.

                            +
                            +

                            Opening Corda/CorDapps in IDEA

                            +

                            When opening a Corda project for the first time from the IDEA splash screen, please click “Open” rather than “Import Project”, +and then import the Gradle project by clicking “Import Gradle project” in the popup bubble on the lower right-hand side of the screen. +If you instead pick “Import Project” on the splash screen, a bug in IDEA will cause Corda’s pre-packaged run configurations to be erased.

                            +

                            If you see this warning too late, that’s not a problem - just use git checkout .idea/runConfiguration or the version control tab in +IDEA to undelete the files.

                            +

                            IDEA’s build of the project may need to be resynced from time to time. This can be done from within IDEA by going to “View” -> “Tool Windows” -> “Gradle” +and clicking “Refresh all Gradle projects”. Whenever prompted about Gradle, accept the defaults suggested by IDEA.

                            -
                            -

                            Troubleshooting

                            -

                            See Troubleshooting, or get in touch with us either on the forums or via slack.

                            +
                            +
                            +

                            Next steps

                            +

                            The best way to check that everything is working fine is by Running the demos.

                            +

                            Once you have these demos running, you may be interested in writing your own CorDapps, in which case you should refer to +The CorDapp template.

                            +

                            If you encounter any issues, please see the Troubleshooting page, or get in touch with us on the +forums or via slack.

                            diff --git a/docs/build/html/glossary.html b/docs/build/html/glossary.html index 519f02495b..6c409bc510 100644 --- a/docs/build/html/glossary.html +++ b/docs/build/html/glossary.html @@ -34,6 +34,9 @@ + + @@ -103,11 +106,15 @@ API reference: Kotlin/ Key concepts

                            CorDapps

                            Documentation Contents:

                            -
                            -

                            Getting started

                            +
                            +

                            Getting started

                            • What’s included?
                            • Getting set up
                            • Troubleshooting
                            • Running the demos
                                @@ -278,53 +285,50 @@ platform itself. Find out more about -

                                Key concepts

                                + -
                                -

                                CorDapps

                                +
                                +

                                CorDapps

                                • CorDapp basics
                                  • App plugins
                                  • @@ -349,8 +353,8 @@ platform itself. Find out more about -

                                    The Corda node

                                    +
                                    +

                                    The Corda node

                                    • Client RPC
                                      • Security
                                      • @@ -415,8 +419,8 @@ platform itself. Find out more about -

                                        Tutorials

                                        +
                                        +

                                        Tutorials

                                        • Writing a contract
                                          • Where to put your code
                                          • @@ -507,18 +511,30 @@ platform itself. Find out more about -

                                            Other

                                            + -
                                            -

                                            Component library

                                            +
                                            +

                                            Component library

                                            • Contract catalogue
                                              • Cash
                                              • @@ -535,8 +551,8 @@ platform itself. Find out more about -

                                                Appendix

                                                +
                                                +

                                                Appendix

                                                • Load testing
                                                  • Configuration of the load testing cluster
                                                  • @@ -559,6 +575,7 @@ platform itself. Find out more about Release notes +
                                                  • Further notes on Kotlin
                                                  • Publishing Corda
                                                    • Before Publishing
                                                    • Publishing Locally
                                                    • @@ -601,8 +619,8 @@ platform itself. Find out more about -

                                                      Glossary

                                                      +
                                                      +

                                                      Glossary

                                                      diff --git a/docs/build/html/inthebox.html b/docs/build/html/inthebox.html index b73a2069ab..ea4e5641cb 100644 --- a/docs/build/html/inthebox.html +++ b/docs/build/html/inthebox.html @@ -34,6 +34,9 @@ + + @@ -104,11 +107,15 @@ API reference: Kotlin/ Key concepts

                                                      CorDapps

                                                        @@ -146,6 +153,8 @@ API reference: Kotlin/ Other

                                                        Component library

                                                        diff --git a/docs/build/html/consensus.html b/docs/build/html/key-concepts-consensus-notaries.html similarity index 69% rename from docs/build/html/consensus.html rename to docs/build/html/key-concepts-consensus-notaries.html index e600b949b0..a3cea12b24 100644 --- a/docs/build/html/consensus.html +++ b/docs/build/html/key-concepts-consensus-notaries.html @@ -12,7 +12,7 @@ - Consensus model — R3 Corda latest documentation + Consensus and notaries — R3 Corda latest documentation @@ -34,9 +34,12 @@ + + - - + + @@ -104,10 +107,14 @@ API reference: Kotlin/ Key concepts

                                                          -
                                                        • Data model
                                                        • -
                                                        • Data types
                                                        • -
                                                        • Transaction tear-offs
                                                        • -
                                                        • Consensus model
                                                            +
                                                          • Overview
                                                          • +
                                                          • Corda ecosystem
                                                          • +
                                                          • Data model
                                                          • +
                                                          • Core types
                                                          • +
                                                          • Financial model
                                                          • +
                                                          • Flow framework
                                                          • +
                                                          • Consensus and notaries

                                                            CorDapps

                                                              @@ -155,6 +163,8 @@ API reference: Kotlin/ Other

                                                              Component library

                                                              @@ -206,11 +217,11 @@ API reference: Kotlin/
                                                            • Docs »
                                                            • -
                                                            • Consensus model
                                                            • +
                                                            • Consensus and notaries
                                                            • - View page source + View page source
                                                            • @@ -220,22 +231,34 @@ API reference: Kotlin/
                                                              -
                                                              -

                                                              Consensus model

                                                              -

                                                              The fundamental unit of consensus in Corda is the state. The concept of consensus can be divided into two parts:

                                                              +
                                                              +

                                                              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 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 defining output states is accepted by the contracts pointed to by the states and has all the required signatures. This is achieved by parties independently running the same contract code and validation logic (as described in data model)
                                                              2. -
                                                              3. 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 – a state has not been used as an input by more than one transaction)
                                                              4. +
                                                              5. 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 data model)
                                                              6. +
                                                              7. 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)
                                                              -

                                                              This article presents an initial model for addressing the uniqueness problem.

                                                              Note

                                                              The current model is still a work in progress and everything described in this article can and is likely to change

                                                              +

                                                              Notary

                                                              -

                                                              We introduce the concept of a notary, which is an authority responsible for attesting that for a given transaction, it had not signed another transaction consuming any of its input states. -The data model is extended so that every state has an appointed 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:

                                                              /**
                                                                * 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
                                                              @@ -249,32 +272,36 @@ The data model is extended so that every state has an appointed
                                                               }
                                                               
                                                              -

                                                              All transactions have to be signed by their input state notary for the output states to be valid (apart from issue transactions, containing no input states).

                                                              +

                                                              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 over it, attesting that the outputs are the unique successors of the inputs, -or provides conflict information for any input state that had been consumed by another transaction it had signed before. -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.

                                                              +

                                                              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 the network. This gives the following benefits:

                                                              +

                                                              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
                                                              • +
                                                              • 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
                                                              -

                                                              A transaction should only be signed by a notary if all of its input states point to it. -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 that doesn’t modify anything but the notary pointer of the state. -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)

                                                              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:

                                                              @Suspendable
                                                               fun changeNotary(originalState: StateAndRef<ContractState>,
                                                              @@ -293,53 +320,52 @@ Ensuring that all input states point to the same notary is the responsibility of
                                                               
                                                               

                                                              Note

                                                              -

                                                              Eventually this will be handled automatically on demand.

                                                              +

                                                              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 committing its input states.

                                                              +

                                                              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, validation of a transaction requires the notary to be able to see the full contents of the transaction in question and its dependencies. +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.

                                                              -

                                                              Our platform is flexible and we currently support both validating and non-validating notary implementations – a party can select which one to use based on its own privacy requirements.

                                                              +

                                                              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 +

                                                              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 requested the commit. If the -conflicting transaction is valid, the current one gets aborted; if not - a dispute can be raised and the input states -of the conflicting invalid transaction are “un-committed” (to be covered by legal process).

                                                              +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).

                                                              Note

                                                              -

                                                              At present all notaries can see the entire contents of a transaction, but we have a separate piece of work to -replace the parts of the transaction it does not require knowing about with hashes (only input references, timestamp -information, overall transaction ID and the necessary digests of the rest of the transaction to prove that the -referenced inputs/timestamps really do form part of the stated transaction ID should be visible).

                                                              +

                                                              At present, all notaries can see the entire contents of a submitted transaction. A future piece of work +will enable the processing of Transaction tear-offs, thus providing data hiding of sensitive information.

                                                              Timestamping

                                                              -

                                                              In this model the notary also acts as a timestamping authority, verifying the transaction timestamp command.

                                                              +

                                                              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. +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 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 -as well, or even requesting human signoff. Thus the time observed by the notary may be quite different to the -time observed in step 1.

                                                              -

                                                              For this reason, times in transactions are specified as time windows, not absolute times. 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 for e.g. display purposes, there is a utility method on Timestamp to -calculate the mid point – but in a distributed system there can never be “true time”, only an approximation of it.

                                                              -

                                                              In this way we express 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 +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:

                                                                @@ -352,6 +378,7 @@ meaning the timestamp has to the contract.

                                                                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.

                                                              @@ -362,10 +389,10 @@ clocks at the US Naval Observatory. This time feed is extremely accurate and ava diff --git a/docs/build/html/transaction-data-types.html b/docs/build/html/key-concepts-core-types.html similarity index 70% rename from docs/build/html/transaction-data-types.html rename to docs/build/html/key-concepts-core-types.html index 16d90fda1b..cb72956a21 100644 --- a/docs/build/html/transaction-data-types.html +++ b/docs/build/html/key-concepts-core-types.html @@ -12,7 +12,7 @@ - Data types — R3 Corda latest documentation + Core types — R3 Corda latest documentation @@ -34,9 +34,12 @@ + + - - + + @@ -104,26 +107,28 @@ API reference: Kotlin/ Key concepts

                                                                -
                                                              • Data model
                                                              • -
                                                              • Data types

                                                                CorDapps

                                                                  @@ -161,6 +166,8 @@ API reference: Kotlin/ Other

                                                                  Component library

                                                                  @@ -212,11 +220,11 @@ API reference: Kotlin/
                                                                • Docs »
                                                                • -
                                                                • Data types
                                                                • +
                                                                • Core types
                                                                • - View page source + View page source
                                                                • @@ -226,68 +234,27 @@ API reference: Kotlin/
                                                                  -
                                                                  -

                                                                  Data types

                                                                  -

                                                                  Corda provides a large standard library of data types used in financial transactions and contract state objects. -These provide a common language for states and contracts.

                                                                  -
                                                                  -

                                                                  Amount

                                                                  -

                                                                  The Amount class is used to represent an amount of some -fungible asset. It is a generic class which wraps around a type used to define the underlying product, called -the token. For instance it can be the standard JDK type Currency, or an Issued instance, or this can be -a more complex type such as an obligation contract issuance definition (which in turn contains a token definition -for whatever the obligation is to be settled in).

                                                                  -
                                                                  -

                                                                  Note

                                                                  -

                                                                  Fungible is used here to mean that instances of an asset is interchangeable for any other identical instance, -and that they can be split/merged. For example a £5 note can reasonably be exchanged for any other £5 note, and a -£10 note can be exchanged for two £5 notes, or vice-versa.

                                                                  -
                                                                  -

                                                                  Here are some examples:

                                                                  -
                                                                  -
                                                                  // A quantity of some specific currency like pounds, euros, dollars etc.
                                                                  -Amount<Currency>
                                                                  -// A quantity of currency that is issued by a specific issuer, for instance central bank vs other bank dollars
                                                                  -Amount<Issued<Currency>>
                                                                  -// A quantity of obligations to deliver currency of any issuer.
                                                                  -Amount<Obligation.State<Currency>>
                                                                  -
                                                                  -
                                                                  -
                                                                  -

                                                                  Amount represents quantities as integers. For currencies the quantity represents pennies, cents or whatever -else the smallest integer amount for that currency is. You cannot use Amount to represent negative quantities -or fractional quantities: if you wish to do this then you must use a different type e.g. BigDecimal. Amount -defines methods to do addition and subtraction and these methods verify that the tokens on both sides of the operator -are equal (these are operator overloads in Kotlin and can be used as regular methods from Java). There are also -methods to do multiplication and division by integer amounts.

                                                                  -
                                                                  -
                                                                  -

                                                                  State

                                                                  -

                                                                  A Corda contract is composed of three parts; the executable code, the legal prose, and the state objects that represent -the details of a specific deal or asset (see Data model for further detail). In relational database terms -a state is like a row in a database. 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.

                                                                  +
                                                                  +

                                                                  Core types

                                                                  +

                                                                  Corda provides a large standard library of data types used to represent the 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 Consensus model).

                                                                  +information, such as the notary pointer (see Consensus and notaries).

                                                                  A number of interfaces then extend ContractState, representing standardised functionality for common kinds -of state:

                                                                  +of state such as:

                                                                  -
                                                                  -
                                                                  OwnableState
                                                                  -
                                                                  A state which has an owner (represented as a PublicKey, discussed later). Exposes the owner and a function -for replacing the owner e.g. when an asset is sold.
                                                                  -
                                                                  LinearState
                                                                  -
                                                                  A state which links back to its previous state, creating a thread of states over time. A linear state is -useful when modelling an indivisible/non-fungible thing like a specific deal, or an asset that can’t be -split (like a rare piece of art).
                                                                  -
                                                                  DealState
                                                                  -
                                                                  A LinearState representing an agreement between two or more parties. Intended to simplify implementing generic -flows that manipulate many agreement types.
                                                                  -
                                                                  FixableDealState
                                                                  -
                                                                  A deal state, with further functions exposed to support fixing of interest rates.
                                                                  -
                                                                  +

                                                                  OwnableState +A state which has an owner (represented as 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.

                                                                  @@ -301,29 +268,26 @@ This is a combination of a (Java) -

                                                                  FungibleAssets and Cash

                                                                  -

                                                                  There is a common FungibleAsset superclass for contracts which model fungible assets, which also provides a standard -interface for its subclasses’ state objects to implement. The clear use-case is Cash, however FungibleAsset is -intended to be readily extensible to cover other assets, for example commodities could be modelled by using a subclass -whose state objects include further details (location of the commodity, origin, grade, etc.) as needed.

                                                                  -

                                                                  Transaction lifecycle types

                                                                  The WireTransaction class contains the core of a transaction without signatures, and with references to attachments -in place of the attachments themselves (see also Data model). Once signed these are encapsulated in the -SignedTransaction class. For processing a transaction (i.e. to verify it) it is first converted to a +in place of the attachments themselves (see also Data model). Once signed these are encapsulated in the +SignedTransaction class. 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 contracts be run, and thus could be contract-invalid -(but not signature-invalid). You can use the verify method as shown below to run the contracts.

                                                                  +

                                                                  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 modification of the internals is complete. It is typical for contract classes to expose helper -methods that can contribute to a TransactionBuilder.

                                                                  +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, this class can be used as a holding bucket to gather signatures from multiple parties. +It is typical for contract classes to expose helper methods that can contribute to a TransactionBuilder. Once a transaction +has been constructed using the builders toWireTransaction or toSignedTransaction function, it shared with other +participants using the 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):

                                                                  @@ -343,37 +307,36 @@ contract type in the library):

                                                                  In a unit test, you would typically use a freshly created MockServices object, or more realistically, you would write your tests using the domain specific language for writing tests.

                                                                  -
                                                                  -

                                                                  Party and PublicKey

                                                                  +
                                                                  +

                                                                  Party and CompositeKey

                                                                  Entities using the network are called parties. Parties can sign structures using keys, and a party may have many keys under their control.

                                                                  -

                                                                  Parties may sometimes be identified pseudonymously, for example, in a transaction sent to your node as part of a +

                                                                  Parties may sometimes be identified pseudonymously. For example, in a transaction sent to your node as part of a chain of custody it is important you can convince yourself of the transaction’s validity, but equally important that you don’t learn anything about who was involved in that transaction. In these cases a public key may be present without any identifying information about who owns it.

                                                                  -

                                                                  Identities of parties involved in signing a transaction can be represented simply by a PublicKey, or by further +

                                                                  Identities of parties involved in signing a transaction can be represented simply by a CompositeKey, or by further information (such as name) using the Party class. An AuthenticatedObject represents an object (like a command) that has been signed by a set of parties.

                                                                  Note

                                                                  -

                                                                  These types are provisional and will change significantly in future as the identity framework becomes more -fleshed out.

                                                                  +

                                                                  These types are provisional and will change significantly in future as the identity framework becomes more fleshed out.

                                                                  -

                                                                  Multi-signature support

                                                                  +

                                                                  Multi-signature support

                                                                  Corda supports scenarios where more than one key or party is required to authorise a state object transition, for example: “Either the CEO or 3 out of 5 of his assistants need to provide signatures”.

                                                                  -
                                                                  -

                                                                  Composite Keys

                                                                  +
                                                                  +

                                                                  Composite Keys

                                                                  This is achieved by public key composition, using a tree data structure CompositeKey. A CompositeKey is a tree that stores the cryptographic public key primitives in its leaves and the composition logic in the intermediary nodes. Every intermediary node specifies a threshold of how many child signatures it requires.

                                                                  An illustration of an “either Alice and Bob, or Charlie” composite key:

                                                                  -_images/composite-key.png +_images/composite-key.png

                                                                  To allow further flexibility, each child node can have an associated custom weight (the default is 1). The threshold then specifies the minimum total weight of all children required. Our previous example can also be expressed as:

                                                                  -_images/composite-key-2.png +_images/composite-key-2.png

                                                                  Verification

                                                                  @@ -390,7 +353,7 @@ the composite key requirement is considered to be met.

                                                                  Date support

                                                                  -

                                                                  There are a number of supporting interfaces and classes for use by contract which deal with dates (especially in the +

                                                                  There are a number of supporting interfaces and classes for use by contracts which deal with dates (especially in the context of deadlines). As contract negotiation typically deals with deadlines in terms such as “overnight”, “T+3”, etc., it’s desirable to allow conversion of these terms to their equivalent deadline. Tenor models the interval before a deadline, such as 3 days, etc., while DateRollConvention describes how deadlines are modified to take @@ -401,12 +364,12 @@ bank holidays). The BusinessCal from files on disk, but in future this is likely to involve reference data oracles in order to ensure consensus on the dates used.

                                                                  -
                                                                  -

                                                                  Cryptography & maths support

                                                                  +
                                                                  +

                                                                  Cryptography and maths support

                                                                  The SecureHash class represents a secure hash of unknown algorithm. We currently define only a single subclass, SecureHash.SHA256. There are utility methods to create them, parse them and so on.

                                                                  We also provide some mathematical utilities, in particular a set of interpolators and classes for working with -splines. These can be found in the maths package.

                                                                  +splines. These can be found in the maths package.

                                                                  @@ -417,10 +380,10 @@ splines. These can be found in the - Next + Next - Previous + Previous
                                                                  diff --git a/docs/build/html/key-concepts-data-model.html b/docs/build/html/key-concepts-data-model.html new file mode 100644 index 0000000000..722202b995 --- /dev/null +++ b/docs/build/html/key-concepts-data-model.html @@ -0,0 +1,445 @@ + + + + + + + + + + + + + + Data model — R3 Corda latest documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                                  + + + + +
                                                                  + + + + + + +
                                                                  +
                                                                  + + + + + + +
                                                                  + +
                                                                  +
                                                                  +
                                                                  +
                                                                  + +
                                                                  +

                                                                  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 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:

                                                                  +_images/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 Clauses which provide a means of re-using common +verification logic.

                                                                  +
                                                                  +
                                                                  +

                                                                  Transactions

                                                                  +

                                                                  Transaction 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:

                                                                  +
                                                                  +
                                                                    +
                                                                  1. 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
                                                                  2. +
                                                                  3. 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.
                                                                  4. +
                                                                  +
                                                                  +

                                                                  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 ” Writing a 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. Transaction tear-offs 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).

                                                                  +
                                                                  +
                                                                  +
                                                                  + + +
                                                                  +
                                                                  + + +
                                                                  +
                                                                  + +
                                                                  + +
                                                                  + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/build/html/key-concepts-ecosystem.html b/docs/build/html/key-concepts-ecosystem.html new file mode 100644 index 0000000000..31498adced --- /dev/null +++ b/docs/build/html/key-concepts-ecosystem.html @@ -0,0 +1,340 @@ + + + + + + + + + + + + + + Corda ecosystem — R3 Corda latest documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                                  + + + + +
                                                                  + + + + + + +
                                                                  +
                                                                  + + + + + + +
                                                                  + +
                                                                  +
                                                                  +
                                                                  +
                                                                  + +
                                                                  +

                                                                  Corda ecosystem

                                                                  +

                                                                  A Corda network consists of the following components:

                                                                  +
                                                                    +
                                                                  • 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.
                                                                  • +
                                                                  +

                                                                  These components are illustrated in the following diagram:

                                                                  +_images/cordaNetwork.png +

                                                                  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 IRS demo and Trader demo), portfolio valuations (see SIMM and Portfolio Demo - aka the Initial Margin Agreement Demo), trade finance, +post-trade order matching, KYC/AML, etc.

                                                                  +
                                                                  +
                                                                  + + +
                                                                  +
                                                                  + + +
                                                                  +
                                                                  + +
                                                                  + +
                                                                  + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/build/html/key-concepts-financial-model.html b/docs/build/html/key-concepts-financial-model.html new file mode 100644 index 0000000000..17204568ce --- /dev/null +++ b/docs/build/html/key-concepts-financial-model.html @@ -0,0 +1,363 @@ + + + + + + + + + + + + + + Financial model — R3 Corda latest documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                                  + + + + +
                                                                  + + + + + + +
                                                                  +
                                                                  + + + + + + +
                                                                  + +
                                                                  +
                                                                  +
                                                                  +
                                                                  + +
                                                                  +

                                                                  Financial model

                                                                  +

                                                                  Corda provides a large standard library of data types used in financial applications and contract state objects. +These provide a common language for states and contracts.

                                                                  +
                                                                  +

                                                                  Amount

                                                                  +

                                                                  The Amount class is used to represent an amount of some +fungible asset. It is a generic class which wraps around a type used to define the underlying product, called +the token. For instance it can be the standard JDK type Currency, or an Issued instance, or this can be +a more complex type such as an obligation contract issuance definition (which in turn contains a token definition +for whatever the obligation is to be settled in).

                                                                  +
                                                                  +

                                                                  Note

                                                                  +

                                                                  Fungible is used here to mean that instances of an asset is interchangeable for any other identical instance, +and that they can be split/merged. For example a £5 note can reasonably be exchanged for any other £5 note, and +a £10 note can be exchanged for two £5 notes, or vice-versa.

                                                                  +
                                                                  +

                                                                  Here are some examples:

                                                                  +
                                                                  +
                                                                  // A quantity of some specific currency like pounds, euros, dollars etc.
                                                                  +Amount<Currency>
                                                                  +// A quantity of currency that is issued by a specific issuer, for instance central bank vs other bank dollars
                                                                  +Amount<Issued<Currency>>
                                                                  +// A quantity of a product governed by specific obligation terms
                                                                  +Amount<Obligation.Terms<P>>
                                                                  +
                                                                  +
                                                                  +
                                                                  +

                                                                  Amount represents quantities as integers. For currencies the quantity represents pennies, cents or whatever +else the smallest integer amount for that currency is. You cannot use Amount to represent negative quantities +or fractional quantities: if you wish to do this then you must use a different type e.g. BigDecimal. Amount +defines methods to do addition and subtraction and these methods verify that the tokens on both sides of the operator +are equal (these are operator overloads in Kotlin and can be used as regular methods from Java). There are also +methods to do multiplication and division by integer amounts.

                                                                  +

                                                                  Issued refers to a product (which can be cash, a cash-like thing, assets, or generally anything else that’s +quantifiable with integer quantities) and an associated PartyAndReference that describes the issuer of that contract. +An issued product typically follows a lifecycle which includes issuance, movement and exiting from the ledger (for example, +see the Cash contract and its associated state and commands)

                                                                  +
                                                                  +
                                                                  +

                                                                  Financial states

                                                                  +

                                                                  In additional to the common state types, a number of interfaces extend ContractState to model financial state such as:

                                                                  +
                                                                  +
                                                                  +
                                                                  LinearState
                                                                  +
                                                                  A state which has a unique identifier beyond its StateRef and carries it through state transitions. +Such a state cannot be duplicated, merged or split in a transaction: only continued or deleted. A linear state is +useful when modelling an indivisible/non-fungible thing like a specific deal, or an asset that can’t be +split (like a rare piece of art).
                                                                  +
                                                                  DealState
                                                                  +
                                                                  A LinearState representing an agreement between two or more parties. Intended to simplify implementing generic +protocols that manipulate many agreement types.
                                                                  +
                                                                  FungibleAsset
                                                                  +
                                                                  A FungibleAsset is intended to be used for contract states representing assets which are fungible, countable and issued by a +specific party. States contain assets which are equivalent (such as cash of the same currency), so records of their existence +can be merged or split as needed where the issuer is the same. For instance, dollars issued by the Fed are fungible and +countable (in cents), barrels of West Texas crude are fungible and countable (oil from two small containers can be poured into one large +container), shares of the same class in a specific company are fungible and countable, and so on.
                                                                  +
                                                                  +
                                                                  +

                                                                  The following diagram illustrates the complete Contract State hierarchy:

                                                                  +_images/financialContractStateModel.png +

                                                                  Note there are currently two packages, a core library and a finance model specific library. +Developers may re-use or extend the Finance types directly or write their own by extending the base types from the Core library.

                                                                  +
                                                                  +
                                                                  + + +
                                                                  +
                                                                  + + +
                                                                  +
                                                                  + +
                                                                  + +
                                                                  + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/build/html/key-concepts-flow-framework.html b/docs/build/html/key-concepts-flow-framework.html new file mode 100644 index 0000000000..3e319dd8a7 --- /dev/null +++ b/docs/build/html/key-concepts-flow-framework.html @@ -0,0 +1,323 @@ + + + + + + + + + + + + + + Flow framework — R3 Corda latest documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                                  + + + + +
                                                                  + + + + + + +
                                                                  +
                                                                  + + + + + + +
                                                                  + +
                                                                  +
                                                                  +
                                                                  +
                                                                  + +
                                                                  +

                                                                  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:

                                                                  +_images/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)
                                                                  • +
                                                                  +
                                                                  + + +
                                                                  +
                                                                  + + +
                                                                  +
                                                                  + +
                                                                  + +
                                                                  + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/build/html/key-concepts-security-model.html b/docs/build/html/key-concepts-security-model.html new file mode 100644 index 0000000000..29f99c6a91 --- /dev/null +++ b/docs/build/html/key-concepts-security-model.html @@ -0,0 +1,345 @@ + + + + + + + + + + + + + + Security model — R3 Corda latest documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                                  + + + + +
                                                                  + + + + + + +
                                                                  +
                                                                  + + + + + + +
                                                                  + +
                                                                  +
                                                                  +
                                                                  +
                                                                  + +
                                                                  +

                                                                  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

                                                                  +

                                                                  Future notary algorithms may include BFT and hardware assisted non-BFT algorithms (where non-BFT algorithms +are converted into a more trusted form using remote attestation and hardware protection).

                                                                  +
                                                                  +
                                                                    +
                                                                  • Authentication, authorisation and entitlements: +Network permissioning, including node to node authentication, is performed using TLS and certificates. +See Network 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. +This is subject to design review with views to selecting a proven, mature entitlements solution.

                                                                  +
                                                                  +

                                                                  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 Transaction tear-offs 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.

                                                                  +
                                                                  +
                                                                  + + +
                                                                  +
                                                                  + + +
                                                                  +
                                                                  + +
                                                                  + +
                                                                  + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/build/html/key-concepts-vault.html b/docs/build/html/key-concepts-vault.html new file mode 100644 index 0000000000..d496b282eb --- /dev/null +++ b/docs/build/html/key-concepts-vault.html @@ -0,0 +1,340 @@ + + + + + + + + + + + + + + Vault — R3 Corda latest documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                                  + + + + +
                                                                  + + + + + + +
                                                                  +
                                                                  + + + + + + +
                                                                  + +
                                                                  +
                                                                  +
                                                                  +
                                                                  + +
                                                                  +

                                                                  Vault

                                                                  +

                                                                  The vault contains data extracted from the ledger that is considered relevant to the node’s owner, stored in a relational model +that can be easily queried and worked with.

                                                                  +

                                                                  The vault keeps track of both unconsumed and consumed states:

                                                                  +
                                                                  +
                                                                    +
                                                                  • Unconsumed (or unspent) states represent fungible states available for spending (including spend-to-self transactions) +and linear states available for evolution (eg. in response to a lifecycle event on a deal) or transfer to another party.
                                                                  • +
                                                                  • Consumed (or spent) states represent ledger immutable state for the purpose of transaction reporting, audit and archival, including the ability to perform joins with app-private data (like customer notes)
                                                                  • +
                                                                  +
                                                                  +

                                                                  By fungible we refer to assets of measurable quantity (eg. a cash currency, units of stock) which can be combined +together to represent a single ledger state.

                                                                  +

                                                                  Like with a cryptocurrency wallet, the Corda vault can create transactions that send value (eg. transfer of state) to someone else +by combining fungible states and possibly adding a change output that makes the values balance (this process is usually referred to as ‘coin selection’). +Vault spending ensures that transactions respect the fungibility rules in order to ensure that the issuer and reference data is preserved as the assets pass from hand to hand.

                                                                  +
                                                                  +

                                                                  Note

                                                                  +

                                                                  Basic ‘coin selection’ is currently implemented. Future work includes fungible state optimisation (splitting and +merging of states in the background), ‘soft locking’ (ability to automatically or explicitly reserve states to prevent +multiple transactions trying to use the same output simultaneously), ‘state re-issuance’ (sending of states back to the +issuer for re-issuance, thus pruning long transaction chains and improving privacy).

                                                                  +
                                                                  +

                                                                  There is also a facility for attaching descriptive textual notes against any transaction stored in the vault.

                                                                  +

                                                                  The vault supports the management of data in both authoritative (“on-ledger”) form and, where appropriate, shadow (“off-ledger”) form:

                                                                  +
                                                                    +
                                                                  • “On-ledger” data refers to distributed ledger state (cash, deals, trades) to which a firm is participant.
                                                                  • +
                                                                  • “Off-ledger” data refers to a firm’s internal reference, static and systems data.
                                                                  • +
                                                                  +

                                                                  The following diagram illustrates the breakdown of the vault into sub-system components:

                                                                  +_images/vault.png +

                                                                  Note the following:

                                                                  +
                                                                    +
                                                                  • the vault “On Ledger” store tracks unconsumed state and is updated internally by the node upon recording of a transaction on the ledger +(following successful smart contract verification and signature by all participants)
                                                                  • +
                                                                  • the vault “Off Ledger” store refers to additional data added by the node owner subsequent to transaction recording
                                                                  • +
                                                                  • the vault performs fungible state spending (and in future, fungible state optimisation management including merging, splitting and re-issuance)
                                                                  • +
                                                                  • vault extensions represent additional custom plugin code a developer may write to query specific custom contract state attributes.
                                                                  • +
                                                                  • customer “Off Ledger” (private store) represents internal organisational data that may be joined with the vault data to perform additional reporting or processing
                                                                  • +
                                                                  • a vault query API is exposed to developers using standard Corda RPC and CorDapp plugin mechanisms
                                                                  • +
                                                                  • a vault update API is internally used by transaction recording flows.
                                                                  • +
                                                                  • the vault database schemas are directly accessible via JDBC for customer joins and queries
                                                                  • +
                                                                  +

                                                                  Section 8 of the Technical white paper describes features of the vault yet to be implemented including private key managament, +soft state locking, state splitting and merging, asset re-issuance and node event scheduling.

                                                                  +
                                                                  + + +
                                                                  +
                                                                  + + +
                                                                  +
                                                                  + +
                                                                  + +
                                                                  + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/build/html/key-concepts.html b/docs/build/html/key-concepts.html new file mode 100644 index 0000000000..45b6fc9f63 --- /dev/null +++ b/docs/build/html/key-concepts.html @@ -0,0 +1,316 @@ + + + + + + + + + + + + + + Overview — R3 Corda latest documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                                  + + + + +
                                                                  + + + + + + +
                                                                  +
                                                                  + + + + + + +
                                                                  + +
                                                                  +
                                                                  +
                                                                  +
                                                                  + +
                                                                  +

                                                                  Overview

                                                                  +

                                                                  This section describes the fundamental concepts and features that underpin the Corda platform, to include:

                                                                  +
                                                                  +
                                                                  +

                                                                  Detailed thinking and rationale behind these concepts are presented in the following published white papers:

                                                                  +
                                                                  +
                                                                  +
                                                                  + + +
                                                                  +
                                                                  + + +
                                                                  +
                                                                  + +
                                                                  + +
                                                                  + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/build/html/loadtesting.html b/docs/build/html/loadtesting.html index 63774f7660..f9606af73e 100644 --- a/docs/build/html/loadtesting.html +++ b/docs/build/html/loadtesting.html @@ -34,6 +34,9 @@ + + @@ -104,11 +107,15 @@ API reference: Kotlin/ Key concepts

                                                                  CorDapps

                                                                  Key concepts

                                                                  -
                                                                  diff --git a/docs/build/html/messaging.html b/docs/build/html/messaging.html index 929f97c880..a67be36d85 100644 --- a/docs/build/html/messaging.html +++ b/docs/build/html/messaging.html @@ -34,6 +34,9 @@ + + @@ -104,11 +107,15 @@ API reference: Kotlin/ Key concepts

                                                                  CorDapps

                                                                  Component library

                                                                  @@ -281,7 +291,7 @@ of the window.

    -_images/vault.png +_images/vault1.png
    New Transactions

    This is where you can create new cash transactions. diff --git a/docs/build/html/node-services.html b/docs/build/html/node-services.html index 0fbfd3db77..bdc5106a01 100644 --- a/docs/build/html/node-services.html +++ b/docs/build/html/node-services.html @@ -34,6 +34,9 @@ + + @@ -104,11 +107,15 @@ API reference: Kotlin/ Key concepts

    CorDapps

      @@ -184,6 +191,8 @@ API reference: Kotlin/ Other

      Component library

      diff --git a/docs/build/html/objects.inv b/docs/build/html/objects.inv index a845d992d0..a0758322ad 100644 Binary files a/docs/build/html/objects.inv and b/docs/build/html/objects.inv differ diff --git a/docs/build/html/oracles.html b/docs/build/html/oracles.html index 06672efd08..5b48af4a45 100644 --- a/docs/build/html/oracles.html +++ b/docs/build/html/oracles.html @@ -34,6 +34,9 @@ + + @@ -104,11 +107,15 @@ API reference: Kotlin/ Key concepts

      CorDapps

        @@ -162,6 +169,8 @@ API reference: Kotlin/ Other

        Component library

        diff --git a/docs/build/html/permissioning.html b/docs/build/html/permissioning.html index ee76269293..47615e10e1 100644 --- a/docs/build/html/permissioning.html +++ b/docs/build/html/permissioning.html @@ -34,6 +34,9 @@ + + @@ -104,11 +107,15 @@ API reference: Kotlin/ Key concepts

        CorDapps

          @@ -151,6 +158,8 @@ API reference: Kotlin/ Other

          Component library

          diff --git a/docs/build/html/persistence.html b/docs/build/html/persistence.html index dc2eedc37e..499c629708 100644 --- a/docs/build/html/persistence.html +++ b/docs/build/html/persistence.html @@ -34,6 +34,9 @@ + + @@ -104,11 +107,15 @@ API reference: Kotlin/ Key concepts

          CorDapps

            @@ -150,6 +157,8 @@ API reference: Kotlin/ Other

            Component library

            diff --git a/docs/build/html/publishing-corda.html b/docs/build/html/publishing-corda.html index 529f06c70b..407d5a262b 100644 --- a/docs/build/html/publishing-corda.html +++ b/docs/build/html/publishing-corda.html @@ -34,9 +34,12 @@ + + - + @@ -104,11 +107,15 @@ API reference: Kotlin/ Key concepts

            CorDapps

              @@ -146,6 +153,8 @@ API reference: Kotlin/ Other

              Component library

                @@ -161,6 +170,7 @@ API reference: Kotlin/ Release notes
              • Code style guide
              • Building the documentation
              • +
              • Further notes on Kotlin
              • Publishing Corda
                • Before Publishing
                • Publishing Locally
                • @@ -313,7 +323,7 @@ and asking if you wish to publish. You can now publish to Bintray and Jcenter by Next - Previous + Previous diff --git a/docs/build/html/release-notes.html b/docs/build/html/release-notes.html index ac722f3020..21a42d326a 100644 --- a/docs/build/html/release-notes.html +++ b/docs/build/html/release-notes.html @@ -34,6 +34,9 @@ + + @@ -104,11 +107,15 @@ API reference: Kotlin/ Key concepts

                  CorDapps

                    @@ -146,6 +153,8 @@ API reference: Kotlin/ Other

                    Component library

                      @@ -159,6 +168,7 @@ API reference: Kotlin/ Secure coding guidelines
                    • Release process
                    • Release notes @@ -224,6 +235,19 @@ API reference: Kotlin/

                      Release notes

                      Here are brief summaries of what’s changed between each snapshot release.

                      +
                      +

                      Milestone 8

                      +
                        +
                      • API:

                        +
                        +
                          +
                        • Party equality is now based on the owning key, rather than the owning key and name. This is important for +party anonymisation to work, as each key must identify exactly one party.
                        • +
                        +
                        +
                      • +
                      +

                      Milestone 7

                        @@ -315,7 +339,7 @@ log entries.
                    • Data model: A party is now identified by a composite key (formerly known as a “public key tree”) instead of a single public key. -Read more in Multi-signature support. This allows expressing distributed service identities, e.g. a distributed notary. +Read more in Composite Keys. This allows expressing distributed service identities, e.g. a distributed notary. In the future this will also allow parties to use multiple signing keys for their legal identity.

                    • Decentralised consensus: A prototype RAFT based notary composed of multiple nodes has been added. This implementation @@ -458,7 +482,7 @@ based on identities rather than node IP addresses.

                    • 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 “Data types” article. +key trees in the “transaction-data-types” article.
                    • A new tutorial has been added showing how to use transaction attachments in more detail.
                    @@ -692,8 +716,8 @@ sure it compiles across refactorings.

                    We have new documentation on:

                    Summary of API changes (not exhaustive):

                      diff --git a/docs/build/html/release-process.html b/docs/build/html/release-process.html index 02384462c7..20070635ba 100644 --- a/docs/build/html/release-process.html +++ b/docs/build/html/release-process.html @@ -34,6 +34,9 @@ + + @@ -104,11 +107,15 @@ API reference: Kotlin/ Key concepts

                      CorDapps

                        @@ -146,6 +153,8 @@ API reference: Kotlin/ Other

                        Component library

                        diff --git a/docs/build/html/running-a-notary.html b/docs/build/html/running-a-notary.html index cbf025eb62..5b133545c0 100644 --- a/docs/build/html/running-a-notary.html +++ b/docs/build/html/running-a-notary.html @@ -34,6 +34,9 @@ + + @@ -104,11 +107,15 @@ API reference: Kotlin/ Key concepts

                        CorDapps

                          @@ -146,6 +153,8 @@ API reference: Kotlin/ Other

                          Component library

                          diff --git a/docs/build/html/running-the-demos.html b/docs/build/html/running-the-demos.html index 33c41afa1e..4ee101c4a9 100644 --- a/docs/build/html/running-the-demos.html +++ b/docs/build/html/running-the-demos.html @@ -34,6 +34,9 @@ + + @@ -117,11 +120,15 @@ API reference: Kotlin/ Key concepts

                          CorDapps

                            @@ -159,6 +166,8 @@ API reference: Kotlin/ Other

                            Component library

                            @@ -250,7 +260,7 @@ extend the demos. For more details about running via the command line or from wi

                            If any of the demos don’t work, please raise an issue on GitHub.

                            -

                            Trader demo

                            +

                            Trader demo

                            This demo brings up four nodes: Bank A, Bank B, Bank Of Corda, and a notary/network map node that they all use. Bank A will be the buyer, and requests some cash from the Bank of Corda in order to acquire commercial paper from Bank B, the seller.

                            To run from the command line in Unix:

                            @@ -283,7 +293,7 @@ trade print their progress and final transaction state in the bank node tabs/win
                            -

                            IRS demo

                            +

                            IRS demo

                            This demo brings up three nodes: Bank A, Bank B and a node that simultaneously runs a notary, a network map and an interest rates oracle. The two banks agree on an interest rate swap, and then do regular fixings of the deal as the time on a simulated clock passes.

                            @@ -405,7 +415,7 @@ major version - even if still in beta.

                          • The H2 web console should start up in a web browser tab. To connect we first need to obtain a JDBC connection string. Each node outputs its connection string in the terminal window as it starts up. In a terminal window where a node is running, look for the following string:

                            -

                            Database connection url is              : jdbc:h2:tcp://10.18.0.150:56736/node

                            +

                            Database connection url is              : jdbc:h2:tcp://10.18.0.150:56736/node

                            You can use the string on the right to connect to the h2 database: just paste it into the JDBC URL field and click Connect. You will be presented with a web application that enumerates all the available tables and provides an interface for you to query them using SQL

                          • @@ -483,7 +493,7 @@ For example, the Explorer tool only allows nodes of this type to issue and exit

                            See https://docs.corda.net/node-explorer.html for further details on usage.

                            -

                            SIMM and Portfolio Demo - aka the Initial Margin Agreement Demo

                            +

                            SIMM and Portfolio Demo - aka the Initial Margin Agreement Demo

                            Background and SIMM Introduction

                            This app is a demonstration of how Corda can be used for the real world requirement of initial margin calculation and diff --git a/docs/build/html/search.html b/docs/build/html/search.html index 4a0028f764..63ce4c284f 100644 --- a/docs/build/html/search.html +++ b/docs/build/html/search.html @@ -34,6 +34,9 @@ + + @@ -102,11 +105,15 @@ API reference: Kotlin/ Key concepts

                            CorDapps

                              @@ -144,6 +151,8 @@ API reference: Kotlin/ Other

                              Component library

                              diff --git a/docs/build/html/searchindex.js b/docs/build/html/searchindex.js index 53141eb4a5..0681a33a95 100644 --- a/docs/build/html/searchindex.js +++ b/docs/build/html/searchindex.js @@ -1 +1 @@ -Search.setIndex({envversion:49,filenames:["CLI-vs-IDE","azure-vm","building-the-docs","clauses","clientrpc","codestyle","consensus","contract-catalogue","contract-irs","corda-configuration-file","corda-plugins","creating-a-cordapp","data-model","event-scheduling","flow-state-machines","flow-testing","further-notes-on-kotlin","getting-set-up","getting-set-up-fault-finding","glossary","index","inthebox","loadtesting","merkle-trees","messaging","network-simulator","node-administration","node-explorer","node-services","oracles","permissioning","persistence","publishing-corda","release-notes","release-process","running-a-notary","running-the-demos","secure-coding-guidelines","setting-up-a-corda-network","transaction-data-types","tutorial-attachments","tutorial-building-transactions","tutorial-clientrpc-api","tutorial-contract","tutorial-contract-clauses","tutorial-cordapp","tutorial-integration-testing","tutorial-test-dsl","using-a-notary"],objects:{},objnames:{},objtypes:{},terms:{"00z":43,"0_xx":18,"10000l":22,"100l":46,"14gb":1,"17t16":43,"1mb":14,"200mb":26,"3rd":36,"5000l":22,"500mb":26,"5xxx":0,"___":45,"____":45,"______":45,"_________":45,"_before_":14,"_do_":14,"_foo":5,"_unless_":32,"abstract":[3,10,12,14,28,29,31,33,43,44,45],"boolean":[12,15,22,33,42,43,44],"break":[14,29,34,41],"byte":[5,12,14,29,33,47],"case":[3,5,6,10,11,12,14,15,17,22,24,29,31,33,36,39,40,43,44,45],"catch":[5,14,17,33,37],"class":3,"default":[1,4,5,7,9,10,11,14,17,19,22,23,25,26,27,28,30,33,36,37,38,39,43,45],"enum":[33,42],"export":[14,26,31],"fa\u00e7ad":26,"final":[6,8,10,12,14,15,18,23,29,33,36,38,41,42,43,44,46,47],"float":[7,8,13],"function":[0,3,5,7,8,10,12],"import":[3,5,12,13,14,17,18,24,29,31,33,36,38,39,41,43,44,45,47],"instanceof":[43,44],"int":[5,22,31,43,48],"long":[5,7,10,12,13,22,31,41,43,44,45],"new":[0,1,5,6,8,9,10,11,12,14,16,20,24,25,26,27,28,30,32,33,34,36,39,40,41,42,43,44,45,46,47,48],"null":[9,13,15,22,29,31,40,43,44,47,48],"public":[1,5,9,11,12,14,19,21,24,26,28,30,33,36,38,39,43,44,45,47],"return":[3,4,5,6,8,10,13,14,15,22,26,28,29,31,33,37,40,41,42,43,44,45,46,47,48],"short":[3,13,34,36],"static":[10,11,12,14,29,36,43,45,47],"super":[3,5,44],"switch":[14,33,43],"throw":[3,4,5,14,22,23,29,41,43,44,48],"transient":14,"true":[6,9,12,15,19,22,29,30,38,42,43,44,45],"try":[0,4,5,12,14,18,32,33,35,42,45],"var":[15,31,41,42],"void":[43,44,47],"while":[25,36,39,42,47],abil:[12,25,33],abl:[1,6,9,11,12,14,23,24,26,27,28,29,30,33,36,43,45,48],abort:[6,29,41],about:[0,1,5,6,10,12,14,16,17],abov:[1,3,5,8,12,14,23,24,26,29,36,38,42,43,44,45,46,47],absent:[3,9],absolut:[6,9,12],abstractnod:[10,28],abstractstatereplacementprotocol:33,accept:[5,6,7,12,17,19,29,36,41,43],acceptablepric:14,acceptsfileupload:29,access:[1,4,5,9,10,14,17,20,22,24],accid:14,accident:[5,37,41],accompani:[5,43],accord:[3,41],accordingli:[38,44],account:[1,12,22,32,33,39,40],accrual:8,accur:[6,36],accuraci:12,achiev:[6,12,23,39],ack:33,acknowledg:[14,28],acquir:36,acronym:36,across:[7,9,12,22,28,31,33,36,40,41],act:[3,6,9,12,14,28,29,33,36],action:[3,13,22,28,29,35,36,41,43,46],activ:[8,9,10,13,17,22,25,28,31,33,36,41,43,45],actor:[5,12,14],actual:[6,8,14,22,28,29,36,37,40,43,44,47,48],adapt:[5,14,29],add:[3,5,11,12,14,19,22,23,24,26,28,29,35,37,40,41,42,43,45,46,47,48],addattach:[15,40],addcommand:[14,29,41,43,48],added:33,addedg:42,addfix:29,adding:20,addinputst:[14,43],addit:[0,5,6,9,11,12,24,28,31,33,39,41,42,43,45],addition:[12,14,16,17,20,31,34,36,45],addmessagehandl:33,addnod:42,addoutputst:[14,43,48],address:[0,1,6,9,11,12,14,24,27,28,33,38,43,45],addsignatureuncheck:29,adequ:3,adjust:[1,5,8,34,43],admin:[27,28,30,32],administ:1,administr:[1,20,21],advantag:12,advertis:[4,9,24,28,33,35,36,43,46,48],advertisedservic:[11,36,42,45,46],advic:34,advis:[0,29],aesthet:36,affect:[18,29,38],affinityexecutor:5,afraid:5,after:[0,3,6,7,8,10,11,13,14,15,16,18,19,22,23,28,29,36,41,43,45,47],again:[8,12,14,15,22,28,29,43,45,46,48],against:8,agent:[22,26,28],agentlib:11,aggreg:[12,33,36,43,44],agre:[1,8,13,14,17,19,36,37,41,45],agree:[8,36],agreement:[8,12,19,20],ahead:[14,43],aid:[33,41,45],aim:[5,12,22],aka:[19,20],albeit:33,albertsen:33,alert:18,algorithm:[12,21,33,39,43],alia:[9,32],alic:[46,47],alice:[19,27,39,42,43,46,47,48],alice_key:40,alice_pubkey:47,alicecli:46,aliceparti:48,aliceproxi:46,alicevaultupd:46,align:[33,41,45],aliv:[14,36],all:[1,2,3,4,5,6,7,8,9,10,11,12,14,15,16,18,19,22,23,24,26,27,28,29,31,32,33,34,36,37,38,39,40,41,43,44,45,46,48],allaslist:46,allevi:6,alloc:36,allow:[0,4,5,6,7,8,9,10,11,12,13,14,19,22,24,27,28,29,30,31,32,33,36,37,39,41,42,43,45,46,47],allpartysignedtx:[14,41],almost:43,along:[1,3,6,14,15,17,29,43,45,48],alongsid:43,alreadi:[5,11,13,14,23,29,30,32,33,36,40,41,43,44,45,47,48],alright:14,also:[0,3,4,5,6,7,8,9,10,11,12,13,14,15,17,18,19,20,22,23,24,25,26,27,28,29,30,31,33,36,39,40,41,43,44,45,46,47,48],alter:[9,14,26,41],altern:[1,2,5,9,24,25,26,27,39,43,45,46],although:[8,9,12,14,17,18,27,28,33,40,43,45],alwai:[5,12,13,14,26,31,38,39,41,43,45],amend:41,among:45,amongst:0,amount:[3,4,7,8,12,14,20,22,33,36],amountrequir:41,amqp:[24,33],analysi:[3,12],analyt:36,andresen:12,ani:[0,1,3,4,5,6,7,8,10,12,13,14,15,17,19,24,26,27,28,29,30,31,33,34,35,36,37,38,39,40,41,42,43,44,45,46,48],annot:[4,5,10,14,24,31],announc:[29,34],annual:1,anonym:[12,28],anonymis:28,anoth:[1,4,5,6,11,12,14,18,19,24,26,27,28,29,30,33,36,40,43,44,47,48],another:41,answer:[5,29],answere:44,anti:45,anticip:5,any:[3,4,7,13,26,28,32,36,41,44],anybodi:12,anycompost:44,anyon:[6,24,43],anyth:[6,12,14,15,37,39,43,44,45],anywher:[29,33,43],apach:24,apart:[6,33,41],api:[0,2,4,5,11,14,15,19,20,21,26,28,31,32,33,34,36,38,41],app:4,appear:[18,29,36,43,45],append:[9,14,26],appendix:20,apple:17,appli:[5,7,8,11,12,22,27,41,43],applic:[10,11,12,19,24,28,29,33,36,37,43,45],applicat:19,applyfix:8,appoint:6,approach:[12,13,14],appropri:[1,5,24,28,29,31,33,35,41,45],approv:[12,13,14,30,32,41],approxim:6,april:33,arbitrari:[3,5,12,14,29,37,39,42],arbitrarili:[12,46],architectur:[4,20,29],area:[0,31],aren:[4,13,21,43],arg:[11,33,42,45],argument:[4,5,10,11,12,14,22,42,43],aris:[12,17],around:[6,12,14,15,23,33,34,39,41,42,43,45,46],arrai:[12,42,45],arrang:14,arraylist:29,arriv:[14,19,29,46],arrow:[8,18,45],art:39,artemi:[11,19,24,45],artemisaddress:[9,38,45],artemismq:[9,28],artemisport:[11,45],articl:[6,12,13,14,29,33,43],artifact:11,artifactid:45,ascertain:[36,45],ask:[5,14,29,32,43],aspect:14,assembl:[0,3,12,23,43],assemblesharedtx:14,assert:[5,14],assertequ:[15,40,46],asset:[3,7,14,20,33,36,37,39,41],assetforsal:14,assetmismatchexcept:14,assettosel:14,assettypenam:14,assign:[12,15,20,29,41],assist:[13,14,31,39],associ:[3,6,12,13,24,29,31,33,38,39,41,42,43,45],assum:[6,12,14,22,23,24,29,32,37,41,43,48],assume:[14,23,29,45],assumpt:14,assur:36,asynchron:[22,41],atom:[6,12,14,33,36,43],attach:[0,11,12,14,19,20,23],attachment:[12,19,20,26],attachmentdemo:40,attachmentexist:40,attachmentstorag:28,attack:[6,33,37],attch:23,attempt:[12,18,24,29,37],attent:[14,45],attest:6,attribut:5,audit:[12,41],authent:[1,4,6,24,28,33,42],authenticatedobject:[3,39,43,44],author:[5,6,28,34,48],authoris:[9,14,28,39,42],authorit:17,auto:[5,43],autoclos:4,autom:[12,13,43],automat:[0,2,4,6,9,11,13,14,24,25,27,28,29,30,31,33,40,43,45,48],auxiliari:28,avail:[0,1,2,6,8,9,11,13,14,17,20,24,25,26,28,29,32,33,34,36,37,42,43,45,48],avoid:[4,5,12,14,29,31],awai:[4,12,14,42],await:[11,36,41],awar:[4,5,13,14,28,33,43,44],awg:34,awkward:[5,14],axi:8,back:[1,4,5,10,12,14,28,29,33,36,37,39,41,43,46],backend:33,background:[0,4,5,20],backoff:24,backport:34,backward:[14,34],bad:[5,14,43,47],balanc:[3,6,7,12,27,33,41,43],banana:39,bananast:39,banco:33,band:14,bandwidth:5,banish:19,bank:[1,8,9,12,20,27,33],bankrupt:43,bankruptci:[6,12,29,36],banner:[1,38],bar:[1,18],barreca:33,barrel:33,base:[5,6,8,9,11,12,13,14,19,22,24,26,28,29,30,33,36,38,39,42,43,45,48],basedir:[9,38],basedirectori:42,basi:[1,8,13,17,25,26,28,45],basic:1,bat:[0,11,25,27,30,45],batch:[22,45],bbva:33,bear:14,becaus:[5,6,12,13,14,17,18,26,28,29,39,41,43,44,45,47,48],becom:[5,8,12,13,14,20,29,34,39,41,45],been:[6,8,9,12,14,17,19,24,29,30,33,34,36,39,41,43,44,45,48],befor:[0,1,6,8,11,12,13,14,15,20,22,28,29],beforesign:29,begin:[1,5,12,28,41,43,45],behalf:36,behav:43,behaviour:[3,6,7,9,22,26,41,44,45,47],behind:[14,19,24,43],believ:33,belong:[23,38],below:[1,5,8,9,11,12,13,14,17,23,24,28,36,39,41,43,45],beneath:19,beneficiari:7,benefit:[6,14],best:[5,41],bet:29,beta:36,better:[5,16,33,43],between:[1,5,6,8,12,13,14,19,24,25,28,29,30,31,33,34,37,39,41,42,43,45],beyond:[12,41],bft:33,big:[5,12,14,33,36,43],bigdecim:[29,39],bilater:[7,8,33],bill:43,bin:[36,42,45],binari:[12,23,28,29,32,42],bind:[6,9,12,25,26],bintrai:32,bintrayupload:32,bip:12,bit:[33,39,40,43,45,47,48],bitcoinj:14,blah:5,blank:[5,26,27,30,43],block:[3,4,5,6,11,12,14,28,29,33,36,37,40,41,45,46],blockchain:[12,14,21,23,43],bloom:5,bloomfilt:5,blotter:36,blue:[8,23],bob:[19,27,39,43,46,47],bob_pubkey:47,bobclient:46,bobproxi:46,bobvaultupd:46,bodi:[5,36],boil:[12,22],boilerpl:11,bond:[43,44],bookkeep:43,bookmark:36,boost:21,boot:45,bootstrap:[9,11,45],bore:43,borrow:47,boss:45,both:[0,6,7,8,12,14,15,16,19,22,25,29,31,33,36,37,39,40,41,42,43,44,45],bottom:18,bounc:15,bound:[6,14,33,38,41,43],box:[1,32],branch:[20,23,33,34,45],branch_nam:45,brand:33,breach:12,breakpoint:45,breviti:[0,44],bridg:[24,28],brief:[4,20],briefli:[24,29,45],bring:[12,22,33,36,40,46],broadcast:[1,12,41,43,48],broadcasttransactionflow:48,broader:38,broke:5,broken:[33,45],broker:[9,24,28,33,45],brought:41,brows:[26,36],browser:[1,9,36,45],bubbl:[17,18],buffer:[4,26],bug:[5,17,18,33,34],bugfix:34,bui:[1,14],build:0,buildcertsigningrequestutilityjar:30,buildcordajar:[9,30,38],builder:[14,15,33,37,40,41,48],buildfilteredtransact:41,buildmerkletransact:[23,29],buildscript:[11,19,45],buildsrc:45,buildtradepropos:41,built:[0,9,11,14,23,33,37,40,43,45],bulk:[12,41],bullet:5,bunch:45,bundl:[12,17],busi:[12,13,14,19,21,29,31,33,39,41,43],businesscalendar:39,button:[1,32,36,45],bytearrai:31,bytecod:[12,14,43],cach:[24,40,45,48],calcul:[6,8,13,14,23,33,36,37,39,43],calculateoursignatur:14,calendar:[8,29,39],call:[0,3,4,5,6,8,10,12,14,16,26,28,29,33,34,36,37,39,40,41,42,43,47,48],callback:[4,5,14,28,33],caller:[29,41,43,48],came:14,camel:5,can:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,35,36,37,38,39,40,41,42,43,44,45,46,47,48],candid:31,cannot:[3,6,7,10,12,19,25,29,33,37,39,41,43,45,48],capabl:43,capit:5,capitan:2,capsul:25,capsule_cache_dir:11,captur:[10,13,41],cardon:33,care:[5,6,10,12,14,15,37,41,47],carefulli:16,carri:[0,28,41],cash:3,cash_stat:31,cashcommand:[22,42,46],cashflow:[42,46],cashflowresult:46,cashkt:43,cashprotocol:[9,38],cashschema:31,cashschemav1:31,cashsigningpubkei:14,cashstat:41,cast:4,catastroph:36,categori:38,caught:4,caus:[5,14,17,18,19,26,36,43,45],cbc:22,ccy_cod:31,cent:39,center:43,central:[20,27],ceo:39,cer:9,certain:[3,5,10,33,36,41,43],certainli:11,certainti:6,certif:[9,20,22,24,28],certificatesigningservic:[9,30,38],certsigningrequestutil:[30,38],chain:[7,12,14,15,20,28,29,33,39,43],chaincommercialpap:47,chaincommercialpaperdoublespend:47,chaincommercialpapertweak:47,challeng:12,chanc:[5,14],chang:[0,2,4,5],changenotari:6,channel:14,charact:[5,9],characterist:19,charg:29,charli:39,chart:44,check:[3,5,6,9,13,14,15,17,20,22,23,24,25,28,29,32,33,37,38,39,40,41,42],checkabl:[29,33],checkfixisnearexpect:29,checknotnul:43,checkout:[17,18,45],checkpoint:[10,28,33],checksignatur:29,checkstat:43,checksufficientsignatur:[14,39,41,48],child:[0,14,39],children:[14,39],childrenfor:14,choic:[1,5,6,12,17,43,45],choos:[0,1,6,27,33,43,48],choreographi:19,chosen:[0,6,12,14,22,48],christma:45,chronolog:13,chronounit:47,chunk:[43,44],circl:25,citi:45,cl1:3,cl2:3,cl4:3,cl5:3,claim:[12,43],clarifi:43,clash:[5,31,45],classic:43,classpath:[4,10,11,12],clauseverifi:44,clean:[0,14,27,33],cleaner:33,cleanup:33,clear:[0,3,4,14,22,37,39],cleardatabasebeforerun:22,clearer:14,clearli:[5,41],click:[1,18,27,32,36,45],client:1,clint:1,clock:[1,6,12,13,14,29,36,41],clone:[0,1,5,18,43,45],close:[4,6,7,45],closeabl:4,closer:6,closest:1,closur:[5,47],cloud:26,cluster:[6,9,20],cmd:[23,43,44],coars:12,code:[0,2,3],codebas:[1,5,20,31,32],cognit:12,coin:12,collabor:33,collaps:22,colleagu:5,collect:[4,5,19,22,26,31,33,35,41,43,44],collector:[5,14,26],collis:5,colon:0,column:[11,26,31],com:[2,17,18,30,32,33,36,45],combin:[12,19,39,43,44],come:[4,12,14,15,26,33,34,37,43],comfort:33,commanddata:[3,29,43,44],commenc:27,commerci:3,commercial_pap:[43,44],commercialpap:[3,7,31,43,44,47],commercialpaperlegaci:43,commercialpapertest:47,commit:[6,9,13,15,20,28,34,35,36],committe:36,common:[3,7,8,9,10,12,14,24,28,31,33,39,41,43,44,47],commonleg:8,commonli:41,commun:[9,14,19,20,24,28,33,37,38,45],compani:[29,30,44],companion:[14,29,43,44],compar:[1,12,23,36,43,45],compat:[4,19,34],compel:6,compet:12,complementari:13,complet:[0,1,4,12,13,14,20,28,30,33,36,39,40],completetx:41,complex:[5,7,12,15,20,31,36,39,40,43,46],complic:[14,29,41,43,44],compon:[0,3,10,11,13,19,20,24,28,33],compos:[3,14,33,39,43,44],compositeclaus:[3,44],compositekei:[14,28,39,41],compound:33,compris:[8,45],comput:[8,19,29,45],computeoursignatur:14,concaten:23,concept:[3,6,7,12,13,14,20,23,29,33,43,44],concern:[12,14,43],concis:33,conclus:[12,29],concret:[10,28],concurr:22,concurrenthashmap:5,condit:[3,6,10,22,28,29,33,44,47],conf:[9,11,28,30,38,45],config:[9,11,22,26,30,33,36,42,45],configur:[0,1,4],configurationfil:26,confirm:[6,18,19,36,41],conflict:[6,12,22,48],confus:[0,14],conjunct:27,connect:[0,1,4,9,11,21,22,24,26,27,28,30,33,36],consequ:41,conserv:[3,41],conserveamount:3,consid:[5,8,12,13,19,29,33,34,39,41,43,44],consider:[41,43],consist:[8,9,12,14,19,22,28,29,33,36,38,41,44],consol:[0,26,33,36,38,42],consortium:19,constant:[5,31,43],constantli:[29,45],constraint:[14,29,33,43,45,46],construct:[3,5,6,10,11,14,20,23,24,28,31,33,37,39,41],constructor:[3,10,13,14,29],consum:[4,6,12,13,19,26,28,33,36,39,41,43,48],consumedcommand:3,consumingtx:48,consumpt:[13,29,41],contact:[14,28,33],contain:[1,3,6,8,9,10,11,12,14,19,23,24,26,27,28,29,30,33,34,36,39,40,41,43,44,45,47,48],content:[1,5,6,10,11,12,13,15,18],context:[5,12,26,28,29,39,41,48],contextclassload:40,contin:29,continu:[1,8,14,20,24],contract:[3,4,6],contracthash:44,contractreject:47,contractst:[3,6,13,23,31,33,39,41,43],contractu:41,contrast:[12,14,29],contribut:[1,20,39],control:[0,4,5,6,9,10,11,12,14],conveni:[3,5,12,29,39,40,41,43],convent:[8,14],convers:[27,39],convert:[3,6,7,8,15,28,31,33,39,41,43],convinc:[14,23,39],coordin:[9,32],copi:[0,5,12,14,24,26,28,41,43,45,47,48],copycat:35,copyonwritearraylist:5,copyright:5,copyvault:22,cor:20,corda:0,corda_bintray_gpg_passphrase:32,corda_bintray_key:32,corda_bintray_user:32,corda_dev_ca:9,corda_gradle_plugins_vers:11,corda_vers:[11,45],cordaapp:45,cordacadevpass:[9,38],cordapluginregistri:[10,11,29,42,45],cordapp:[0,4,10],cordarpccli:[4,40],cordarpcop:[4,14,40,42],cordarpcopsimpl:28,cordform:0,core:[1,7,10,11,12,14,18,22,26,28],corner:[1,18],corp:[27,30],corpor:[36,44],correct:[7,12,14,18,29,33,34,36,41,43,45,47],correctli:[12,14,18,19,28,29,33,41,43],correspond:[4,19,22,24,36,39,43,44],correspondingli:[5,40],cost:[1,4,29,43],could:[5,6,7,12,14,22,29,37,39,41,43],couldn:[23,29],count:[8,36],countabl:33,counter:[5,14,45],counterparti:[1,7,8,19,24,36,37,40,41],counterparty:45,countri:[29,39,45],coupl:[14,15,22,42,45],cours:[14,22,26,29,31,43],coven:43,cover:[6,7,12,14,29,36,39,43,45],cpu:22,crash:[14,28,29],crazi:45,creat:[1,4,5,6],createcommand:48,createdummyirs:8,createsomenod:15,creation:[8,12,23,43],creator:29,credenti:[27,32,42,45],credit:[33,36],crisi:36,crisp:43,criteria:7,critic:[12,34],crop:12,crypto:[33,45],cryptograph:[19,23,39],cryptographi:20,csr:33,ctrl:45,curl:[26,45],currenc:[3,7,8,14,22,27,31,33,39,41,43],current:[0,4,5,6,8,9,11,12,13,14,20,21,22,23,24,25,27,28,29,30,31,33,34,35,37,39,42,43,45,47,48],currentstep:[14,29],currentthread:40,currenttim:14,currentvault:41,curv:8,custodi:[15,39],custom:[4,6,9,10,14,26,28,31,33,36,39],customis:[4,31,42],cut:20,cutoff:22,cycl:[5,14,43],dai:[6,8,14,26,29,34,39,47],daili:45,daniel:33,danks:33,dao:33,dashboard:[26,27],data:[1,2,5,6,7,8,10,11],databas:[9,10,11,12,15,20,21,22],databaseschema:31,databasetransact:15,dataset:[8,36],datasourc:[9,38],datasourceclassnam:[9,38],datasourceproperti:[9,38],datastructur:22,date:[6,7,8,13,18,20,26,34,36],dateoffset:33,daterollconvent:39,david:33,days:47,dcapsul:11,dead:24,deadlin:[29,39],deal:[1,5,14,29,36,39,43],dealstat:39,debt:[7,36],debugg:11,decd098666b9657314870e192ced0c3519c2c9d395507a238338f8d003929de9:26,decd:26,decentralis:[12,29,33],decid:[18,23,29,31,41,43],decis:[6,12,41,43],declar:[5,9,10,28,47],dedic:[1,5],dedupl:[28,33],defaultissu:43,defaultref:47,defens:41,defin:[3,5,6,10,12,14,15,21,22,26,28,31,33,39,42,43,44,45,47],definit:[3,6,14,19,33,39,43],delai:[8,29],deleg:[41,44,48],delet:[5,12,14,28,33,43],deliber:[12,47],deliv:[7,15,28,39,45],deliveri:[14,21,24,36,45],deliveryaddress:45,deliveryd:45,demand:[1,6,12,14,33],demo:0,demonstr:[0,17,27,33,36,45,46],denial:6,denot:23,dens:5,depend:[0,1,5,6,11,12,13,14,15,17,18,19,29,33,36,38,41,43,45],dependson:[11,45],deploi:0,deploy:[0,1,11,19,25,45],deploynod:[9,11,36,40,42,45],deployvisualis:25,deposit:43,deprec:33,deregist:24,deriv:[0,8,14,19,31,33,39,43],describ:[5,6,12,13,14,20,22,23,24,28,36,37,39,42,43,45,48],descript:[1,3,5],deserv:[22,34],design:[5,6,12,16,19,20,29,33,37,43,44,45],desir:[10,14,39],desktop:26,despit:[14,40,43],destin:24,destroi:[7,12,41,43],destructur:43,detail:[1,3,4,5,7],detect:5,determin:[0,3,7,8,13,18,19,24,41,43,44,45,46],determinist:[4,22,33,46],dev:[9,22,26],develop:[0,1,5,9,11,12,14,16,17,20,26,28,30,31,33,34,36,41,43,45],developer:45,devic:[9,12],devis:12,devmod:[9,30,38],diagnos:38,diagram:[8,43],dialog:1,dialogu:45,diamond:19,did:23,didn:[5,14,23,34,43,45,47],differ:[1,3,5,6,7,8,9,10,11,12,13,14,17,22,24,27,29,31,33,36,39,41,42,43,44,45,46,47],differenti:[30,48],difficult:14,difficulti:44,digest:6,digit:[12,14,29,33,41,43],digitalsignatur:[14,29,41,48],dir:[30,38],direct:[1,5,19,20,28,31],directli:[0,4,5,14,15,19,24,26,28,33,36,39,41,42,43,44,45,46,48],directori:[0,1,2,9,11,18,20,22,26,28,30,36,38,45],directthreadexecutor:5,dirti:43,disabl:[28,39],disadvantag:12,disagr:36,disambigu:31,discard:37,discov:12,discoveri:25,discuss:[12,14,29,39,41,45],disk:[1,14,24,33,39],disobei:29,dispens:36,displai:[0,1,6,33,36,42],disput:[6,8,43],disrupt:[22,24,33],disruptionpattern:22,disruptionspec:22,distinct:[5,38],distribut:[6,9,10,11,12,14,19,20,21,29,33,35,36,41],distrust:[6,14],dive:20,divid:6,divis:39,dlog4j:26,doc:[0,2,4,5,20,33,36,42,45,46],docker:26,docsit:[2,20,34,45],document:0,doe:[5,6,7,8,9,11,12,13,14,15,21,24,26,28,29,30,31,33,36,37,40,41,43,45,46,48],doesn:[3,5,6,9,12,14,15,18,21,26,29,37,40,43,47,48],dokka:2,dollar:[39,43,46],dollars:[43,46,47],domain:[19,33,39,43],domicil:43,domino:36,don:[4,5,12,14,16,17,18,22,27,29,34,36,37,39,43,44,47],done:[2,3,4,12,14,15,17,22,23,24,30,33,42,43,45],doorman:24,dot:[8,23],doubl:[12,14,21,27,28,38,43,45,47],doubt:5,down:[1,5,9,12,14,22,27,41,43,44,45,46],download:[0,4,14,15,17,18,20],downsid:[5,12],drain:[4,14],draw:[33,42],drawn:42,drive:41,driver:[0,9,26,31,33,42,45,46],driverdirectori:42,drm:29,drop:[1,45],dsl:[0,11,19,33,45,46,47],dt_socket:[0,11,45],due:[0,5,6,8,12,13,14,16,17,28,31,36,43,44],dummi:[7,15,40,47],dummy1:15,dummy2:15,dummy_notary_key:15,dummy_pubkey_1:[43,47],dummycontract:[15,48],dump:42,duplic:[14,23],durat:[13,29,41],durationsecond:22,dure:[5,8,9,10,11,14,25,26,28,33,43],dynam:[10,12,33,43],each:[0,1,3,4,5,6,8,9,10,11,12,13,14,19,22,23,24,25,28,29,31,33,34,36,39,40,41,42,43,44,45,46,47],earli:[5,7,28],earlier:[0,37],earliest:[8,13],easi:[0,1,5,12,16,29,33,43],easier:[5,11,14,17,33,43],easiest:[4,43],easili:[5,14,20,36,43,45],echo:45,econom:[1,8],ed25519:33,edg:42,edge:42,edit:[0,26,32,38,45],editor:[1,18],effect:[8,9,12,14,15,31,36,47],effort:17,either:[0,3,4,5,6,7,8,9,10,12,14,17,18,19,22,23,27,31,36,39,42,43,45,47],elbonia:39,element:[5,19,23,29,41,43,45],elementari:[44,45],elimin:[21,33],els:[6,12,14,15,28,29,39,40,41,42,43,44,48],elsewher:10,elucid:41,email:14,emailaddress:30,embed:[9,10,12,21,23,26,29,33,45],embedd:24,emit:[4,33,46],emoji:40,empti:[9,27,33,43,47],emptyledg:47,emptyset:3,enabl:[0,9,10,11,28,33,44],enact:36,enc:22,encapsul:[3,5,29,39],enclos:5,encod:[24,29,41],encount:[1,13,28,41],encourag:[20,31,40],encrypt:[30,41],encumb:43,encumberedst:43,encumbr:[33,43],encumbranc:20,end:[3,5,6,8,12,14,20,22,24,28,29,34,41,44,45,47],endeavour:45,endpoint:[11,24,26,45],enforc:[3,5,12,43],enforceverifyorfail:47,engin:36,england:44,english:[5,43],enhanc:33,enjoy:33,enorm:14,enough:[5,14,15,36,41,43],ensur:[3,5,6,10,12,14,18,19,23,28,30,33,34,37,39,41,43,44,45],ensure:[1,6,18,29,36,45],enter:[11,32,36,45,46,47],entir:[6,8,12,14,28,29,43,45],entireti:8,entiti:[6,12,23,29,30,31,39,43],entitl:42,entri:[8,9,11,12,14,31,33,37,43,44],enumer:[8,31,36,41,45],environ:[0,1,5,11,14,17,27,29,32,41],envis:20,envisag:43,equal:[3,6,14,33,39,41,43,44],equiti:31,equival:[5,8,27,28,35,39,41,43],eras:17,error:[0,1,3],escal:29,especi:[39,41],essenti:[0,26,28,29,41,43,44],establish:[13,17,24,36,38,46],estim:1,etc:[0,5,6,7,8,14,19,21,26,27,29,33,34,36,38,39,43,44,45],eur:1,euribor:[1,26,29],euro:39,evalu:[8,26,29,44],even:[4,6,12,14,16,23,28,29,31,33,36,43,44,47],event:[5,6,8,12],eventu:[22,28,38],eventual:[6,34],ever:[5,12],everi:[0,3,4,6,10,12,14,22,23,24,28,29,31,33,34,36,37,39,43,44],everybodi:12,everyon:[6,29,43],everyth:[6,37,42,43],evid:[29,41],evolut:[12,44],evolv:[31,33,38,42,43,45],exact:[0,6],exactli:[12,28,29,39,43],examin:[5,11,12,15,43],exampl:[0,1,2,3,4,5,6,7,8],exampleapi:45,exampleclientrpc:45,exampleflow:45,exampleplugin:45,examplerpccordapluginregistri:42,examplerpcvalu:42,exampleservic:45,exampletest:45,exampleweb:45,exce:22,excel:29,except:[3,4,5,10,14,24,37,41,43],exception:[0,5,14],excess:[5,26],exchang:[8,14,19,28,39,41],exclud:[9,31,41],exclus:7,execut:[0,3,6,11,12,13,14,19,22,25,27,28,33],executor:5,exemplifi:47,exhaust:[28,33],exist:[1,5,6,7,8,9,11,12,13,25,28,30,31,33,39,43,45,47],exit:[3,7,9,15,27,28,30,33,36,42,43],exitcash:42,expand:[27,41,45],expect:[1,4,5,7,9,13,14,22,28,29,30,31,33,34,37,39,40,41,43,44,45,46,47],expectedtypenam:14,expectev:46,expens:[4,5],experi:[11,17,33,34,45],experienc:12,experiment:[5,33,36],expir:30,explain:[5,13,14,22,25,30,33,45],explan:[3,5,25,29,42],explicit:[5,12,14,41,43],explicitli:[5,10,12,36,41,47],explor:[5,12,15,18,21,26,27,33,36,41,43,45],explorer:20,expos:[5,10,11,12,13,14,26,28,31,33,39,41,42,48],expose:39,exposur:[7,8,19],expound:17,express:[6,8,12,19,33,39,43,47],ext:[11,45],extend:[3,5,6,10,11,14,16,20,27,28,29,33,36,39,43,44],extens:[0,5,10,14,19,25,26,28,29,33,37,39,41,43],extent:12,extern:[9,14,28,38,41,45],extraadvertisedserviceid:[9,28,35,38],extract:[12,26,29,36,39,41,43],extractcommand:44,extrem:[6,12,16,19,22],face:[43,44,47],facevalu:[3,43,47],facil:[19,28],facilit:45,fact:[0,5,6,8,12,14,19,29,33,38,43,45,47],factor:[8,36],fail:[3,10,43,44,47],failswith:47,failur:[14,19,47],fairli:[5,15,36],fall:24,fals:[5,9,14,15,29,38,39,41,43,48],famili:31,familiar:[4,12,20,43,45,48],famou:[12,33],fanci:43,far:[14,29,36,41,43,44,46],fashion:[5,31,36],fast:[12,15],faster:26,faucet:36,fault:14,fear:19,featur:[1,4,5,9,11,12],fed:25,feed:[6,29],feedback:33,feel:[43,45],fetch:[24,26,28,29,40],fetchtransactionsflow:40,few:[0,5,14,16,26,29,34,36,41,43,44,45],fiber:[14,28,29],fiction:27,field:[5,8],file:[1,2,4,5],fill:[5,14,36,41,43],filter:[3,5,22,23,29,31,33,41],filtercommand:[23,29],filteredleav:[23,29],filteredtransact:[23,29,41],filterfun:[23,29],filterisinst:43,filterst:3,finalis:[8,14,33],finalityflow:[40,41,48],financ:[11,14,33,45],financi:[12,13,14,19,33,36,39,41],find:[0,2,14,15,16,17,20,21,26,29,37,41,45],fine:[4,12,26,47],finish:[14,33,45,46],fire:14,first:[0,3,4,5,6,8,9,11,13,14,15,16,17,18,19,24,26,29,30,31,32,33,36,39,40,41,42,43,44,45,46,48],firstli:[10,27,36,40,43,45],fit:[5,12],fix:[1,5,7,8,12,13,14,18,20,22,23],fixabledealst:39,fixedleg:8,fixedlegpaymentschedul:8,fixedratepaymentev:8,fixer:29,fixingflow:29,fixingroledecid:13,fixingsessioninitiationhandl:13,fixof:[23,29],fixqueryflow:29,fixqueryhandl:29,fixsignflow:29,fixsignhandl:29,flag:[9,26,30],flat:31,flesh:39,flexibl:[6,12,39],flight:[4,12],floatingleg:[8,13],floatinglegpaymentschedul:8,floatingratepaymentev:8,flow:[5,6,8,10,11,12,13],flowhandl:[14,46],flowlog:[13,14,28,29],flowlogicreffactori:[10,13],flowstatemachineimpl:28,flowtrack:14,flux:11,fly:14,focu:23,focus:[3,44],fold:[5,42],folder:[2,9,11,28,30,36,41,45],follow:[1,2,5,6,9,11,12,13,14,17,18,20,22,25,26,27,28,29,30,32,35,36,41,42,43,44,45,47,48],font:5,foo:[5,42],foobrokenexcept:5,foot:37,fooutil:43,forc:[12,26,33,43,47],fordai:[13,29],foreach:42,foreign:41,foreignexchangeflow:41,forev:34,forget:[14,29,43],form:[4,6,11,12,13,14,23,24,28,29,36,41,43,44,45],format:[2,4,5],former:42,formerli:33,formula:33,forth:[4,14,41],fortun:36,forum:[17,20],forward:[14,24,28,29,34,36],found:[3,9,14,17,18,20,26,29,32,33,34,39,40,41,44,45],four:[24,36,38,43,45],fourpmtimelock:43,fraction:39,frame:[5,14,28,36],free:[6,12,14,17,36],freed:4,freeli:29,freez:41,frequenc:[1,8],fresh:[27,29,43,47],freshkei:14,freshli:[39,45],friend:38,friendli:28,from:[0,1,2,3,4,5,6,7,8,9,10,11,12,14,15,16,17,18,19,20,22,23,24,25,26,27,28],fromcountri:39,front:[43,45],frontend:21,frustrat:12,ftx:[23,29],fulfil:[7,12],full:[5,6,7,9,10,14,23,24,25,28,33,36,41,42,43,44],fulli:[5,6,9,10,12,14,19,25,28,31,33,38,39,41,45,46],fullysign:14,fun:[3,6,13,14,15,22,23,29,31,40,41,42,43,44,45,47,48],fund:[12,36,41,43],fundament:[6,12,43],fungibl:[3,7,19,39,41,43,44,45],fungibleasset:[7,20,33],further:[3,8,9,12],futur:[4,6,7,9,12],futuretransact:42,fuzz:33,fxrespons:41,fxtransactionbuildtutori:41,fxtransactionbuildtutorialtest:41,gain:21,garbag:[4,5,14,26],gather:[20,22],gatherfrequ:22,gatherourinput:41,gatherremotest:22,gave:29,gavin:12,gbp:[3,27,44],gcd:12,gear:34,gener:[0,1,2,3,4],generatecount:22,generatefix:29,generateiniti:15,generateirsandfixsom:8,generateissu:[43,44],generatemappedobject:31,generatemov:[43,44],generateredeem:[43,44],generatespend:[14,41,43],generatetransact:42,generatexxx:41,genuin:5,geograph:1,get:[0,1,4,5,6,12,14],getalice_pubkey:47,getanynotari:48,getbefor:43,getbloomfilters:5,getbob_pubkey:47,getclass:43,getcommand:[43,44],getcontract:43,getdummy_pubkey_1:47,getencumbr:43,getfacevalu:43,getfix:8,getflowtrack:14,getinput:[33,43],getinstat:33,getissuanc:43,getkei:43,getlegalcontractrefer:[43,44],getmaturityd:43,getmega_corp:47,getmega_corp_pubkey:47,getnotari:48,getnotarysignatur:14,getorthrow:[15,46],getoutput:[33,43],getoutst:33,getowner:[43,44],getpap:47,getparticip:43,getprotocolvers:4,getrequiredcommand:44,getresourceasstream:40,getresultorthrow:22,getsign:[43,44],getsubtyp:36,getter:[31,43],gettest_tx_time:47,gettimestamp:43,gettransact:15,getvalu:[43,44],gigabyt:26,github:[1,2,17,18,20,36,45],giusepp:33,give:[6,11,12,15,24,26,28,29,33,41,43],given:[0,1,3,6,10,12,14,23,24,29,31,33,35,39,42,43,44,48],givenpric:14,glanc:27,global:[1,5,6,12,33,39,47],glue:14,gnu:2,goal:[5,12,19,21,34,44],goe:4,gone:[14,33,43],good:[0,5,14,15,20,23,43,44],got:[14,23,26,29,46],govern:36,gpg:32,gps:6,gr1:3,gr2:3,gr3:3,grab:45,grade:39,gradlew:[0,11,18,22,25,27,30,32,36,38,42,45,46],grain:[4,26],grammar:5,granular:12,graph:[1,4,12,15,21,26,31,33,42],graphit:26,graphstream:42,great:[0,33,36],greater:5,greatest:12,green:[18,45],grip:17,groom:12,group:[1,3,7,9,11,12,20,23,24,27,28],groupclaus:44,groupid:45,groupingkei:[3,44],groupstat:[3,43,44],grow:42,guarante:[19,24,34,39],guava:[5,43],gui:[14,18,33,45],guidelin:[17,18,20,33],h2databas:36,hack:[12,33],had:[6,14,15,33,39,43],hand:[1,13,14,17,25,28,38,41,43,45],handa:33,handi:15,handler:[11,13,14,28],handshak:[24,29],happen:[5,6,12,13,14,20,23,29,34],happi:[36,40],happili:[26,29],hard:[5,12,14,34],harder:[12,37,43],hardwar:[1,9],hash:[6,12,14,15,19,21,23,26,29,33,39,40,41,43],hashcod:[3,43],hashmap:22,haskel:33,hasn:22,hassl:14,hat:34,have:[0,1,3,4,5,6,7,8,10,11,12,13,14,15,17,18,19,21,22,23,24,26,27,28,29,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,47,48],haven:[43,45],head:[1,3],heap:[14,26],hearn:12,heart:43,heavi:34,heavili:12,hedg:[7,8],held:[28,31,43],hell:14,hello:14,help:[5,12,13,14,25,29,36,41,43,45],helper:[3,8,10,14,28,39,40,41,43,47,48],henc:[6,8,12,28],her:[43,47],here:[0,1,5,6,9,11,12,14,15,16,18,19,20,23,24,25,26,29,31,33,39,41,42,43,44,45],herself:42,hidden:[24,28],hide:20,hierarch:[0,14],hierarchi:[5,14],high:[12,14,33],higher:[4,5,6,26,45],highli:[0,33],highlight:33,hint:0,histor:29,histori:35,hit:12,hoc:33,hocon:9,hold:[3,10,12,22,23,28,33,41],holder:[5,12,43],holidai:[8,29,39],home:[18,36],homepath:[11,45],hood:47,hope:28,hospit:14,host1:22,host2:22,host:[9,11,22,24,25,28,29,30,32,33,38,45],hostil:37,hostnam:38,hotspot:5,hour:14,hous:27,how:[0,1,3,4,5,7,12],howev:[0,6,7,8,9,12,14,23,28,29,30,31,35,39,40,41,43,44,45,47],html:[2,5,36,45],http:[1,2,9,17,18,26,28,29,30,32,36,38,40,43,44],https:9,hub:[14,19],human:[6,9,12,14,29,36],hundr:14,hurt:[14,29],icommercialpaperst:47,icon:[1,17],idea:[0,5,12,14,17,18,21],ideal:[14,43],idempot:33,ident:[6,9,12,14,15,19,20,22,23,24],identicon:33,identifi:[1,8,10,12,14,19,23,24,26,28,29,31,33,36,39,41,46],identiti:[6,14,28,39,48],identityless:12,identityservic:28,ifmatch:33,ifnotmatch:33,ignor:[14,42,43,44,45],iii:10,illegalargumentexcept:[5,14,29,43,44,47],illegalstateexcept:[3,5,41,43,44,47],illustr:[1,25,39,43],illustrat:5,imag:[1,23,45],imagin:[3,5,14,43,44],immedi:[4,12,28,41],immut:[5,8,12,29,43],immutabl:[5,12],immutablelist:43,imper:5,implement:[0,3,4,5,6,7,8,10,11,12],impli:[14,24,31],implic:[6,12,14],implicit:46,implicitli:8,important:34,importantli:41,impos:[29,43],imposs:[12,23,29],improv:[33,34,43,44],improve:12,improvement:33,inact:28,inadvert:43,inbound:24,includ:[0,3,5,6,7,9,10,12,14,18,19,20],include:10,inclus:[3,23],incom:[28,33],incompat:47,incomplet:22,inconsist:0,inconveni:43,incorpor:[17,24,29],increas:[5,33,36],increment:[0,4],inde:29,indent:5,independ:[6,29,31,36,44],index:[8,12,13,18,31,34,43,45,48],indexsourc:13,indic:[4,5,8,9,13,14,33,38,41,43],indicat:22,individu:[5,20],indivis:39,industri:[16,17,19,26,36],inf:[10,45],infer:47,influenc:26,info:[14,15,31,42],inform:[1,5,6,9,10,12,14,15,18,24,27,28,29,30,33,36,39,40,43,45,46],infrastructur:[4,12,15,21,26,28,33,43],ingredi:41,inher:12,inherit:[5,43],init:29,initi:[6,10,14,18,22,24,28,29,33,36,38,41,42],initial:[19,20],initialis:[15,25,28,31,48],inlin:[14,41],inmemorynetworkmapservic:28,inoutgroup:[3,43,44],input:[3,6,7,12,14,19,20,22,23,27,29,33,35,36,40],inputindex:48,inputpap:47,inputslist:41,inputst:48,inquisit:45,insert:[5,6,15,26,28,29,31,41],insid:[4,10,12,14,15,23,28,36,37,41,43],inspect:[22,45,46],instal:[0,2,9,11,13,17,18,32,33,36,42,43,45],installdist:[36,42],instanc:[3,5],instance:47,instant:[5,13,14,29,39,41,43],instanti:[10,12,13,14,26,33],instat:47,instead:[1,5,12,14,15,21,24,28,33,39,43,48],instigat:6,institut:12,instruct:[17,18,19,20,26,36,40,42,43,45],instrument:[7,8,13,28,41,45],insuffici:[12,41],insufficientbalanceexcept:43,integ:[4,33,39,43,48],integer:43,integr:[0,5,9,12,14,17,18,23,26,29,31,33,36,45,46],integrat:20,integrationtest:46,integrationtestingtutori:46,intellig:5,intend:[5,7,11,12,14,15,26,27,28,29,31,37,39,40,45,47],intent:[3,10,25,29,33,43],intention:5,inter:33,interact:[4,5,12,14,15,20,24,29,33,41,43],interchang:[19,39,41],interest:[1,4],interest_r:[9,38],interfac:[0,1,4,5,7,10,13,20,21,24],interior:33,interleav:22,interledg:33,intermedi:41,intermediari:[36,39],intern:[5,10,11,14,24,26,28,31,33,39,43,45],internalis:5,interop:[16,33,43],interoper:28,interpol:39,interpret:[5,12,22],intersect:43,interv:[22,39],intervent:28,intesa:33,introduc:[5,6,13,19,29,33,43],introductori:[20,45],intuit:[5,27],invalid:[6,14,29,39,43],invari:[22,43,46],investig:14,invoc:[4,14],invoic:40,invok:[4,5,10,12,13,14,26,28,29,33,45],invoke:14,involv:[6,7,12,14,20,28,35,39,41,43,46,48],ipsa:29,irrelev:13,irsdemo:[1,9,23,36],irsexport:8,irstest:8,irsutil:8,isbefor:43,isconsist:22,isda:[33,36],isdebug:45,isempti:[29,41,43],isinstanc:14,isn:[4,5,12,14,24,37,39,43],isnotari:42,isnotempti:[40,42],isol:44,issu:[1,3,6,7,12,15,17],issuanc:[7,22,33,36,39,43,44,47],issue:[3,7,19,22,36,42,43,44,47],issuecash:[22,42,46],issuecommand:44,issuedbi:[46,47],issuer:[7,12,14,15,27,33,36,39,41,43,44,47],issuer_kei:31,issuer_ref:31,issueref:[42,46],issuerparti:31,issuerref:31,issuetransact:48,istribut:20,item:[19,41,43,45],iter:[14,33,34,43],iterabl:31,iterat:[29,41],itself:[4,6,8,9,12,13,14,20,24,26,27,28,29,31,33,36,40,41,42,43,47],jar:[0,2,9,10,11,12,25,26,30,33,38,40,41,45],jarandsourc:11,java:[0,3,4,5,10,11,12,13,14,16,17,19,26,28,29,30,31,33,38,39,42,43,44,45,47],javaag:41,javaclass:[14,31],javacommercialpap:[43,47],javadoc:[5,11,45],javadocjar:11,javafx:[17,33],javatesthelp:47,javax:31,jax:10,jcenter:20,jdbc:[9,11,26,31,33,36,38,45],jdbcdatasourc:[9,38],jdbcx:[9,38],jdk1:18,jdk:[17,18,33,39,43,45],jdwp:11,jersey_vers:45,jetbrain:[16,17,18,45],jms:24,jmx2graphit:26,jmx:26,jmxtran:26,job:[14,22],jobs:22,johann:33,join:[9,24,31,33,43],jolokia:26,jpa:31,json:[9,26,28,45],judgement:5,junit:45,just:[4,5,12,14,17,18,22,24,26,29,33,36,37,39,40,41,42,43,45,47,48],jvm:[4,11,12,14,16],kdoc:5,keep:[12,14,41,43,45],kei:[1,3,5,7,9,10,12,14,15,19,20,21,24],kept:[14,30,48],keymanagementservic:[14,28,29],keypair:[14,28,29,43,48],keystor:[9,28,30],keystorepassword:[9,38],keyword:[5,47],kick:14,kill:22,kind:[12,14,29,37,39,43,45],knob:22,know:[1,4,6,12,13,14,15,16,23,29,37,41,43,44,45,47,48],knowledg:29,known:[1,8,12,15,17,19,23,28,29,33,34,36],knownfix:29,koan:17,korea:43,kotlin:[2,5,10,14],kotlin_vers:45,label:[14,47],lack:[12,14],lambda:[14,26,47],land:8,lang:[10,47],languag:[4,5,11,12,14,16,17,18,19,33,39,43,45],larg:[12,14,24,29,33,39,40,41,43],larger:[5,12,37],last:[14,22,29,34,47],lastli:45,late:17,lateinit:15,latenc:6,later:[4,5,14,15,17,21,29,31,33,37,39,42,43,44,45,46],latest:[5,10,17,18,20,33,41,45],latestrecord:41,latex:33,latter:[5,42,43],launch:[13,27,29,36,42],layer:[9,12,14,15,24,28,29,31,33,35],layout:[11,25,33,45],lazi:29,lazili:26,ldap:33,lead:[5,12,44],leader:9,leaf:[19,23],leak:[4,6,12,14,29],learn:[12,14,15,16,20,39,43],least:[1,9,22,36,40,43,44,45],leav:[1,3,5,14,23,27,29,39],ledger:[1,6,7,8,12,14,19,20,26,27,29,31,33,36,38,39,40,41,43,45,46,47],ledgertransact:[14,33,39],leewai:37,left:[1,14,25,30,36,44,45,47],leg:[8,13],legaci:28,legal:[6,9,12,24,28,29,30,33,39,41,43,45,48],legalcontractrefer:[43,44],legalident:[15,41,42,46,48],legalidentitykei:[41,48],legallyidentifi:[14,29],legalnam:[9,38,45],less:[14,26,33,40,44,47],lesser:43,let:[1,3,5,12,13,14,15,22,23,24,26,29,33,39,41,42,43,44,45,47,48],letmein:[9,38],letter:[5,24],level:[0,3,5,6,8,10,14,18,22,23,24,26,27,28,33,36,37,39,41,43,44,47],lib:[2,11,25,30,38,41,45],liber:5,libor:[8,26,29],librari:[0,4,5,14,19,20,26,28,29,33,36,39,42,43,45],licat:20,licens:[5,36],license:45,life:[14,43],lifecycl:7,lifetim:[8,10],lightweight:[15,19],like:[3,4,5,6,8,12,13,14,15,17,22,23,24,25,26,29,33,34,36,39,41,42,43,45],likewis:[29,43],limit:[3,7,12,19,22,26,43,48],linear:[28,39],linearhead:41,linearheadsoftyp:41,linearid:41,linearst:[39,41],liner:5,link:[5,12,14,29,32,33,38,39,45,46],linkabl:12,linkag:12,linux:[11,26,33],list:[0,2,3,9,10,12,14,22,23,24,28,29,31,33,34,35,36,39,41,42,43,44,45,48],listen:[0,1,5,24,28,33,42,45],listof:[15,29,31,41,42,43,45,46],liter:12,littl:[5,14,43,47],live:[8,10,14,28,33,36],livelock:12,lizard:19,llc:30,load:[0,6,9,10,12,14,20],loadtest:22,loan:[7,8,29],local:[0,2,9,10,11,12,14,18,19,20,22,25,26,28,31],local_branch_nam:45,localcertificatesbasedirectori:22,locald:29,localhost:[1,9,26,27,36,38,45],localtunnelstartingport:22,locat:1,lock:[5,7,9,31,43],log4j2:[26,38],log4j:[33,45],log:0,logger:[14,26],loggerfor:26,logic:[3,6,12,13,14,15,19,24,31,33,37,39,40,41,43,44],login:[11,27,32,36,42],loglevel:26,london:[9,11,30,38,40,45],longer:[0,5,8,9,14,30,33],longrang:22,look:[0,1,3,5,8,14,15,22,24,26,29,34,36,39,40,43,44,45,47],lookup:[9,24],loop:[5,8,22,42,43,46],loquitur:29,loss:29,lot:[5,8,12,17,33,36,37,43],low:[6,14],lower:[5,41],lowest:24,lurch:14,machin:[1,9,12,13,14,19,22,33,38],macos:[11,33],made:[5,8,12,14,28,29,33,34,39,40,41,42,45],magicnumb:48,mai:[0,1,4,5,6,11,12,14,17,18,19,20,22,24,25,26,27,28,29,31,33,34,36,37,38,39,41,42,43,44,45,46,47],mail:34,mailbox:28,main:[0,9,13,14,17,22,24,28,33,40,42,44,45],mainstream:21,maintain:[6,12,19,29,43,48],mainten:24,major:[0,14,33,34,36],make:[0,1,2,4,5,6,8,9,11,12,14,15,17,20,22,24,26,27,29,32,33,34,36,37,40,41],maker:16,maketransact:15,malici:[14,33,37,41],man:33,manag:[9,12,14,17,19,20,22,24,26,27],mandatori:43,mani:[5,6,11,12,13,14,15,22,29,33,39,40,43,45],manifest:0,manipul:[39,41],manner:[12,14,24,33,42,43,44],manual:[0,11,13,14,25,41,48],map:[0,1,3,5,8,9,10,14,15,19,20,22],mappabl:43,mappedschema:31,mappedtyp:31,margin:[19,20],mark:[4,5,7,14,19,31,43],markdown:5,marker:[14,37],market:45,marshal:4,master:[34,45],match:[3,4,9,12,14,23,24,29,37,39,41,42,44,46],materi:44,math:20,mathemat:39,matter:[14,29,36,43],matur:[6,7,8,25,26,29,43,47],maturityd:[43,47],maven:[0,11,18,20],mavenloc:11,mavenpubl:11,maximis:12,maximum:12,maybestx:14,maybetraderequest:14,mbean:26,mean:[4,5,6,10,12,13,14,15,17,19,22,23,29,33,36,39,41,42,44],meandref:42,meaning:[6,7],meaningfulli:40,meant:[14,22,45],meantim:46,meanwhil:[42,44],measur:[8,36],mechan:[10,19,24,29,33],meet:[3,28,41,43,45],mega:30,mega_corp:[15,47],mega_corp_key:15,mega_corp_pubkey:47,megacorp:[15,47],member:[8,9,33,36],memori:[14,15,20,24],menlo:5,mention:[13,14,17,29,43],menu:[1,17,45],mere:8,merg:[12,33,39,41,43,45],mergeabl:43,merkl:[19,20],merkleroot:[23,29],merkletreeexcept:[23,29],mess:14,messag:[0,4,5,9,11,12,14,15,19,20,21,22],messagingserveraddress:[9,28],messagingservic:[24,28],met:[10,39,45],meta:[10,45],metadata:[26,40,45,48],method:[3,4,5,6,9,10,13,14,15,22,26,28,29,31,33,37,38,39,40,41,43,48],metric:[26,36],micro:[33,44],microsoft:1,mid:6,middl:[5,14,33],middlewar:[19,28],midpoint:45,might:[5,8,12,14,18,29,31,37,41,43,45],migrat:41,mike:12,mileston:[20,30],min:42,mind:[5,14,29],mine:12,miner:12,mini_corp_pubkey:15,minim:[3,12,14],minimis:[6,7,12,24],minimum:[4,8,12,39,41],minor:[24,33,34],minu:43,minut:[0,1,14,16,29,32,45],mismatch:[12,43,47],miss:[5,9,14],mission:26,mistak:[33,37,41],mix:[0,5,33],mock:[15,45],mocknetwork:[15,25],mocknod:[15,28],mockservic:39,modal:45,mode:[9,25,27,30,33],model:5,modest:12,modif:[28,39,41,43],modifi:[1,6,7,8,10,11,14,18,19,39,41,43,45,47],modul:[5,9,15,30,32,33,41,43,45],moment:[14,15,33],monei:[29,41,43],monitor:[5,10,20],month:[8,14,34],monthli:45,more:[0,1,3,4,5,6,7,8,9,11,12,14,15,16,17,18,19,20,23,24,25,26,28,29,30,31,33,35,36,39,40,41,42,43,44,45,46,48],moreexecutor:5,mortensen:33,most:[0,3,5,8,12,14,17,24,25,26,38,43,44,45],mostli:43,motiv:[20,45],move:[3,7,10,12,14,15,27,33,34,36,41,42,43,44,45,47,48],movement:[14,43],movetransact:48,movetransactionbuild:48,much:[5,12,14,16,29,31,33,37,41,43],multi:[5,14,20,24,33],multigraph:42,multilater:[7,33],multipl:[3,4],multipli:8,must:[3,4,5,6,7,9,10,11,12,13,14,24,26,28,29,31,32,33,37,38,39,40,41,42,43,44,45],mustafa:33,mutabl:[5,12,39,43],mutablelistof:41,mutat:[12,28,41],mutual:[6,7,14,37],myfil:26,myident:[29,48],myinfo:[29,41,48],mykei:39,mykeypair:14,mylegalnam:[9,30,38],mynodeinfo:29,mypublickei:14,mysigningkei:[29,48],mysql:21,nail:5,name:1,namedbyhash:20,namespac:14,narrow:[3,5,27],nativ:[14,17,41],natixi:33,natur:[0,41,43],naval:6,navig:[1,11,32,36,45],navistar:6,nearestc:[9,11,30,38,45],neat:47,necessari:[5,6,19,29,33,34,45],necessarili:[31,39],nee:33,need:[0,1,2,3,5,6,8,10,12,13,14,15,17,18,19,22,23,26,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48],neg:[39,45],negoti:[12,39,41],neither:14,nest:[14,46],net:[3,7,8,9,10,11,14,15,26,28,30,31,32,33,35,36,38,40,41,42,43,45,46,47],network:[1,6,9,12,13,14,15,19,20,21,22,23],networkmap:[11,24,45],networkmapcach:[9,10,14,28,48],networkmapservic:[9,11],networkmapupd:42,neutral:21,never:[5,6,12,19,43],newdeal:29,newli:[13,45,48],newnotari:6,newowner:[43,48],newsecurerandom:33,newstat:41,nextdoubl:42,nextfixingof:13,nextlong:42,nextscheduledact:13,nfinal:40,nice:[29,43],nio:5,noddi:26,node:[0,1,4,7],node_dir:11,node_directory:38,nodea:[1,11,45],nodeb:[1,11,45],nodec:[1,45],nodefilt:22,nodehandl:[22,46],nodehost:22,nodeident:42,nodeinfo:[9,14,28,46],nodeinterestr:[10,29,41],nodenam:45,nodex:45,nodisruptionwindowm:22,non:[2,4,5,6,7,9,12,14,19,20,22,24,28,33,39,41],nonc:44,nondeterminist:46,none:[3,13,14,23,29,31,36,44],nonemptyset:33,nordea:33,normal:[3,4,7,8,10,11,14,18,22,23,24,25,27,28,33,39,40,41,43,44,48],north:43,notabl:[5,45],notari:1,notaris:[6,12,14,20,33,36,39,41,43,45,46],notary:14,notary_committed_states:36,notarychang:[33,41],notarychangeflow:6,notaryclusteraddress:[9,28],notaryexcept:48,notaryflow:[14,28,33,41,48],notaryident:[14,15,42,46],notarynod:[14,15],notarynodeaddress:9,notarysig:14,notarysignatur:[14,48],notarytous:39,note:[0,1,2,5,7,8,9,10,11,12,14,15],noth:[5,12,13,14,33,37,43,45],notic:[5,36,44,47],notif:[22,24,28,40],notifi:[24,25,48],notion:[8,12,33],notnul:[43,44],now:[1,5,11,12,14,15,23,26,32,33,36,38,39,41,42,43,45,46,47,48],nugget:43,nullabl:43,nullpublickei:43,number:[0,3,5,7,8,12,15,19,22,24,27,28,29,31,32,34,36,38,39,41,43,45],numer:[10,12],obj:[43,44],object:[3,4,5,7,8,9,12,13,14,15,19,20,21,24,26,29],oblig:[7,8,33,39,41,45],obligat:3,obligor:7,observ:[4,6,8,12,13,14,22,25,33,40,45],observatori:6,obsolet:[13,33],obtain:[5,6,9,13,14,15,17,23,29,30,33,36,45,48],obviou:[5,6,12,29],obvious:[0,8,19,25],occasion:[0,17,18],occur:[6,13,14,28,43,46],occurr:[6,14],odd:43,off:[14,20],offer:[14,18,28,31,45],offlin:24,offset:8,ofsecond:41,often:[5,7,8,12,14,18,29,41,43],oftenor:29,oil:33,old:[6,14,19,32,33,41,43,48],omit:[13,36],onc:[4,5,6,10,14,19,30,34,39,41,43,46],once:[1,2,8,11,13,14,19,20,24,25,30,31,32,36,38,39,40,41,43,45],one:[3,6,18,23,29,36,41,45],ongo:4,onledgerasset:[7,43],onli:[0,3,4,5,6,8,9,11,12,13,14,16,19,23,24,25,26,27,28,29,30,33,34,36,37,38,39,41,42,43,44,45,46,47,48],only:[14,24,28,32,38],onto:[4,5,14,24,43,47],opaquebyt:[33,42,46,47],open:[0,1,3,4,6,11,12,14,17,18,20,24,26,28,33,36,42,45,46],opengamma:[33,36],openjdk:17,openjfx:17,openssl:22,oper:[1,8,9,13,14,17,19,24,26,28,29,33,37,38,39,41,42,43,48],oppos:0,opposit:3,opt:[1,11,22,45],optim:5,optimis:33,option:[0,1,2,5,8,9,13,14,19,22,25,29,30,31,33,41,43,44,45,46,48],optional:[9,41],oracl:[1,8,10,12,17,19,20,21,23,24,26,28],oracleparti:29,orchestr:[21,33],ordain:8,order:[0,2,4,5,6,7,8,12,14,18,21,22,25,28,29,31,33,36,38,39,40,42,43,44,45,46],ordernumb:45,ordinari:[12,14,33,43],ordinarili:29,org:[2,9,38,43,44,45],organis:[0,31,32],orient:20,origin:[23,31,33,39,40,41,43,44,45,47],originalst:6,orm:[31,33],osx:45,otc:31,other:0,otherparti:[14,29],othersid:[14,40],otherwis:[1,4,5,9,10,11,13,14,24,28,29,37,41,42,43,46],our:[0,5,6,12,13,14,15,16,17,20,22,23,24,28,29,32,33,34,39,40,41,42,43,44,45,48],ourkei:41,ournotari:48,ourselv:[14,29,43,48],oursign:41,oursignatur:14,ourstat:41,out:[0,3,5,6,7,12,13,14,17,20,23,24,26,28,29,33,34,35,36,37,39,40,41,43,44,45,48],outcom:14,outer:44,outlin:[12,14,29,33],outpoint:12,output:[0,3,6,7,11,12,14,19,20,23,27,29,33,36,40],outref:[15,41],outsid:[11,12,14,28,29,38],outstand:7,over:[0,1,5,6,8,9,11,12,14,15,19,22,23,24,26,29,31,33,36,39,41,43,45],overal:[6,13,41,47],overdu:13,overflow:5,overhead:26,overidden:[9,11],overload:[14,39],overlord:19,overnight:39,overrid:[3,10,13,14,22,29,31,42,43,44],overridden:[10,11],overutilis:22,overview:1,overwhelm:12,overwrit:32,own:[1,5,6,7,11,13,14,17,20,22,24,25,26,27,28,29,31,33,34],ownablest:[14,39,43],ownedquant:42,owner:[13,14,31,39,41,43,44,47,48],owner_kei:31,ownership:[14,15,36,43,48],owningkei:[14,23,29,41,43,48],ozturk:33,p2p:[24,33],pack:43,packag:[10,17,31,33,39,45],packet:12,page:[1,9,18,29,34,36,45],pai:[7,14,27],paid:[7,8,12,36,43],pair:[1,12,14,15,28,29,30,39,41,43],pan:33,pane:18,paper:3,paragraph:22,parallel:[4,12,22,29,33,46],parallelis:12,param:[22,31,48],paramet:[4,5,10,13,14,22,26,29,33,39,40,41,43,44],parameteris:[12,22,41],parent:[14,19],pars:[29,39,43],part:[0,3,4,5,6,7,9,10,11,12,13,14,18,22,23,24,27,28,29,30,31,33,37,38,39,41,43,44,45],parti:[1,5,6,7,8,12,13],partial:[6,12,14,20,23,29,37],partialmerkletx:29,partialtx:[14,23],particip:[6,12,27,28,29,33,43,48],particular:[3,5,6,10,12,14,17,19,20,23,26,29,31,33,39,41],partner:[36,41],partyandrefer:[5,42,43,47],partyfromnam:40,partynod:15,partyrefer:[5,43],pascal:5,pass:[1,3,10,14,22,23,26,28,29,31,33,36,40,41,43,44,46,48],passphras:32,password:[1,4,9,11,24,26,27,30,33,36,38,42],past:[1,5,36,43,45],patch:[5,33],path:[5,9,10,11,13,18,22,24,26,33,36,41,42,43,45],path_to_loadtest_conf:22,pattern:[5,12,41,42],paus:[11,25],paycash:[42,46],paye:12,payer:[8,12],payload:29,payment:[1,7,8,12,13,14,19,27,29,36,43],pdf:[29,40],peer:[14,21,23,24,27,28,29,43,45],penni:[31,39,43],peopl:[5,12,14,16,19,43],per:[5,11,12,13,24],perfect:44,perform:[0,1,5,6,8,12,13,14,17,19,22,24,29,33,36,39,40,43,44,45],perhap:[5,12,24,38,43],period:[8,30,36,41],perman:[14,40,41,43,47],permiss:[4,9,20,21,24],persist:9,persistentcashst:31,persistentst:31,perspect:[12,14,28,43],pertin:45,phase:33,phrase:29,physic:[1,6,28,33,38],pick:[0,14,17,24,33,34,43],piec:[5,6,12,14,19,22,38,39,43,47],pip:2,pki:[12,33],place:[2,5,8,10,12,13,14,17,21,23,24,29,33,34,36,39,42,43,44,45],plai:[12,22,27],plain:9,plan:[12,14,29,32,33],platform:[6,8,10,11,12,13,14,16,17,20,23,33,36,37,39,43,45],plc:27,pleas:[1,5,9,17,27,31,33,36,40,45],ploadtest:22,plu:[9,28,39,47],pluggabl:33,plugin:[4,9],pluginservicehub:[10,11,14,28,29,33],pluginserviceregistri:45,point:[4,5,6,7,10,11,12,14,19,22,26,28,29,31,33,34,37,41,42,43,44,45],pointer:[6,14,39],pointless:5,polish:33,polit:36,poll:[22,30],pool:[5,12],poor:12,pop:[18,45],popul:[28,41],popular:16,popup:[17,18],port:[0,1,9,11,22,27,28,33,34,36,38,45],portal:1,portfolio:[1,20,33],portion:41,posit:[5,12,14,20,43,48],possess:[6,14,48],possibl:[3,12,14,17,22,28,29,30,33,36,40,41,43,47],post:[28,45],postgr:21,potenti:[5,6,14,16,29,36,43,45],pound:[39,43],power:[12,28],practic:[9,12,33,36,41,43],preced:[0,43],precis:[6,12,21],precondit:[5,43],predic:46,predict:22,predominantli:17,prefer:[0,1,5,18,27,31,45],prefix:[5,31],preliminari:36,prepar:[12,33,43],prescrib:38,present:[1,3,4,6,7,8,9,10,11,14,21,22,25,29,31,33,35,36,39,41,43,44,45,48],preserv:[6,12,41],press:[17,45],pretend:[26,33,39],pretti:[12,14],prevent:[24,33,36,37,41,43],previou:[12,14,22,33,39,44,45,47,48],previous:[8,13,29,33,45,48],price:[12,14,29],primari:[17,29],primarili:[0,7],primit:[39,47],print:[4,26,33,36,37,38,40,42,46],println:[40,42,46],printorvisualis:42,prior:48,privaci:[5,6,12,14,21,29,33,41,43],privat:[1,5,9,10,12,14,15,24,29,30,31,38,41,43,45,47],privatefoo:5,privatekei:[14,28],probabl:[0,43],problem:[6,12,14,17,18,29,38],proce:[1,14],procedur:[14,30,43],process:[0,1,3,4,6,8,9,10,11,12,13,14,20,21,26,27,28,29,30,33],processor:[12,22],produc:[2,13,25,41,43,46,47],product:[0,5,11,13,16,17,21,33,34,36,39,41,45],profil:[26,32],profound:12,program:[4,5,12,26,28,33,36,39,43],programmat:42,progress:[1,6,8],progresstrack:[14,29],project:[0,1,11,17,18,28,30,32,33,36,41,43],prolif:33,promis:33,prompt:[17,45],proof:[7,12,23],propag:[4,14,26,43,44,45,47],properli:[14,28,37],properti:4,proport:36,propos:[14,28,37,41,45],proprietari:[33,36],prose:[29,39,43],prospectus_hash:40,protect:[14,28,30,36],protocolhandl:40,protocolvers:4,prototyp:[5,21,29,33,35,43],provabl:41,prove:[6,12,43],proven:36,provid:[0,1,2,3,4,5,6,7,8,9,10,11,12,14,15,17,19,22,23,24,25,26,27,28],provision:39,proxi:[4,40,42,46],pseudo:29,pseudonym:39,ptx:[14,29,40],pubkei:47,publicfoo:5,publickei:[14,20,28],publish:[11,20,29],publishtomavenloc:32,pull:[18,41,45],punish:29,purchas:[1,14,36,45],purchaseord:45,purchaseordercontract:45,purchaseorderst:45,pure:[7,12,29,46],purpos:[1,6,7,14,19,24,31,35,36,38,39,41,42,43,45,46],push:[4,24,34],put:[5,14,19,20,22,34,41,42],putti:1,python:[2,33,45],qualifi:[9,10,31],qualiti:41,quantiti:[3,12,22,39,41,42,43,45,46],quasar:[10,11,14,19,28,29,41,45],quasar_vers:45,queri:[4,8,9,10,13,28],queryablest:[28,31],queryrequest:29,question:[5,6,13,18,24,29,39,44],queu:[19,24],queue:[4,5,14,20],quick:[29,45],quickcheck:33,quickli:[12,19,30,37,43],quit:[4,5,6,14,17,43],r3cev:22,r3corda:[11,33,45],r3dlg:34,r3prototyp:[2,41],raft:[9,20,28,33,35],rais:[3,6,36,44],ran:0,random63bitvalu:44,random:[12,13,22,24,27,33,36,39,41,42,48],randomis:[33,40],randomli:[22,27,42],rang:[1,3,6,31,45],rapid:[5,11,21,34],rare:[9,39],rate:[1,5],ratesfixflow:[23,29,41],rather:[3,5,12,14,18,24,25,33,38,41,42,43],raw:[1,24,26,36],rdbms:[31,33],rdms:33,reach:[6,8,12,13,29,33,36],reachabl:14,react:22,reactiv:33,read:[1,5,9,11,12,14,16,20,21,23,26,28,29,33,43,45],readabl:[9,14,16,36],reader:20,readi:[1,3,34,43,45],readili:[39,44],readm:[20,45],readme:[5,45],real:[5,25,29,30,33,36,39,41,43],realis:14,realist:39,realiti:[8,46],realli:[5,6,12,14,23,29,43],reason:[5,6,8,12,14,17,22,33,37,39,43],reassign:43,recal:8,receipt:[28,36],receiv:[4,7,8,10,12,14,19,22,24,28,29,33,34,36,37,40,41,43,45,46],receiveandcheckproposedtransact:14,receiveandvalidatetraderequest:14,received:29,receiving:14,recent:[1,17,33,45],recheck:41,recipi:[7,12,36,40,43,46],recognis:[10,12,14,17,43],recommend:[0,1,5,17,24,35,36,45],record:[6,13,15,19,28,31,36,40,41,45,48],recordtransact:[15,28,41,48],recreat:[14,18],red:[8,23,45],redeem:[3,7,27,43,44],redempt:43,redeploi:45,redesign:33,redirect:38,reduc:[5,11,36],redund:5,ref:[14,15,29,39,41,42,46,47],refactor:33,refer:[0,5,6,7,8,9,10,12,13,14,17,19,20,28,29,33,35,36,39,40,41,42,43,44,45,47,48],referenc:[6,40,45],refin:33,reflect:[1,14,20,22,33,41,43,44,45],refresh:[0,17,33,45],refus:18,regard:[6,17,38,41],regardless:14,regener:[8,34],regist:1,registerflowiniti:[10,14,29],registerrpckryotyp:[10,42],registr:[10,28],registri:10,regress:33,regul:[41,43],regular:[1,14,19,26,36,38,39,43],reifi:41,reissu:43,reissuanc:12,reject:[9,24,28,29,30,41,43],rel:[9,12,16,17,26,29,33,41],relabelablestep:14,relai:40,relat:[8,13,20],relationship:[28,43],relax:[22,30,33],releas:[4,19,20,27,30],relev:[3,10,11,12,13,19,28,29,33,39,41,43,44,48],reli:[4,11,12,33,36,37],reliabl:28,relianc:12,relic:26,religi:5,remain:[11,13,14,29,33,41,43,45],rememb:[5,13,18,37,41],remind:[14,37,44],remot:[0,10,11,18,22,25,28,36,38,41,45],remote_branch_nam:45,remotemessagingport:22,remotenodedirectori:22,remotesystemdservicenam:22,remov:[14,23,27,33,34,43],renam:[14,33],render:[5,14,25,27,33],renderifsupport:40,repay:44,repeat:[0,5,8,14,40],replac:[4,6,8,17,26,33,34,36,39,41,42,43,45],replai:33,replic:[9,12,35,36],repo:[0,1,20,45],repoint:6,report:[14,27,33,44],repositori:[0,5,11,17,18,32,33,34,36,45],repres:[1,5,7,8,10,12,14,22,27,28,29,31,33,39,41,42,43],represent:[4,8,31],reproduc:41,republish:45,request:[0,4,6,9,10,12,14,20,22,24,28,29],requestingparti:48,requir:[0,1],requiredcommand:[3,33,44],requiredflow:10,requiresinglecommand:[43,44],requirethat:[43,44],research:33,resel:29,resend:28,resent:28,reset:[8,25],reshap:12,resid:28,residu:41,residualamount:41,residualoutput:41,resolut:[12,14,33,48],resolv:[5,14,15,29,36,38,39,43],resolvetransactionsflow:[14,15,40],resolvetransactionsflowtest:15,resourc:[0,1,4,9,10,12,14,22,29,40,41,45],resp:29,respect:[0,5,12,14,41,45,46],respend:12,respond:[14,28],respons:[4,6,10,12,13,14,24,28,29,31,41,42,45,46,48],rest:[6,10,12,14,21,24,26,33,44,45],restart:[10,14,28,30],restor:[10,14,18,19],restrict:[1,3,5,25,36,41],restructur:[33,44,45],restructuredtext:2,result:[5,6,8,9,12,14,15,27,28,29,30,31,33,36,37,40,41,43,45,48],resultfutur:15,resum:[14,28,30,33],resurrect:14,resync:17,retain:24,rethrown:4,retri:[14,21,24],retriev:[8,14,30,35,40],retrieveoutput:47,returnvalu:[40,46],reus:[4,12],reusabl:[3,19,29,33,40,43],reveal:[6,12,14,23,29,33],revers:[14,28],revert:7,review:[5,33,34,45],revis:[8,18,41],rewrit:14,richer:11,right:[1,5,14,17,18,26,29,33,34,36,37,41,45],rightmost:23,rigid:12,rigidli:5,risk:[14,36],robert:33,robust:33,rogerwilli:45,role:[12,13,27,28,36,42],roll:[8,14,33,36],rollov:[39,43],root:[1,9,11,23,24,28,30,34,38,41,45],roothash:29,rotat:[26,33],roughli:[6,34],rout:[14,15,17,24,33],row:[26,27,31,36,39,43],rpcclienttonod:[42,46],rpcexception:4,rpckryo:4,rpcreturnsobserv:4,rpcsincevers:4,rpcuser:[9,27,38,42,45,46],rui:33,ruin:47,rule:[5,14,28,29,33,36,43],run:[0,1,2,3,4,5,6,9,11,12,13,14,15,17],runbuy:36,runconfigur:[17,18],rundemonod:[27,33],runexampleclientrpc:45,runnetwork:15,runnod:[0,11,33,36,42,45],runparamet:22,runrecipi:36,runrpccashissu:36,runsel:36,runsend:[0,36],runshellcommandgetoutput:22,runsimulationnod:27,runtim:[5,14,45],runwebcashissu:36,sacrif:45,safe:[4,5,10,12,14,30,37,42,46],sai:[5,6,12,17,22,36,38,43,44,48],sake:[36,46],sale:43,same:[0,1,4,5,6,7,8,9,11,12,13,14,22,24,28,29,30,33,36,38,39,41,42,43,44,45,47],sampl:[0,10,11,14,20,25,26,27,33,36,40,45],sanction:43,sandbox:[12,13,21,33,37],saniti:14,santiago:33,sate:48,satisfi:[36,39,43,44],save:[5,14,33,43],saw:46,scala:[16,43],scalabl:[5,12],scale:[8,37],scenario:[12,25,28,39,41,45,46],scene:[14,43],schedul:[8,10],schedulablest:[13,28],scheduledact:13,schedulerservic:28,schema:20,schemafamili:31,schemaopt:31,schemaservic:31,scheme:[23,28],schroeter:33,scienc:45,scope:[3,10,12,27,40,44],scotiabank:33,scotland:44,scrape:26,scratch:[39,43,45],screen:[1,5,17,18,27,33,43],script:[0,2,11,12,33,36,40,45],scroll:36,scrub:14,seamless:[16,17],seamlessli:17,search:[1,27,28,41,43],sec:45,second:[3,8,10,14,15,22,29,36,39,40,41,43,45,46],secondari:14,secp256r1:33,secret:9,section:[9,12,22,29,33,34,41,45,48],securehash:[15,23,29,39,43,44,48],securerandom:33,see:[1,2,3,4,5,6,7,8,9,11,13,14,15,17,18,22,23,25,29,30,31,32,33,35,36,38,39,40,41,42,43,44,45,46],seed:14,seek:[12,33],seem:12,seen:[5,8,10,14,29,43],segment:11,select:[1,3,6,17,18,31,33,36,41,43,44,45],selector:3,selectschema:31,self:[11,22,33,36,46],selfissuecommand:22,selfissuest:22,selfissuetest:22,selfsignedtx:41,sell:[14,41,43,44,47],sellamount:41,sellerownerkei:14,sellersig:14,sellertradeinfo:14,semi:[1,12],send:[1,5,6,12,14,15,23,24,26,28,29,33,34,36,40,41,43,45,46,48],sendandrec:[14,29],sender:[12,14,36,40],sending:29,sendsignatur:14,sens:[8,29,43,44],sensit:[13,23,36,37],sent:[13,14,24,29,33,39,40,41,43],separ:[0,1,3,6,9,10,11,12,14,17,23,24,26,29,33,36,39,41,43,45],septemb:36,sequenc:[12,28,33,46],sequenti:[14,46],seri:14,serial:[4,10,21,28,43],serialis:[4,5,10,12,14,19,21,29,33,43],seriou:[12,34],serv:[11,45,46],server:[4,9,10,11,21,24,26,28,30,33,42,45],servic:[1,9,10],servicehub:[10,11,14,24,28,29,41,48],servicehubintern:33,serviceident:29,serviceinfo:[36,42,45,46],serviceload:[10,29],serviceplugin:[10,29],servicetyp:[9,28,36,48],servlet:45,session:[13,24,28,33],sessionid:13,set:[1,3,4,8,9,10,11,12,13,14],setlifecycl:3,setof:[3,14,15,36,40,41,42,44,45,46,48],setter:[31,43],settim:[14,29,39,41],settl:[3,7,15,39,40],settlement:[7,14],setup:[11,13,15,25,30],sever:[0,9,11,12,14,24,28,29,31,35,36,38,42,43,46,47],sha256:[23,39,43,44],sha256sum:26,sha:[12,26],shape:12,share:[0,1,7,8,12,14,19,28,29,33,37,40,41,43,45],shasum:26,she:43,shell:[22,45],ship:1,shoot:37,shortcut:21,shorthand:47,shortli:0,should:[0,1,3,5,6,7,10,11,12,13,14,18,20,21,22,23,28,29,30,31,32,33,36,37,38,39,40,41,42,43,44,45,46,47],shoulder:5,shouldn:[14,23,41,43,45],shoutout:33,show:[1,12,16,18,25,27,28,33,36,43,44,45],shown:[1,4,9,14,15,25,39,41,45],shut:46,shutdown:[14,28],side:[4,12,13,14,17,25,29,36,37,39,40,41,45],sidebar:25,sidenot:38,sig:[29,33,43],sign:[6,8,9,12,14,15,19,20,21,23,24,28],signal:[19,41],signatori:41,signatur:[6,7,12,14,19,20,21,23,27,29,33,36],signaturesfromsel:14,signedtransact:[14,15,20,39],signer:[23,29,36,41,43,44,47],signfirsttx:15,signific:[0,12,29,33],significantli:[8,22,39,40],signing:[14,29],signingkei:29,signoff:6,signrequest:29,signwith:[14,15,39,40,41,43,48],signwithecdsa:[14,29],signwithourkei:14,silver:5,similar:[5,12,14,17,24,29,33,41,42,43,44],similarli:[31,41],simmvaluationdemo:[1,36],simpl:[0,4,5,7,8,9,10,12,14,15,17,18,20,21,22,26,28,29,33,35,36,39,40,41,42,43],simplecp:47,simplecpdoesntcompil:47,simplecpmov:47,simplecpmovefail:47,simplecpmovesuccess:47,simpleissuancewithtweak:47,simpleissuancewithtweaktopleveltx:47,simplenam:31,simpler:[12,16,44],simplest:[12,14,43],simpli:[1,5,11,12,14,15,22,28,31,33,35,39,43,45,47],simplic:41,simplif:33,simplifi:[3,5,7,12,28,35,39,41,43],simul:[1,9,20],simultan:[12,14,36,39,43],sinc:[43,44,45],singl:[3,4,5,7,10,12,14,15,20,22,25,26,28,29,33,35,36,38,39,40,41,43,44],singlemessagerecipi:24,singleownerst:48,singleton:[10,14,29,43,44],singletonserializeastoken:[10,29],site:[5,33,34],situat:[5,12,23,33,41],size:[1,5,8,12,14,26,29,43,44,45],skeleton:15,skip:[14,39,43,45],sl4j:26,slack:[17,20],sleep:[22,42],slf4j:14,slightli:[0,35,41,43],slip:34,slot:33,slow:[5,12,22],slowest:12,small:[3,4,12,13,14,26,29,33,37,40,43],smaller:[3,33,44],smallest:39,smart:[15,20,21,29,33,41],smooth:43,snapshot:[12,29,32,33,34,40,42],snapshots:45,snide:2,snippet:[14,45],socket:26,softwar:[12,14,34,37],sofu:33,sold:[14,39],sole:[24,33],solut:14,solv:[12,14,29],solvenc:29,some:[0,1,4,5,6,7,10,12,13,14,15,17,21,22,23,26,27,28,29,31,33,36,38,39,41,42,43,44,45,46,47,48],somed:43,somehow:22,someon:[6,12,43,48],someth:[4,5,8,12,14,29,33,43],sometim:[0,12,14,19,26,39,41],someusernam:22,somewhat:[4,12,14,22,33,36],somewher:43,sonatyp:32,soon:[33,43],sophist:[12,20],sort:[14,29,33],sound:[5,14,43],sourc:[1,8,11,13,14],sourcejar:11,sourcenotari:41,sourceset:26,sparingli:5,spawn:[10,46],speak:33,spec:33,special:[3,4,6,12,14,44,47],specif:[3,4,6,7,10,11,12,13,14,17,19,22,24,26,28,33,39,41,43,44,45,46],specifi:[1,2,3,4,5,6,7,9,11,12,14,19,21,22,23,30,31,33,38,39,40,41,43,44,45,46,47,48],speed:[12,14,16,45],spend:[12,14,15,21,27,28,37,38,41,43,46,47],spent:[12,43,47],sphinx:2,sphinx_rtd_them:2,spin:22,spirit:33,splash:[17,18],spline:39,split:[3,12,23,24,33,39,41,43,44],splittabl:43,splittablerandom:[22,42],spot:33,spread:[6,14],spreadsheet:29,spuriou:3,sql:[21,31,33,36,45],src:[9,14,28,40,45,46],ssd:1,ssh:[1,22],sshuser:22,ssl:[9,33],sslkeystor:[9,30,45],stabil:45,stabilis:34,stabl:[4,10,20,34,42,45],stack:[10,14,26,28,29],stage:[5,7,14,39,41,43],stai:[12,28,41,43,44],stake:12,standalon:[25,29,33,42],standard:[3,5,10,11,14,17,19,25,26,28,33,36,38,39,41,42,43,44,45],standardis:[3,12,39,41],start:[0,1,4,5,8,10],startflow:[14,15,33,40,42,46],startflowdynam:[14,42],startflowpermiss:[42,46],startnod:[42,45,46],startprotocol:[9,38],startup:[9,10,26,33],startwith:42,state:[0,3,4,6,7,8,9,10],stateandref:[6,14,29,33,39,41,43,48],statehistori:48,stateless:12,statemachinemanag:[10,14],statemachinerunid:14,statement:[5,12,14,29,43],stateref:[12,13,23,31,39,41,48],statesoftyp:[41,43],staticservedir:10,statist:26,statu:[41,45],status:12,stdlib:45,stem:43,stereotyp:41,still:[6,12,13,14,18,25,29,33,36,41,43],stock:[12,29],stone:22,stood:31,stop:[5,14,28,45],stopnod:15,storag:[9,12,14,15,19,20],store:[6,9,10,11,14,15,18,26,28,30,33,35,36,39,41,43,45,48],stori:[5,33],straight:1,straightforward:[14,43],strain:22,straincpu:22,stream:[4,14,24,25,33,40,42,46],stress:[5,22,33],strictli:[8,10,12],string:[0,9,14,22,29,31,36,39,42,43,45,48],strip:43,strong:16,strongli:17,stub:[33,36],stuck:20,studi:43,stuff:5,stx1:15,stx2:15,stx:[14,39,40],sub:[1,4,5],subclass:[7,14,31,39,43],subclaus:44,subdirectori:26,subflow:[6,10,14,28,29,41,48],subfold:[10,28],subgroup:12,subject:[9,11,19,24,36,45],submiss:29,submit:[1,5,6,14,22,24,30,33,36,45],subnet:45,subscrib:[4,24,33,40,42],subscript:1,subsequ:[19,30,41,43,46,47],subset:[7,23,33,44],substanc:45,substitut:[9,10,41],subsystem:[10,24],subtask:14,subtl:[5,12],subtract:39,subvert:37,success:[3,24,36,41,46],successfulli:[36,38,40,42],successor:[6,13,16],succinct:5,sudo:2,suffer:[12,36],suffic:14,suffici:[12,24,29,33,34,36,39,41,42],suffix:45,suggest:[11,17,24,26,43],suggestinterestrateannouncementtimewindow:[13,29],suit:[33,40],suitabl:[13,24,28,29,34],suitablecashst:41,sukrit:33,sum:[22,36,41,42,43,45],sumcashbi:[14,43],summari:[1,20,33,34,39],sumorthrow:3,sumorzero:3,sun:5,superclass:[7,33,39],superior:5,supersed:12,superset:9,supertyp:43,suppli:[7,22,42],support:[3,4,5,6,7,8,9,10,11,12,14,16,17,20,21,24,25,26,29,30,31,33],supportedschema:31,suppos:[14,43],suppress:[5,33],suppresswarn:5,sure:[6,32,33,34,37,40,43,45,46],surfac:14,surround:5,surviv:14,suspend:[6,11],suspens:[10,28],swap:1,swapping_signatures:14,swapsignatureswithsel:14,sync:[28,43,45],synchronis:[5,6,12,28,36],syntax:[0,16,43],system:[0,4,6,9,11,12,14,17,18,21,22,23,24,26,27,28,31,33,43,45],systemd:[22,38],systemus:24,tab:[1,5,11,17,18,33,36,45],tabl:[11,26,27,28,31,33,36,45],tableprefix:31,tackl:33,tag:[4,5,19,34,45],tag_nam:45,take:[1,3,5,8,10,13,14,15,21,22,23,26,29,30,33,34,36,37,39,41,43,44,45,47],taken:[1,10,43],talk:[15,44],tamper:14,target:[2,5,9,12,15,16,25,26,45],tcp:[11,26,36,45],tear:20,teardown:15,techniqu:[5,12,21,29,45],tell:[2,14,42,45],templat:[0,9],temporari:[11,14,24],temporarili:[14,34],tempt:[37,43],ten:43,tend:19,tenor:[8,26,29,39],term:[1,3,7,9,12,13,19,24,36,38,39,44],termin:[8,11,14,26,28,33,36,42,45],terminolog:12,test:[0,1,2,3,7,9,11,14],test_tx_time:47,testcompil:45,testnam:22,testnet:[9,11,30,33,38,45],testpassword:46,testtimelock:43,testuser:46,text:[1,5,18,26,33,45,47],than:[3,4,5,6,11,12,14,17,18,24,25,26,29,30,33,39,41,43,45,47],thank:33,thei:[0,1,3,4,5,6,7,8,10,11,12,13,14,19,20,22,23,24,25,26,28,29,31,33,34,36,37,39,40,41,43,44,45],theirsign:41,theirstat:41,them:[0,3,4,5,8,9,10,12,13,14,15,17,18,20,21,22,23,24,26,28,29,31,33,34,36,38,39,40,41,42,43],theme:[33,37],themselv:[4,14,15,22,24,25,28,29,36,37,39,42,43,44,45],therefor:[0,4,10,11,12,14,18,19,21,28,34,36,37,41,43],thi:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,17,18,19,20,22,23,24,25,26,27,28,29,30,31,32,33,34,36,37,38,39,40,41,42,43,44,45,46,47,48],thin:24,thing:[0,5,12,13,14,15,20,21,22,26,29,33,37,39,40,42],think:[5,12,14,18,24,37,43],third:[12,23,33,36,45],thisstateref:13,thoma:33,thorough:14,those:[0,1,4,6,12,13,14,26,29,36,37,43,44,45],though:[14,23,26,29,43],thought:[12,16],threadsaf:5,three:[1,3,11,14,23,27,36,39,43,44,46],threshold:[19,26,28,33,39],through:[3,4,8,10,12,13,14,17,24,25,26,28,29,33,41,43,45,47],throughout:45,throughput:[6,12],thrown:[4,14,37,43],thu:[3,5,6,9,12,13,26,28,29,33,39,41,43,44],tick:45,ticket:14,tidi:15,tighten:43,tightli:14,time:[0,1,5,6,7,8,11,12,13,14,15,17,18,19,20,25,26,28,29,30,31,33,36,39,40,41],timelin:43,timem:43,timeout:4,timestamp:5,titl:18,tls1:28,tls:[9,24,33],toblock:[40,46],todo:[5,14,29,40,43],togeth:[1,3,7,10,12,17,23,33,43,44,45],toinstant:45,token:[3,10,14,39,41,44],tokeypair:29,told:5,toledgertransact:[39,41],toler:[6,13],tolist:41,too:[5,14,17,33,41,43],took:[14,44],tool:[0,14,16,17,19,22,24,25,26,27,31,33,36,40,45],toolbar:18,top:[1,3,5,10,12,14,18,22,24,27,33,36,42,44,45,47],topic:[24,43],topicsess:[24,33],topolog:27,topriv:14,torn:33,toset:41,tosignedtransact:[14,15,39,40,41,43,48],tostateandref:41,tostr:[5,14,31,43],total:[0,12,22,26,39,41],totypedarrai:41,touch:[17,20],toward:[33,34],towiretransact:[23,29,39],trace:[14,26,44],track:[12,13],tracker:[14,33],trade:[1,6,8],tradeapprovalcontract:41,tradeoff:5,trader:[20,27,33],traderequest:14,tradit:12,traffic:[9,12,25],transact:[1,3,6,7,10,12,13,14,15,19,20],transactionbuild:[14,29,33,39,40,41,43,48],transactionforcontract:[3,43,44],transactionforverif:43,transactionst:[6,23,33,39],transactionstorag:28,transactiontyp:[14,33,40,41,48],transactionverificationexcept:47,transfer:[36,37,41,43,47,48],transferedfundsoutput:41,transit:[28,37,39,41,43],translat:28,transmit:[20,33],transport:[0,9,11,45],travel:43,treat:[11,24,33,37,43],tree:[14,18,19,20],tri:[0,12,17,33,43],tricki:[12,14],trigger:[3,7,13,14,22,28,29,36,44],trivial:[5,12,40],troubl:18,trust:[7,9,12,28,30,37,41],trustpass:[9,38],truststor:[9,28,45],truststorepassword:[9,38],truth:14,tune:20,tunnel:38,tupl:5,ture:12,turn:[3,12,14,39,43,44,47],tutori:[0,4,7,14,16,17,20,21,25,33,38,40],tweak:[22,33,47],twice:47,two:[1,3,5,6,7,8,11,12,13],twopartydealflow:13,twopartytradeflow:14,txb:39,txhash:[12,14,42,43,48],txid:41,txstate:29,txt:[26,45],type:1,typenam:14,typeonlycommanddata:[43,44],typetobui:14,typic:[0,1,10,12,13,14,24,26,28,29,31,37,39,40,41,43],ugli:14,ultim:[28,41],ultimat:26,unaccept:14,unacceptablepriceexcept:14,unavoid:14,uncertain:36,unchang:33,unclutt:14,unconfirm:41,unconsum:[28,31],undelet:[17,18],under:[2,11,22,28,33,34,36,39,42,43,44,47],undergo:33,underli:[7,8,12,14,33,39],underscor:5,understand:[0,12,25,26,29,41,43,44,45],unencrypt:9,unexpect:[14,37,45],unfinish:14,unfortun:[14,26,37,43],unicredit:33,unifi:33,uniform:13,unilater:41,unindex:18,union:41,uniqu:[6,12,13,14,24,28,29,30,32,33,39,40],uniqueidentifi:[20,33],uniquenessprovid:28,unit:[0,3,6,12,14,15,18,22,24,28,29,33,39,41,43,45,47],univers:33,unknow:6,unknown:[39,41],unknownfix:29,unless:[5,14,29,34,43,45],unlik:[28,43],unlike:[7,10],unlink:18,unlock:9,unmerg:45,unnatur:12,unpack:[11,28,43],unprocess:[3,44],unread:14,unrecognis:43,unrel:[43,44,45],unresolv:17,unschedul:13,unserialis:14,unset:8,unspecifi:46,unspent:[12,19],unstarted:14,unsubscrib:4,unsubscript:4,unsupportedoperationexcept:[4,43],until:[4,6,8,12,13,14,15,28,29,33,34,36,38,45,47],untrust:14,untrustworthydata:[14,33,37],unverifiedtransact:47,unwrap:[14,29,33,41],upcom:[13,33],updat:[4,10,11,12,14,18,22,24,28,33,34,41,42,43,45,46],update:[17,46],upgrad:[14,18,31,33,43],upgrade:33,uphold:43,upload:20,uploadattach:40,uploadrat:36,upon:[8,11,14,19,28,36,41,43,45],upward:34,urandom:22,url:[9,11,26,30,33,36,38,45],usa:27,usabl:[0,33,34,43],usag:[0,5,14,20],usage:[3,42],usb:45,usd:[22,27,42],use:[1,5,7,12,27,36,45],usehttps:[9,38],useless:43,user1:[9,27,36,38,45],usernam:[1,4,9,24,26,27,32,36,42],using:3,usr:2,usual:[5,11,12,36,41,43,44,45],usualli:[3,34,44,45],utc:13,util:[6,9,11,15,17,20,26,28],utilis:[25,42],utiliti:30,uuid:[33,39],vagu:5,val:[3,5,6,13,14,15,22,23,29,31,39,40,41,42,43,44,45,46,47,48],valid:[1,4],validatedtransact:15,validfrom:43,valu:[5,6,7,8,9,10,12,14,23,27,28,29,33,35,36,41,43,44,45,47],valuabl:29,valueof:42,vanilla:[7,8],vari:20,variabl:[5,8,11,12,14,32,43],variant:[28,43],variou:[5,10,12,14,24,26,28,33,36,37,43,45],vault:[10,14,20,22,27],vaultandupdat:[42,46],vaultservic:[10,14,28,41],vaultsselfissu:22,vcs:17,vega:33,vehicl:12,vendor:[21,26],verbos:43,verdict:41,veri:[5,7,9,12,14,17,19,26,28,29,36,37,43,47],verif:[0,3,7,9,12,19,21,23,24,28,29,33],verifi:[3,6,12,14,15,19,20,23,28,29,33,36,39,40,41],verifiedtransact:[40,42],verifyclaus:[3,44],verifying:14,verifylifecycl:3,verifypropos:33,verifysignatur:[14,41],versa:[7,8,12,14,39],versionnumb:45,versu:14,vertic:5,vet:37,vice:[7,8,12,14,39],video:33,virtual:[1,10,12,19,37],visibl:[1,6,12,20,23,27,28,36],vision:[20,45],visit:[1,9],visual:[27,33,36],visualis:[24,25,42,45],visualvm:26,vital:14,vpn:38,wai:[3,4,5,6,11,12,13,14,18,19,22,23,24,26,27,29,31,33,36,38,41,43,45,47],wait:[13,14,15,18,22,28,29,33,36,40,45,46],waitforallnodestofinish:[42,45],wake:33,wallet:[12,13,14,19,33,43],want:[0,3,4,5,12,14,18,20,22,23,26,29,33,36,37,39,43,44,45,46,47,48],warn:4,watch:[20,37,40],weak:[29,39],wear:34,web:[1,9,10,11,21,26,28,29,33,36],webaddress:[9,38],webapi:10,webapp:33,webinar:20,webport:[11,45],webserv:[33,38],websit:[1,17,18],week:16,weekend:8,weight:39,well:[0,2,5,6,8,10,12,13,14,17,19,21,23,26,28,31,33,40,41,43,44,45],went:5,were:[3,5,12,14,28,29,36,41,43,45],what:[1,5,6,7,8,12,13,14,15,18,20],whatev:[5,14,25,28,29,39,41],when:[0,1,3,4,5,6,7,8,9,10,11,12,13,14,15,17,18,22,24,25,26,27,28,29,30,31,33,36,37,39,40,41,42,43,44,45,47],whenev:[5,17],where:[1,4,5,6,11,12,14,17,18,19,20,22,23,25,26,27,28,29,31,33,34,36,39,40,41],wherea:[8,18,36],wherebi:[1,44],wherev:26,whether:[3,4,6,7,14,22,28,29,33,38,39,43,44],which:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,17,18,19,20,21,22,23,24,25,26,28,29,31,33,34,36,38,39,40,41,42,43,44,45,46,47,48],whilst:[12,14,25,28,29,33,37,43],white:[10,20,33,45],whitelist:[7,10,11,13,14,42],who:[5,9,12,14,16,24,29,33,36,39,43,45],whole:[23,28,35,47],whom:[7,12],whose:[7,26,39],why:[5,12,16,20],wide:[4,5,23],widescreen:5,widespread:5,widget:[27,45],width:5,wiki:[43,44],wikipedia:[43,44],wipe:18,wiretransact:[14,20,23,39],wish:[1,11,12,14,29,31,32,33,36,39,41,43,45],wit:38,withattach:15,within:[2,5,6,9,10,12,15,16,17],withitem:[39,41,43],withkei:[14,41],withnewown:[14,43],without:[0,5,14],withoutissu:[14,43],withoutown:[43,44],withowner:[43,47],won:[14,24,27,29,33,42,43,45,46,47],word:[5,6,9],work:0,worker:5,workflow:[1,10,41],workflowtransactionbuildtutori:41,workflowtransactionbuildtutorialtest:41,working:29,workspac:[9,10,11,28,30,41],world:[9,12,14,25,27,29,36,38,41,43,47],worn:43,worri:[5,14,43,45],worst:12,worth:[5,37,43,44,45],worthless:29,would:[0,4,5,7,8,10,11,12,14,17,19,21,25,26,29,36,37,39,40,41,43,44,45,46,48],wouldn:29,wow:45,wrap:[3,5,14,24,26,28,33,37,39,43,44],wrapper:[0,5,6,14,42,45],write:[0,3,5,10],written:[2,3,4,8,12,16,17,29,33,41,43,45,46],wrong:[4,5,14,47],wrote:12,wtx:[14,23,29,40,41],www:2,xcode:17,xml:26,xmx1024m:26,xsrf:45,xss:45,xterm:[11,36],year:[8,14],yet:[5,8,12,14,19,21,25,27,30,33,39,41,46],yield:[12,26],york:11,you:[0,1,2,3,4,5,11,12,13,14,15,16,17,18,20,21,22,23,24,25,26,27,29,30,31,32,33,35,36,37,38,39,42,43,44,45,46,47],your:[1,4,5,10],yourself:[12,13,20,37,39,44,45],zero:[3,12,19,29,43,45],zip:[12,26,36,40],zone:13,zoneddatetim:13,zoom:33},titles:["CLI vs IDE","Working with the Corda Demo on Azure Marketplace","Building the documentation","Clauses","Client RPC","Code style guide","Consensus model","Contract catalogue","Interest rate swaps","Node configuration","The Corda plugin framework","CorDapp basics","Data model","Event scheduling","Writing flows","Writing flow tests","Further notes on Kotlin","Getting set up","Troubleshooting","Glossary","Welcome to the Corda documentation!","What’s included?","Load testing","Transaction tear-offs","Networking and messaging","Network Simulator","Node administration","Node Explorer","Brief introduction to the node services","Writing oracle services","Network permissioning","Persistence","Publishing Corda","Release notes","Release process","Running a notary service","Running the demos","Secure coding guidelines","What is a corda network?","Data types","Using attachments","Building transactions","Client RPC API tutorial","Writing a contract","Writing a contract using clauses","The CorDapp template","Integration testing","Writing a contract test","Using a notary service"],titleterms:{"class":[4,29,42,43,44],"function":[14,43],about:18,abstractconserveamount:3,abstractissu:3,access:26,across:45,adding:43,administr:26,adopt:12,advanc:1,against:11,agreement:36,aka:36,allof:3,amount:39,anyof:3,api:[42,43],app:11,approach:29,artemismessagingserv:28,assert:29,assertion:5,asset:43,assign:48,attach:[26,40],attachment:[36,40],azure:1,background:[36,45],bank:36,basic:[3,11,29,41],befor:32,bind:29,bitcoin:12,brief:28,build:[2,11,30,41,45],buyer:14,cash:[7,39],catalogu:7,central:32,certif:[30,38],chain:47,chang:6,check:43,claus:[3,43,44],cli:[0,18],client:[4,29,42,45],cluster:22,code:[5,17,37,43],command:[0,41,43,45],comment:5,commerci:[7,43,44],commit:41,commod:7,comparison:12,compil:5,complain:18,complet:41,composit:[3,39],con:12,configur:[9,18,22,38,45],connect:38,consensu:6,consol:45,construct:43,content:20,continu:29,contract:[7,37,43,44,47],control:17,corda:[1,10,11,17,20,23,32,36,38],cordapp:[11,29,42,45],cordform:11,core:29,creat:8,cryptographi:39,cut:34,data:[12,23,29,39],databas:26,date:39,dbcheckpointstorag:28,dbtransactionmappingstorag:28,dbtransactionstorag:28,debug:[0,11,44,45],demo:[1,27,36,40],deploi:[1,45],detail:8,document:[2,20],download:26,e2etestkeymanagementservic:28,encumbranc:43,error:[4,5],ethereum:12,event:[13,28],exampl:[9,13,23,45],execut:36,explorer:27,extend:45,featur:14,field:9,file:[9,45],filteron:3,firstof:3,fix:26,flow:[14,15,28,29,37],format:9,framework:[10,28],frequent:0,from:[29,42,45],fungibleasset:39,further:16,futur:14,gather:41,gener:[5,41,43],get:[17,32,45],git:17,glossari:19,gradl:[0,11,17,18,45],group:[43,44],groupclauseverifi:3,guid:5,guidelin:37,handl:4,happen:[36,43],hibernateobserv:28,hide:[23,29],how:[13,22,43,44],http:45,ide:0,ident:28,implement:[13,14,28,29],includ:21,individu:22,initial:36,inmemoryidentityservic:28,inmemorynetworkmapcach:28,inmemorystatemachinerecordedtransactionmappingstorag:28,inmemoryuniquenessprovid:28,input:41,install:11,installat:18,instanc:8,integrat:46,intellij:[0,17,18,45],interact:45,interest:[7,8,26],interfac:[25,27],introduct:[13,14,28,29,36,41],irs:[1,36],issu:18,jcenter:32,jvm:17,kei:[28,39],kotlin:[16,17,18],kryo:[4,42],lack:18,length:5,lifecycl:[8,39,41],line:[0,5,45],load:22,local:[32,45],locat:9,log:[1,26,38],mac:0,machin:45,make:43,manag:28,map:[24,31],margin:36,marketplac:1,math:39,maven:32,memori:26,merkl:23,messag:[24,28],mileston:[33,45],miss:18,model:[6,12],monitor:26,multi:[39,43],multipl:6,name:5,namedbyhash:39,network:[24,25,28,29,30,38],networkmapservic:28,next:1,node:[9,11,26,27,28,38,45],nodeattachmentservic:28,nodemessagingcli:28,nodeschedulerservic:28,nodeschemaservic:28,nodevaultservic:28,non:43,notari:[6,28,35,36,48],notaris:48,notaryservic:28,note:[16,33],notion:36,nozerosizedoutput:3,object:31,obligat:7,observabl:4,off:23,opene:45,oracl:29,orient:43,other:3,output:41,overview:12,own:38,pai:29,paper:[7,43,44],parti:[14,39,43],partial:41,particular:43,per:29,permiss:30,persist:[11,28,31],persistentkeymanagementservic:28,persistentnetworkmapservic:28,persistentuniquenessprovid:28,plai:29,plugin:[10,11,29],portfolio:36,pre:1,pro:12,process:34,progress:14,project:45,properti:5,protocol:4,provid:[29,45],publickei:39,publish:32,put:43,queri:29,queue:24,raft:36,raftuniquenessprovid:28,raftvalidatingnotaryservic:28,rate:[7,8,26],rational:12,regist:[4,42],relat:[28,31],releas:[33,34,45],request:30,requir:[2,43],requisit:1,rpc:[4,42,45],run:[18,22,27,30,35,36,45],safeti:4,schedul:[13,28],schema:31,sdk:18,secur:[4,24,37,42],seller:14,servic:[11,24,28,29,35,45,48],set:[17,38],setup:32,sign:[29,30],signatur:39,signedtransact:41,simm:[1,36],simpl:44,simplenotaryservic:28,simul:25,singl:47,smart:43,snapshot:45,sourc:17,space:5,start:[11,14,38,43,45],state:[11,39,43],statemachinemanag:28,step:[1,34,36],storag:28,storageserviceimpl:28,structur:[3,45],style:[5,12],sub:[14,29],summari:44,support:39,suspend:14,swap:[7,8],task:0,tear:23,technic:8,templat:[11,45],test:[15,22,43,46,47],them:44,theori:14,thing:43,thread:[4,5],time:43,timestamp:6,track:14,trade:14,tradeoff:12,trader:36,transact:[23,29,39,41,43,47,48],transmit:43,tree:23,troubleshoot:[17,18],tune:26,tutori:42,two:[14,29],type:[3,24,39],uniqueidentifi:39,unix:0,upload:26,usag:[23,26],used:0,user:1,using:[11,29,40,43,45,48],util:30,utxo:12,valid:6,validatingnotaryservic:28,valuat:1,vari:29,vault:28,verif:39,verifi:43,version:[4,14,17],via:[0,17,18,29,45],view:[1,11],visibl:41,warn:5,web:45,welcom:20,what:[21,25,36,38,44],where:43,why:44,window:0,wire:4,wiretransact:41,within:[18,28],without:18,work:[1,44,45],write:[14,15,22,29,43,44,47],your:[11,14,26,38,42,43,45]}}) \ No newline at end of file +Search.setIndex({envversion:49,filenames:["CLI-vs-IDE","azure-vm","building-the-docs","clauses","clientrpc","codestyle","contract-catalogue","contract-irs","corda-configuration-file","corda-plugins","creating-a-cordapp","event-scheduling","flow-state-machines","flow-testing","further-notes-on-kotlin","getting-set-up","getting-set-up-fault-finding","glossary","index","inthebox","key-concepts","key-concepts-consensus-notaries","key-concepts-core-types","key-concepts-data-model","key-concepts-ecosystem","key-concepts-financial-model","key-concepts-flow-framework","key-concepts-security-model","key-concepts-vault","loadtesting","merkle-trees","messaging","network-simulator","node-administration","node-explorer","node-services","oracles","permissioning","persistence","publishing-corda","release-notes","release-process","running-a-notary","running-the-demos","secure-coding-guidelines","setting-up-a-corda-network","tutorial-attachments","tutorial-building-transactions","tutorial-clientrpc-api","tutorial-contract","tutorial-contract-clauses","tutorial-cordapp","tutorial-integration-testing","tutorial-test-dsl","using-a-notary"],objects:{},objnames:{},objtypes:{},terms:{"00z":49,"0_xx":16,"10000l":29,"100l":52,"14gb":1,"17t16":49,"1mb":12,"200mb":33,"3rd":43,"5000l":29,"500mb":33,"5xxx":0,"abstract":[3,9,12,35,36,38,40,49,50,51],"boolean":[13,29,40,48,49,50],"break":[12,16,36,41,47],"byte":[5,12,23,36,40,53],"case":[3,5,9,10,12,13,15,21,22,23,29,31,36,38,40,43,46,49,50,51],"catch":[5,12,40,44],"class":[],"default":[1,4,5,6,8,9,10,12,15,16,17,22,23,29,30,32,33,34,35,37,40,43,44,45,49,51],"enum":[40,48],"export":[12,33,38],"fa\u00e7ad":33,"final":[7,9,12,13,21,30,36,40,43,45,47,48,49,50,52,53],"float":[6,7,11],"function":[],"import":[3,5,11,12,15],"instanceof":[49,50],"int":[5,29,38,49,54],"long":[5,6,9,11,28,29,38,47,49,50,51],"new":[0,1,5,7,8,9,10,12,14,18,21,22,23,24,31,32,33,34,35,37,39,40,41,43,46,47,48,49,50,51,52,53,54],"null":[8,11,13,29,36,38,46,49,50,53,54],"public":[1,5,8,10,12,17,19,22,23,31,33,35,37,40,43,45,49,50,51,53],"return":[3,4,5,7,9,11,12,13,21,29,33,35,36,38,40,44,46,47,48,49,50,51,52,53,54],"short":[3,11,41,43],"static":[9,10,12,28,36,43,49,51,53],"super":[3,5,50],"switch":[12,40,49],"throw":[3,4,5,12,26,29,30,36,47,49,50,54],"transient":12,"true":[8,13,17,21,24,29,36,37,45,48,49,50,51],"try":[0,4,5,12],"var":[13,38,47,48],"void":[49,50,53],"while":[15,22,32,43,48,53],___:51,____:51,______:51,_________:51,_foo:5,_unless_:39,abil:[23,28,32,40],abl:[1,8,10,12,21,27,30,31,33,34,35,36,37,40,43,49,51,54],abort:[21,36,47],about:[],abov:[1,3,5,7,12,23,26,30,31,33,36,43,45,48,49,50,51,52,53],absent:[3,8],absolut:[8,21],abstractnod:[9,35],abstractstatereplacementprotocol:40,accept:[5,6,15,17,21,23,36,43,47,49],acceptablepric:12,acceptsfileupload:36,access:[],accid:12,accident:[5,44,47],accompani:[5,49],accord:[3,23,47],accordingli:[45,50],account:[1,22,23,29,39,40,46],accrual:7,accur:[21,43],achiev:[21,22,23,24,30],ack:40,acknowledg:[12,35],acquir:43,acronym:43,across:[],act:[3,8,12,21,35,36,40,43],action:[3,11,23,29,35,36,42,43,47,49,52],activ:[7,8,9,11,15,22,24,26,27,29,32,35,38,40,43,47,49,51],actor:[5,12],actual:[7,12,21,29,35,36,43,44,46,49,50,53,54],adapt:[5,12,36],add:[3,5,10,12,17,29,30,31,33,35,36,42,44,46,47,48,49,51,52,53,54],addattach:[13,46],addcommand:[12,36,47,49,54],added:40,addedg:48,addfix:36,adding:[],addinputst:[12,49],addit:[0,5,8,10,21,22,23,25,28,31,35,38,40,47,48,49,51],addition:[12,14,15,16,27,38,41,43,51],addmessagehandl:40,addnod:48,addoutputst:[12,49,54],address:[0,1,8,10,12,24,31,34,35,40,45,49,51],addsignatureuncheck:36,adequ:3,adjust:[1,5,7,41,49],admin:[34,35,37,39],administ:1,administr:[],admiss:[24,27],advertis:[4,8,31,35,40,42,43,49,52,54],advertisedservic:[10,43,48,51,52],advic:41,advis:[0,36],aesthet:43,affect:[16,36,45],affinityexecutor:5,afraid:5,after:[0,3,6,7,9,10,11,12,13,14,17,18,21,29,30,35,36,43,47,49,51,53],again:[7,12,13],against:[],agent:[24,29,33,35],agentlib:10,aggreg:[40,43,49,50],agil:21,agre:[1,7,11,12,17,23,43,44,47,51],agree:[7,43],agreement:[],ahead:[12,49],aid:[23,40,47,51],aim:[5,29],aka:[],albeit:40,albertsen:40,alert:16,algorithm:[19,21,22,23,27,40,49],alia:[8,39],alic:[52,53],alice:[17,22,34,48,49,52,53,54],alice_key:46,alice_pubkey:53,alicecli:52,aliceparti:54,aliceproxi:52,alicevaultupd:52,align:[16,40,47,51],aliv:[12,43],all:[1,2,3,4,5,6,7,8,9,10,12,13,14,15,17,21,22,23,24,26,27,28,29,30,31,33,34,35,36,38,39,40,41,43,44,45,46,47,49,50,51,52,54],allaslist:52,allevi:21,alloc:43,allow:[0,4,5,6,7,8,9,10,11,12,17,21,22,24,29,31,34,35,36,37,38,39,40,43,44,47,48,49,51,52,53],allpartysignedtx:[12,47],almost:49,along:[1,3,12,13,21,24,36,49,51,54],alongsid:49,alreadi:[5,10,11,12,21,27,30,36,37,39,40,43,46,47,49,50,51,53,54],alright:12,also:[0,3,4,5,6,7,8,9,10,11,12,13,15,16,17,18,21,22,23,25,28,29,30,31,32,33,34,35,36,37,38,40,43,46,47,49,50,51,52,53,54],alter:[8,12,33,47],altern:[1,2,5,8,22,31,32,33,34,49,51,52],although:[7,8,12,23,34,35,40,46,49,51],alwai:[5,11,12,16,22,23,33,38,45,47,49,51],amend:47,aml:24,among:51,amongst:[0,27],amount:[],amountrequir:47,amqp:[24,31,40],analysi:3,analyt:43,ancestor:23,ani:[0,1,3,4,5,6,7,9,11,12,13,15,17,21,22,23,24,25,27,28,31,33,34,35,36,37,38,40,41,42,43,44,45,46,47,48,49,50,51,52,54],annot:[4,5,9,12,31,38],announc:[36,41],annual:1,anonym:35,anonymis:[35,40],anoth:[1,4,5,10,12,16,17,21,23,24,28,31,33,34,35,36,37,40,43,46,49,50,53,54],another:47,answer:[5,36],answere:50,anti:51,anticip:5,any:[3,4,6,11,33,35,39,43,47,50],anycompost:50,anyon:[21,31,49],anyth:[12,13,22,23,25,44,49,50,51],anywher:[36,40,49],apach:31,apart:[21,40,47],api:[],app:[],appear:[16,36,43,49,51],append:[8,12,23,33],appendix:18,apple:[],appli:[5,6,7,10,27,29,34,47,49],applic:[9,10,17,23,24,25,31,35,36,40,43,44,49,51],applicat:[15,17],applyfix:7,appoint:21,approach:[],appropri:[1,5,28,31,35,36,38,40,42,47,51],approv:[11,12,37,39,47],approxim:21,april:40,apt:16,arbitrari:[3,5,12,22,23,36,44,48],arbitrarili:[23,52],architectur:[4,18,36],archiv:28,area:[0,27,38],aren:[4,11,19,49],arg:[10,40,48,51],argument:[4,5,9,10,12,23,29,48,49],aris:15,around:[12,13,21,22,25,30,40,41,47,48,49,51,52],arrai:[48,51],arrang:[12,24],arraylist:36,arriv:[12,17,36,52],arrow:[7,51],art:25,artemi:[10,17,31,51],artemisaddress:[8,45,51],artemismq:[8,35],artemisport:[10,51],articl:[11,12,21,36,40,49],artifact:10,artifactid:51,ascertain:[43,51],ask:[5,12,27,36,39,49],aspect:[12,23],assembl:[0,3,30,49],assemblesharedtx:12,assert:[],assertequ:[13,46,52],asset:[],assetforsal:12,assetmismatchexcept:12,assettosel:12,assettypenam:12,assign:[],assist:[11,12,22,26,27,38],associ:[3,11,21,22,23,25,31,36,38,40,45,47,48,49,51],assum:[12,21,23,27,29,30,31,36,39,44,47,49,54],assume:[12,30,36,51],assumpt:[12,27],assur:43,asynchron:[26,29,47],atom:[12,21,40,43,49],attach:[],attachment:[],attachmentdemo:46,attachmentexist:46,attachmentstorag:35,attack:[21,40,44],attch:30,attempt:[21,31,36,44],attent:[12,51],attest:[21,23,27],attribut:[5,28],audit:[28,47],augment:23,authent:[1,4,21,24,27,31,35,40,48],authenticatedobject:[3,22,49,50],author:[5,21,24,27,35,41,54],authoris:[8,12,22,27,35,48],authorit:28,auto:[5,49],autoclos:4,autom:[11,24,49],automat:[0,2,4,8,10,11,12,21,23,27,28,31,32,34,35,36,37,38,40,46,49,51,54],auxiliari:35,avail:[0,1,2,7,8,10,11,12,15,18,21,28,31,32,33,35,36,39,40,41,43,44,48,49,51,54],avoid:[4,5,12,36,38],awai:[4,12,48],await:[10,43,47],awar:[4,5,11,12,35,40,49,50],awg:41,awkward:[5,12],axi:7,back:[1,4,5,9,12,24,26,28,35,36,40,43,44,47,49,52],backend:40,background:[],backoff:31,backport:41,backward:[12,41],bad:[5,12,49,53],balanc:[3,6,21,23,28,34,40,47,49],banana:22,bananast:22,banco:40,band:12,bandwidth:5,banish:17,bank:[],bankrupt:49,bankruptci:[21,23,36,43],banner:[1,45],bar:[1,16],barreca:40,barrel:[25,40],base:[5,7,8,10,11,12,17,21,22,25,27,29,31,33,35,36,37,40,43,45,48,49,51,54],basedir:[8,45],basedirectori:48,basi:[1,7,11,15,24,32,33,35,51],basic:[],bat:[0,10,15,32,34,37,51],batch:[29,51],bbva:40,bear:12,becaus:[5,11,12,16,21,22,33,35,36,47,49,50,51,53,54],becom:[5,7,11,12,18,22,36,41,47,51],been:[7,8,12,15,16,17,21,22,27,31,36,37,40,41,43,47,49,50,51,54],befor:[],beforesign:36,begin:[1,5,35,47,49,51],behalf:43,behav:49,behaviour:[3,6,8,21,29,33,47,50,51,53],behind:[12,17,20,31,49],believ:40,belong:[30,45],below:[1,5,7,8,10,11,12,15,22,30,31,35,43,47,49,51],beneath:17,beneficiari:6,benefit:[12,21],best:[5,15,47],bet:36,beta:43,better:[5,14,40,49],between:[1,5,7,11,12,17,21,23,25,26,31,32,35,36,37,38,40,41,44,47,48,49,51],beyond:[23,25,27,47],bft:[27,40],big:[5,12,40,43,49],bigdecim:[25,36],bilater:[6,7,40],bill:49,bin:[43,48,51],binari:[30,35,36,39,48],bind:[],bintrai:39,bintrayupload:39,bit:[22,40,46,49,51,53,54],bitcoin:[12,17,23,40,43,49],bitcoinj:12,blah:5,blank:[5,33,34,37,49],block:[3,4,5,10,12,21,23,26,35,36,40,43,44,46,47,51,52],blockchain:[12,19,30,49],bloom:5,bloomfilt:5,blotter:43,blue:[7,30],bob:[17,22,34,49,52,53],bob_pubkey:53,bobclient:52,bobproxi:52,bobvaultupd:52,bodi:[5,43],boil:29,boilerpl:10,bond:[49,50],bookkeep:49,bookmark:43,boost:19,boot:51,bootstrap:[8,10,51],bore:49,borrow:53,boss:51,both:[0,6,7,12,13,14,15,17,21,25,26,28,29,32,36,38,40,43,44,46,47,48,49,50,51],bottom:[16,23],bounc:13,bound:[12,21,23,40,45,47,49],box:[1,39],branch:[15,16,18,30,40,41,51],branch_nam:51,brand:40,breadth:23,breakdown:28,breakpoint:51,breviti:[0,50],bridg:[31,35],brief:[],briefli:[31,36,51],bring:[29,40,43,46,52],broadcast:[1,23,24,26,27,47,49,54],broadcasttransactionflow:54,broader:45,broke:5,broken:[40,51],broker:[8,31,35,40,51],brought:47,brows:[33,43],browser:[1,8,43,51],bubbl:15,bucket:22,buffer:[4,33],bug:[5,15,16,40,41],bugfix:41,bui:[1,12],build:[],buildcertsigningrequestutilityjar:37,buildcordajar:[8,37,45],builder:[12,13,22,40,44,46,47,54],buildfilteredtransact:47,buildmerkletransact:[30,36],buildscript:[10,17,51],buildsrc:51,buildtradepropos:47,built:[0,8,10,12,30,40,44,46,49,51],bulk:47,bullet:5,bunch:51,bundl:[16,23],busi:[11,12,17,19,22,23,24,26,36,38,40,47,49],businesscalendar:22,button:[1,39,43,51],bytearrai:38,bytecod:[12,23,49],cach:[31,46,51,54],calcul:[7,11,12,21,22,30,40,43,44,49],calculateoursignatur:12,calendar:[7,22,36],call:[0,3,4,5,7,9,12,14,21,22,23,24,25,26,33,35,36,40,41,43,44,46,47,48,49,53,54],callback:[4,5,12,35,40],caller:[36,47,49,54],came:12,camel:5,can:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,21,22,23,24,25,28,29,30,31,32,33,34,35,36,37,38,39,40,42,43,44,45,46,47,48,49,50,51,52,53,54],candid:38,cannot:[3,6,9,17,21,23,25,32,36,40,44,47,49,51,54],capabl:[24,49],capit:5,capitan:2,capsul:32,capsule_cache_dir:10,captur:[9,11,47],cardon:40,care:[5,9,12,13,21,44,47,53],carefulli:14,carri:[0,25,35,47],cash:[],cash_stat:38,cashcommand:[29,48,52],cashflow:[48,52],cashflowresult:52,cashkt:49,cashprotocol:[8,45],cashschema:38,cashschemav1:38,cashsigningpubkei:12,cashstat:47,cast:4,catastroph:43,categori:45,caught:4,caus:[5,12,15,16,17,33,43,49,51],cbc:29,ccy_cod:38,cent:25,center:49,central:[],centralis:24,ceo:22,cer:8,certain:[3,5,9,40,43,47,49],certainli:10,certainti:21,certif:[],certificatesigningservic:[8,37,45],certsigningrequestutil:[37,45],chain:[],chaincommercialpap:53,chaincommercialpaperdoublespend:53,chaincommercialpapertweak:53,chanc:[5,12],chang:[],changenotari:21,channel:12,charact:[5,8],characterist:17,charg:36,charli:22,chart:50,check:[],checkabl:[36,40],checkfixisnearexpect:36,checknotnul:49,checkout:[15,16,51],checkpoint:[9,26,35,40],checksignatur:36,checkstat:49,checksufficientsignatur:[12,22,47,54],child:[0,12,22],childprogresstrack:12,children:[12,22],childrenfor:12,choic:[1,5,21,49,51],choos:[0,1,15,16,21,34,40,49,54],choreographi:[17,24],chosen:[0,12,21,29,54],christma:51,chronolog:11,chronounit:53,chunk:[49,50],circl:32,citi:51,cl1:3,cl2:3,cl4:3,cl5:3,claim:[23,49],clarifi:49,clash:[5,38,51],classic:49,classpath:[4,9,10,23],clauseverifi:50,clean:[0,12,34,40],cleaner:40,cleanup:40,clear:[0,3,4,12,29,44],cleardatabasebeforerun:29,clearer:12,clearli:[5,16,47],click:[1,15,16,34,39,43,51],client:[],clint:1,clock:[1,11,12,21,23,36,43,47],clone:[0,1,5,15,16,49,51],close:[4,6,21,51],closeabl:4,closer:21,closest:1,closur:[5,53],cloud:33,cluster:[],cmd:[30,49,50],code:[],codebas:[1,5,18,38,39],coin:28,collabor:40,collaps:29,colleagu:5,collect:[4,5,17,29,33,38,40,42,47,49,50],collector:[5,12,33],collis:5,colon:0,column:[10,33,38],com:[2,15,37,39,40,43,51],combin:[17,22,24,28,49,50],come:[4,12,13,33,40,41,44,49],comfort:40,commanddata:[3,36,49,50],commenc:34,commerci:[],commercial_pap:[49,50],commercialpap:[3,6,38,49,50,53],commercialpaperlegaci:49,commercialpapertest:53,commit:[],committe:43,committing:12,common:[3,6,7,8,9,12],commonleg:7,commonli:47,commun:[8,12,15,17,18,24,26,31,35,40,44,45,51],compani:[23,25,36,37,50],companion:[12,36,49,50],compar:[1,30,43,49,51],comparison:[23,44,49],compat:[4,17,21,41],compel:21,compet:23,complementari:11,complet:[],completetx:47,complex:[5,6,13,23,25,26,38,43,46,49,52],complic:[12,36,47,49,50],compon:[0,3,9,10,11,17,18,24,28,31,35,40],compos:[3,12,21,23,40,49,50],compositeclaus:[3,50],compositekei:[],compound:40,compris:[7,51],comput:[7,17,36,51],computeoursignatur:12,concaten:30,concept:[3,6,11,12,18,20,21,23,26,30,36,40,49,50],concern:[12,49],concis:40,conclus:36,concret:[9,35],concurr:29,concurrenthashmap:5,condit:[3,9,21,29,35,36,40,50,53],conf:[8,10,35,37,45,51],config:[8,10,29,33,37,40,43,48,51],configur:[],configurationfil:33,confirm:[16,17,21,43,47],conflict:[21,23,29,54],confus:[0,12],conjunct:34,connect:[],consensu:[],consequ:47,conserv:[3,47],conserveamount:3,consid:[5,7,11,17,22,23,24,28,36,40,41,47,49,50],consider:[47,49],consist:[7,8,12,17,23,24,29,35,36,40,43,45,47,50],consol:[],consortium:17,constant:[5,38,49],constantli:[36,51],constraint:[12,36,40,49,51,52],construct:[],constructing_offer:12,constructor:[3,9,11,12,36],consum:[4,11,17,21,22,23,27,28,33,35,40,43,47,49,54],consumedcommand:3,consumingtx:54,consumpt:[11,36,47],contact:[12,35,40],contain:[1,3,7,8,9,10,12,17,21,22,23,25,28,30,31,33,34,35,36,37,40,41,43,46,47,49,50,51,53,54],content:[],context:[5,22,33,35,36,47,54],contextclassload:46,contin:36,continu:[],contract:[],contracthash:50,contractreject:53,contractst:[3,11,21,22,25,30,38,40,47,49],contractu:47,contrast:[12,36],contribut:[1,18,22],control:[],conveni:[3,5,22,36,46,47,49],convent:[7,12],convers:[22,34],convert:[3,6,7,13,21,22,27,35,38,40,47,49],convinc:[12,22,30],coordin:[8,39],copi:[0,5,12,31,33,35,47,49,51,53,54],copycat:42,copyonwritearraylist:5,copyright:5,copyvault:29,cor:18,corda:[],corda_bintray_gpg_passphrase:39,corda_bintray_key:39,corda_bintray_user:39,corda_dev_ca:8,corda_gradle_plugins_vers:10,corda_vers:[10,51],cordaapp:51,cordacadevpass:[8,45],cordapluginregistri:[9,10,36,48,51],cordapp:[],cordarpccli:[4,46],cordarpcop:[4,12,46,48],cordarpcopsimpl:35,cordform:[],core:[],corner:[1,16],corp:[34,37],corpor:[43,50],correct:[6,12,16,36,40,41,43,47,49,51,53],correctli:[12,17,23,35,36,40,47,49],correspond:[4,17,22,29,31,43,49,50],correspondingli:[5,46],cost:[1,4,36,49],could:[5,6,12,21,22,29,36,44,47,49],couldn:[30,36],count:[7,43],countabl:[25,40],counter:[5,12,51],counterparti:[1,6,7,17,24,31,43,44,46,47],counterparty:51,countri:[22,36,51],coupl:[12,13,29,48,51],cours:[12,29,33,36,38,49],coven:49,cover:[6,12,21,36,43,49,51],cpu:29,crash:[12,35,36],crazi:51,creat:[],createcommand:54,createdummyirs:7,createsomenod:13,creation:[7,30,49],creator:36,credenti:[34,39,48,51],credit:[40,43],crisi:43,crisp:49,criteria:6,critic:41,cross:27,crude:25,cryptic:15,crypto:[40,51],cryptocurr:28,cryptograph:[17,22,30],cryptographi:[],csr:40,ctrl:51,curl:[33,51],currenc:[3,6,7,12,25,28,29,34,38,40,47,49],current:[0,4,5,7,8,10,11,12,15,18,19,21,22,23,25,27,28,29,30,31,32,34,35,36,37,38,40,41,42,44,48,49,51,53,54],currentstep:[12,36],currentthread:46,currenttim:12,currentvault:47,curv:7,custodi:[13,22],custom:[4,8,9,12,21,22,23,26,28,33,35,38,40,43],customis:[4,38,48],cut:[],cutoff:29,cycl:[5,12,49],dai:[7,12,21,22,26,33,36,41,53],daili:51,daniel:40,danks:40,dao:40,dashboard:[33,34],data:[],databas:[],databaseschema:38,databasetransact:13,dataset:[7,43],datasourc:[8,45],datasourceclassnam:[8,45],datasourceproperti:[8,45],datastructur:29,date:[],dateoffset:40,daterollconvent:22,david:40,days:53,dcapsul:10,dead:31,deadlin:[22,36],deal:[1,5,12,22,25,28,36,43,49],dealstat:25,debt:[6,43],debugg:10,decd098666b9657314870e192ced0c3519c2c9d395507a238338f8d003929de9:33,decd:33,decentralis:[27,36,40],decid:[26,30,36,38,47,49],decis:[21,47,49],declar:[5,8,9,12,35,53],deconflict:27,dedic:[1,5],dedupl:[35,40],defaultissu:49,defaultref:53,defens:47,defin:[3,5,9,12,13,19,21,22,23,24,25,29,33,35,38,40,48,49,50,51,53],definit:[3,12,17,21,25,40,49],delai:[7,36],deleg:[47,50,54],delet:[5,12,25,35,40,49],deliber:53,deliv:[6,13,35,51],deliveri:[12,19,27,31,43,51],deliveryaddress:51,deliveryd:51,demand:[1,12,21,24,40],demo:[],demonstr:[0,27,34,40,43,51,52],denial:21,denot:30,dens:5,depend:[0,1,5,10,11,12,13,16,17,21,23,24,27,36,40,43,45,47,49,51],dependson:[10,51],depict:[23,26],deploi:[],deploy:[0,1,10,17,23,32,51],deploynod:[8,10,43,46,48,51],deployvisualis:32,deposit:49,deprec:40,depth:21,deregist:31,deriv:[0,7,12,17,22,38,40,49],describ:[5,11,12,16,18,20,21,22,23,25,28,29,30,31,35,43,44,48,49,51,54],descript:[1,3,5,27,28],deserv:[29,41],design:[5,14,17,18,21,24,27,36,40,44,49,50,51],desir:[9,12,22],desktop:33,despit:[12,46,49],destin:31,destroi:[6,23,47,49],destructur:49,detail:[],detect:5,determin:[0,3,6,7,11,17,24,31,47,49,50,51,52],determinist:[4,23,27,29,40,52],dev:[8,29,33],develop:[0,1,5,8,10,12,14,15,16,18,23,24,25,26,28,33,35,37,38,40,41,43,47,49,51],developer:51,devic:[8,27],devmod:[8,37,45],diagnos:45,diagram:[7,23,24,25,26,28,49],dialog:1,dialogu:51,diamond:17,did:30,didn:[5,12,30,41,49,51,53],differ:[1,3,5,6,7,8,9,10,11,12,21,22,23,25,27,29,31,34,36,38,40,43,47,48,49,50,51,52,53],differenti:[37,54],difficult:12,difficulti:50,digit:[12,23,36,40,47,49],digitalsignatur:[12,36,47,54],dir:[37,45],direct:[1,5,17,24,35,38],directli:[0,4,5,12,13,15,17,22,25,26,28,31,33,35,40,43,47,48,49,50,51,52,54],directori:[0,1,2,8,10,16,18,29,33,35,37,43,45,51],directthreadexecutor:5,dirti:49,disabl:[22,35],disagr:43,disambigu:38,discard:44,discoveri:32,discuss:[12,22,36,47,51],disk:[1,12,22,31,40],disobei:36,dispens:43,displai:[0,1,21,40,43,48],disput:[7,21,49],disrupt:[29,31,40],disruptionpattern:29,disruptionspec:29,distinct:[5,45],distribut:[8,9,10,12,17,18,19,20,21,23,24,27,28,36,40,42,43,47],distrust:[12,21],dive:18,divid:21,divis:25,dlog4j:33,doc:[0,2,4,5,16,18,40,43,48,51,52],docker:33,docsit:[2,18,41,51],document:[],doe:[5,6,7,8,10,11,12,13,19,23,31,33,35,36,37,38,40,43,44,46,47,49,51,52,54],doesn:[3,5,8,12,13,16,19,21,33,36,44,46,49,53,54],dokka:2,dollar:[25,49,52],dollars:[49,52,53],domain:[17,22,40,49],domicil:49,domino:43,don:[4,5,12,14,22,29,34,36,41,43,44,49,50,53],done:[2,3,4,12,13,15,23,29,30,31,37,40,48,49,51],doorman:31,dot:[7,30],doubl:[12,19,21,34,35,45,49,51,53],doubt:[5,16],down:[1,5,8,12,29,34,47,49,50,51,52],download:[],downsid:5,drain:[4,12],draw:[40,48],drawn:48,drive:47,driver:[0,8,33,38,40,48,51,52],driverdirectori:48,drm:36,drop:[1,51],dsl:[0,10,17,40,51,52,53],dt_socket:[0,10,51],due:[0,5,7,11,12,14,15,21,35,38,43,49,50],dummi:[6,13,46,53],dummy1:13,dummy2:13,dummy_notary_key:13,dummy_pubkey_1:[49,53],dummycontract:[13,54],dump:48,duplic:[12,25,30],durat:[11,36,47],durationsecond:29,dure:[5,7,8,9,10,12,32,33,35,40,49],dynam:[9,23,40,49],each:[0,1,3,4,5,7,8,9,10,11,12,17,21,22,23,24,26,27,29,30,31,32,35,36,38,40,41,43,46,47,48,49,50,51,52,53],earli:[5,6,35],earlier:[0,15,44],earliest:[7,11],easi:[0,1,5,14,36,40,49],easier:[5,10,12,15,40,49],easiest:[4,49],easili:[5,12,18,28,43,49,51],echo:51,econom:[1,7],ecosystem:[],ed25519:40,edg:48,edge:48,edit:[0,22,33,39,45,51],edition:15,editor:1,effect:[7,8,12,13,38,43,53],effort:[],either:[0,3,4,5,6,7,8,9,12,16,17,21,22,23,29,30,34,38,43,48,49,51,53],elbonia:22,element:[5,17,30,36,47,49,51],elementari:[50,51],elimin:[19,23,40],els:[12,13,21,25,28,35,36,46,47,48,49,50,54],elsewher:9,elucid:47,email:12,emailaddress:37,emb:26,embed:[8,9,19,23,26,30,33,36,40,51],embedd:31,emit:[4,40,52],emoji:46,empti:[8,34,40,49,53],emptyledg:53,emptyset:3,enabl:[0,8,9,10,21,26,35,40,50],enact:43,enc:29,encapsul:[3,5,22,36],enclos:5,encod:[31,36,47],encount:[1,11,15,35,47],encourag:[18,38,46],encrypt:[37,47],encumb:49,encumberedst:49,encumbr:[40,49],encumbranc:[],end:[3,5,7,12,18,21,23,29,31,35,36,41,47,50,51,53],endeavour:51,endpoint:[10,31,33,51],enforc:[3,5,23,49],enforceverifyorfail:53,engin:43,england:50,english:[5,49],enhanc:40,enjoy:40,enorm:12,enough:[5,12,13,43,47,49],ensur:[3,5,9,12,15,17,21,22,23,28,30,35,37,40,41,44,47,49,50,51],ensure:[1,16,21,36,43,51],enter:[10,26,39,43,51,52,53],entir:[7,12,21,35,36,49,51],entireti:[7,23],entiti:[21,22,23,30,36,37,38,49],entitl:[27,48],entri:[7,8,10,12,23,38,40,44,49,50],enumer:[7,38,43,47,51],environ:[0,1,5,10,12,24,34,36,39,47],envis:18,envisag:[23,49],equal:[3,12,21,22,25,40,47,49,50],equiti:38,equival:[5,7,22,25,34,35,42,47,49],eras:15,error:[],escal:36,especi:[22,47],essenti:[0,33,35,36,47,49,50],establish:[11,31,43,45,52],estim:1,etc:[0,5,6,7,12,17,19,21,22,24,25,33,34,36,40,41,43,45,49,50,51],ethereum:[12,23,49],eur:1,euribor:[1,33,36],euro:25,evalu:[7,33,36,50],even:[4,12,14,15,21,26,30,35,36,38,40,43,49,50,53],event:[],eventu:[29,35,45],eventual:[21,41],ever:5,everi:[0,3,4,9,12,21,22,23,24,27,29,30,31,35,36,38,40,41,43,44,49,50],everyon:[21,36,49],everyth:[15,21,44,48,49],evid:[36,47],evolut:[23,28,50],evolv:[22,38,40,45,48,49,51],exact:[0,21],exactli:[22,23,35,36,40,49],examin:[5,10,13,49],exampl:[],exampleapi:51,exampleclientrpc:51,exampleflow:51,exampleplugin:51,examplerpccordapluginregistri:48,examplerpcvalu:48,exampleservic:51,exampletest:51,exampleweb:51,exce:29,excel:36,except:[3,4,5,9,12,21,26,31,44,47,49],exception:[0,5,12],excess:[5,33],exchang:[7,12,17,25,35,47],exclud:[8,38,47],exclus:6,execut:[],executor:[5,24],exemplifi:53,exhaust:[35,40],exist:[1,5,6,7,8,10,11,21,22,23,25,32,35,37,38,40,49,51,53],exit:[3,6,8,13,25,34,35,37,40,43,48,49],exitcash:48,expand:[34,47,51],expect:[1,4,5,6,8,11,12,21,22,24,29,35,36,37,38,40,41,44,46,47,49,50,51,52,53],expectedtypenam:12,expectev:52,expens:[4,5],experi:[10,40,41,51],experiment:[5,40,43],expir:37,explain:[5,11,12,29,32,37,40,51],explan:[3,5,32,36,48],explicit:[5,12,47,49],explicitli:[5,9,23,26,28,43,47,53],explor:[5,13,19,33,34,40,43,47,49,51],explorer:[],expos:[5,9,10,11,12,22,23,27,28,33,35,38,40,47,48,54],expose:22,exposur:[6,7,17],expound:[],express:[7,17,21,22,23,40,49,53],ext:[10,51],extend:[],extens:[0,5,9,12,17,28,32,33,35,36,40,44,47,49],extern:[8,12,35,45,47,51],extraadvertisedserviceid:[8,35,42,45],extract:[22,28,33,36,43,47,49],extractcommand:50,extrem:[14,17,21,29],face:[16,49,50,53],facevalu:[3,49,53],facil:[17,28,35],facilit:51,fact:[0,5,7,12,17,21,23,24,36,40,45,49,51,53],factor:[7,43],fail:[3,9,49,50,53],failswith:53,failur:[12,17,53],fairli:[5,13,43],fall:31,fals:[5,8,12,13,22,36,45,47,49,54],famili:38,familiar:[4,18,49,51,54],famou:40,fanci:49,far:[12,36,43,47,49,50,52],fashion:[5,38,43],fast:13,faster:33,faucet:43,fault:12,fear:17,featur:[],fed:[25,32],feed:[21,36],feedback:40,feel:[49,51],fetch:[31,33,35,36,46],fetchtransactionsflow:46,few:[0,5,12,14,33,36,41,43,47,49,50,51],fiber:[12,35,36],fiction:[23,34],field:[],file:[],fill:[5,12,43,47,49],filter:[3,5,29,30,36,38,40,47],filtercommand:[30,36],filteredleav:[30,36],filteredtransact:[30,36,47],filterfun:[30,36],filterisinst:49,filterst:3,finalis:[7,12,40],finalityflow:[12,46,47,54],financ:[10,12,24,25,40,51],financi:[],find:[0,2,12,13,14,16,18,19,33,36,44,47,51],fine:[4,15,33,53],finish:[12,40,51,52],fire:12,firm:28,first:[0,3,4,5,7,8,10,11,12,13,14,15,16,17,21,23,31,33,36,37,38,39,40,43,46,47,48,49,50,51,52,54],firstli:[9,34,43,46,49,51],fit:[5,23],fix:[],fixedleg:7,fixedlegpaymentschedul:7,fixedratepaymentev:7,fixer:36,fixingflow:36,fixingroledecid:11,fixingsessioninitiationhandl:11,fixof:[30,36],fixqueryflow:36,fixqueryhandl:36,fixsignflow:36,fixsignhandl:36,flag:[8,33,37],flat:38,flesh:22,flexibl:[21,22,23],flight:4,floatingleg:[7,11],floatinglegpaymentschedul:7,floatingratepaymentev:7,flow:[],flowhandl:[12,52],flowlog:[11,12,26,35,36],flowlogicreffactori:[9,11],flowstatemachineimpl:35,flowtrack:12,flux:10,fly:12,focu:30,focus:[3,50],fold:[5,48],folder:[2,8,10,35,37,43,47,51],follow:[1,2,5,8,10,11,12,15,16,18,20,21,23,24,25,26,27,28,29,32,33,34,35,36,37,39,42,43,47,48,49,50,51,53,54],font:5,foo:[5,48],foobrokenexcept:5,foot:44,fooutil:49,forc:[33,40,49,53],fordai:[11,36],foreach:48,foreign:47,foreignexchangeflow:47,forev:41,forget:[12,36,49],form:[4,10,11,12,24,26,27,28,30,31,35,36,43,47,49,50,51],format:[],former:48,formerli:40,formula:40,forth:[4,12,47],fortun:43,forum:[15,18],forward:[12,31,35,36,41,43],found:[3,8,12,15],four:[31,43,45,49,51],fourpmtimelock:49,fraction:25,frame:[5,12,35,43],free:[12,15,21,23,43],freed:4,freeli:36,freez:47,frequenc:[1,7],fresh:[34,36,49,53],freshkei:12,freshli:[22,51],friend:45,friendli:35,from:[],fromcountri:22,front:[49,51],frontend:19,ftx:[30,36],fulfil:6,full:[5,6,8,9,12,21,27,30,31,32,35,40,43,47,48,49,50],fulli:[5,8,9,12,17,21,22,27,32,35,38,40,45,47,51,52],fullysign:12,fun:[3,11,12,13,21,29,30,36,38,46,47,48,49,50,51,53,54],fund:[43,47,49],fundament:[20,21,49],fungibl:[3,6,17,25,26,28,47,49,50,51],fungibleasset:[6,25,40,47,50],further:[],furthermor:21,futur:[],futuretransact:48,fuzz:40,fxrespons:47,fxtransactionbuildtutori:47,fxtransactionbuildtutorialtest:47,gain:[19,27],garbag:[4,5,12,33],gatewai:24,gather:[],gatherfrequ:29,gatherourinput:47,gatherremotest:29,gave:36,gbp:[3,34,50],gear:41,gener:[],generatecount:29,generatefix:36,generateiniti:13,generateirsandfixsom:7,generateissu:[49,50],generatemappedobject:38,generatemov:[49,50],generateredeem:[49,50],generatespend:[12,47,49],generatetransact:48,generatexxx:47,genuin:5,geograph:1,get:[],getalice_pubkey:53,getanynotari:54,getbefor:49,getbloomfilters:5,getbob_pubkey:53,getclass:49,getcommand:[49,50],getcontract:49,getdummy_pubkey_1:53,getencumbr:49,getfacevalu:49,getfix:7,getflowtrack:12,getinput:[40,49],getinstat:40,getissuanc:49,getkei:49,getlegalcontractrefer:[49,50],getmaturityd:49,getmega_corp:53,getmega_corp_pubkey:53,getnotari:54,getnotarysignatur:12,getorthrow:[13,52],getoutput:[40,49],getoutst:40,getowner:[49,50],getpap:53,getparticip:49,getprotocolvers:4,getrequiredcommand:50,getresourceasstream:46,getresultorthrow:29,getsign:[49,50],getsubtyp:43,getter:[38,49],gettest_tx_time:53,gettimestamp:49,gettransact:13,getvalu:[49,50],gigabyt:33,github:[1,2,15,18,43,51],giusepp:40,give:[10,13,15,21,31,33,35,36,40,47,49],given:[0,1,3,9,12,21,22,23,30,31,36,38,40,42,48,49,50,54],givenpric:12,glanc:34,global:[1,5,21,22,23,24,27,40,53],glue:12,gnu:2,goal:[5,17,19,41,50],goe:4,gone:[12,40,49],good:[0,5,12,13,18,30,49,50],got:[12,30,33,36,52],govern:[23,25,43],gpg:39,gps:21,gr1:3,gr2:3,gr3:3,grab:51,gradlew:[0,10,15,29,32,34,37,39,43,45,48,51,52],grain:[4,33],grammar:5,graph:[1,4,13,19,23,24,26,27,33,38,40,48],graphit:33,graphstream:48,great:[0,40,43],greater:5,green:[26,51],grei:23,grip:[],ground:27,group:[],groupclaus:50,groupid:51,groupingkei:[3,50],groupstat:[3,49,50],grow:48,guarante:[17,22,23,24,31,41],guava:[5,49],gui:[12,16,40,51],guidelin:[],h2databas:43,hack:40,had:[12,13,21,22,40,49],hand:[1,11,12,15,23,27,28,32,35,45,47,49,51],handa:40,handi:13,handler:[10,11,12,35],handshak:[31,36],happen:[],happi:[43,46],happili:[33,36],hard:[5,12,41],harder:[44,49],hardwar:[1,8,27],hash:[12,13,17,19,22,23,27,30,33,36,40,46,47,49],hashcod:[3,49],hashmap:29,haskel:40,hasn:29,hassl:12,hat:41,have:[0,1,3,4,5,6,7,9,10,11,12,13,15,16,17,19,21,22,23,26,27,29,30,31,33,34,35,36,38,39,40,41,42,43,44,45,46,47,48,49,50,51,53,54],haven:[49,51],head:[1,3],heap:[12,33],hear:15,heart:49,heavi:41,heavili:23,hedg:[6,7],held:[35,38,49],hell:12,hello:12,help:[5,11,12,32,36,43,47,49,51],helper:[3,7,9,12,22,35,46,47,49,53,54],henc:[7,21,35],her:[49,53],here:[0,1,5,8,10,12,13,14,15,16,17,21,22,25,30,31,32,33,36,38,40,47,48,49,50,51],herself:48,hidden:[31,35],hide:[],hierarch:[0,12],hierarchi:[5,12,25],high:[12,40],higher:[4,5,21,33,51],highli:[0,40],highlight:[24,40],hint:0,histor:36,histori:42,hoc:40,hocon:8,hold:[3,9,22,29,30,35,40,47],holder:[5,49],holidai:[7,22,36],home:[16,43],homepath:[10,51],hood:53,hope:35,hospit:[12,26],host1:29,host2:29,host:[8,10,24,29,31,32,35,36,37,39,40,45,51],hostil:44,hostnam:45,hotspot:5,hour:12,hous:34,how:[],howev:[0,6,7,8,12,15,21,30,35,36,37,38,42,46,47,49,50,51,53],html:[2,5,43,51],http:[],https:8,hub:[12,17],human:[8,12,21,23,26,36,43],hundr:12,hurt:[12,36],icommercialpaperst:53,icon:1,idea:[0,5,12],ideal:[12,49],idempot:40,ident:[],identicon:40,identifi:[1,7,9,12,16,17,21,22,23,25,30,31,33,35,36,38,40,43,47,52],identiti:[12,21,22,27,35,54],identityless:23,identityservic:35,ifmatch:40,ifnotmatch:40,ignor:[12,48,49,50,51],iii:9,illegalargumentexcept:[5,12,36,49,50,53],illegalstateexcept:[3,5,47,49,50,53],illustr:[1,22,23,24,25,26,28,32,49],illustrat:5,imag:[1,30,51],imagin:[3,5,12,49,50],immedi:[4,35,47],immut:[5,7,23,28,36,49],immutabl:5,immutablelist:49,imper:5,implement:[],impli:[12,24,31,38],implic:[12,21,23],implicit:52,implicitli:7,important:41,importantli:47,impos:[36,49],imposs:[30,36],improv:[21,28,40,41,49,50],improvement:40,inact:35,inadvert:49,inbound:31,includ:[],include:9,inclus:[3,30],incom:[35,40],incompat:53,incomplet:29,inconsist:0,inconveni:49,incorpor:[31,36],increas:[5,40,43],increment:[0,4],inde:36,indent:5,independ:[21,36,38,43,50],index:[7,11,23,38,41,49,51,54],indexsourc:11,indic:[4,5,7,8,11,12,22,40,45,47,49],indicat:29,indirectli:26,individu:[],indivis:25,industri:[14,15,17,33,43],inf:[9,51],infer:53,influenc:33,info:[12,13,38,48],inform:[1,5,8,9,12,13,15,16,21,22,24,26,31,34,35,36,37,40,43,46,49,51,52],infrastructur:[4,13,19,23,24,33,35,40,49],ingredi:47,inherit:[5,49],init:36,initi:[9,12,16,22,29,31,35,36,40,43,45,47,48],initial:[],initialis:[13,32,35,38,54],inlin:[12,47],inmemorynetworkmapservic:35,inoutgroup:[3,49,50],input:[],inputindex:54,inputpap:53,inputslist:47,inputst:54,inquisit:51,insert:[5,13,21,33,35,36,38,47],insid:[4,9,12,13,23,30,35,43,44,47,49],inspect:[29,51,52],instal:[0,2,8,10,11,15,16,39,40,43,48,49,51],installdist:[43,48],instanc:[],instance:53,instant:[5,11,12,22,36,47,49],instanti:[9,11,12,33,40],instat:53,instead:[1,5,12,13,15,16,19,22,23,31,35,40,49,54],instigat:21,instruct:[15,16,17,18,33,43,46,48,49,51],instruction:15,instrument:[6,7,11,35,47,51],insuffici:47,insufficientbalanceexcept:49,integ:[4,25,40,49,54],integer:49,integr:[0,5,8,12,15,23,30,33,36,38,40,43,51,52],integrat:[],integrationtest:52,integrationtestingtutori:52,intellig:5,intend:[5,6,10,12,13,22,23,24,25,33,34,35,36,38,44,46,51,53],intent:[3,9,32,36,40,49],intention:5,inter:[24,40],interact:[],interchang:[17,25,47],interest:[],interest_r:[8,45],interfac:[],interior:40,interleav:29,interledg:40,intermedi:47,intermediari:[22,43],intern:[5,9,10,12,28,31,33,35,38,40,49,51],internalis:5,interop:[14,40,49],interoper:35,interpol:22,interpret:[5,23,29],intersect:49,interv:[22,29],intervent:35,intesa:40,introduc:[5,11,17,23,36,40,49],introductori:[18,51],intuit:[5,34],invalid:[12,21,22,23,36,49],invari:[29,49,52],investig:12,invoc:[4,12],invoic:46,invok:[4,5,9,11,12,23,26,33,35,36,40,51],invoke:12,involv:[6,12,18,21,22,35,42,47,49,52,54],ipsa:36,irrelev:11,irsdemo:[1,8,30,43],irsexport:7,irstest:7,irsutil:7,isbefor:49,isconsist:29,isda:[40,43],isdebug:51,isempti:[36,47,49],isinstanc:12,isn:[4,5,12,22,31,44,49],isnotari:48,isnotempti:[46,48],isol:50,issu:[],issuanc:[6,22,23,25,28,29,40,43,49,50,53],issue:[3,6,17,29,43,48,49,50,53],issuecash:[29,48,52],issuecommand:50,issuedbi:[52,53],issuer:[6,12,13,25,28,34,40,43,47,49,50,53],issuer_kei:38,issuer_ref:38,issueref:[48,52],issuerparti:38,issuerref:38,issuetransact:54,istribut:18,item:[17,47,49,51],iter:[12,40,41,49],iterabl:38,iterat:[36,47],itself:[4,7,8,11,12,15,18,21,23,31,33,34,35,36,38,40,43,46,47,48,49,53],jar:[0,2,8,9,10,23,32,33,37,40,45,46,47,51],jarandsourc:10,jav:16,java:[0,3,4,5,9,10,11,12,14],javaag:47,javaclass:[12,38],javacommercialpap:[49,53],javadoc:[5,10,51],javadocjar:10,javafx:[],javatesthelp:53,javax:38,jax:9,jcenter:[],jdbc:[8,10,28,33,38,40,43,45,51],jdbcdatasourc:[8,45],jdbcx:[8,45],jdk1:16,jdk:15,jdwp:10,jersey_vers:51,jetbrain:[14,15,16,51],jms:31,jmx2graphit:33,jmx:33,jmxtran:33,job:[12,29],jobs:29,johann:40,join:[8,28,31,38,40,49],jolokia:33,jpa:38,json:[8,33,35,51],judgement:5,junit:51,just:[4,5,12,15,16,22,23,29,31,33,36,40,43,44,46,47,48,49,51,53,54],jvm:[],kdoc:5,keep:[12,15,23,28,47,49,51],kei:[],kept:[12,37,54],keymanagementservic:[12,35,36],keypair:[12,35,36,49,54],keystor:[8,35,37],keystorepassword:[8,45],keyword:[5,53],kick:12,kill:[26,29],kind:[12,22,36,44,49,51],knob:29,know:[1,4,11,12,13,14,21,24,27,30,36,44,47,49,50,51,53,54],knowledg:36,known:[1,7,13,15,17,23,24,30,35,36,40,41,43],knownfix:36,koan:[],korea:49,kotlin:[],kotlin_vers:51,kyc:24,label:[12,53],lack:[],lambda:[12,33,53],land:7,lang:[9,53],languag:[4,5,10,12,14,15,16,17,22,23,25,40,49,51],larg:[12,22,25,31,36,40,46,47,49],larger:[5,23,44],last:[12,26,29,36,41,53],lastli:51,late:15,lateinit:13,latenc:21,later:[4,5,12,13,19,22,36,38,40,44,48,49,50,51,52],latest:[5,9,15,16,18,40,47,51],latestrecord:47,latex:40,latter:[5,48,49],launch:[11,34,36,43,48],layer:[8,12,13,31,35,36,38,40,42],layout:[10,32,40,51],lazi:36,lazili:33,ldap:40,lead:[5,50],leader:8,leaf:[17,30],leak:[4,12,21,36],learn:[12,13,14,18,22,49],least:[1,8,29,43,46,49,50,51],leav:[1,3,5,12,16,22,30,34,36],ledger:[1,6,7,12,17,18,20,21,22,23,24,25,26,28,33,34,36,38,40,43,45,46,47,49,51,52,53],ledgertransact:[12,22,40],leewai:44,left:[1,12,32,37,43,50,51,53],leg:[7,11],legaci:35,legal:[8,21,23,31,35,36,37,40,47,49,51,54],legalcontractrefer:[49,50],legalident:[13,47,48,52,54],legalidentitykei:[47,54],legallyidentifi:[12,36],legalnam:[8,45,51],legitim:23,less:[12,33,40,46,50,53],lesser:49,let:[1,3,5,11,12,13,22,29,30,31,33,36,40,47,48,49,50,51,53,54],letmein:[8,45],letter:[5,31],level:[0,3,5,7,9,12,16,21,22,27,29,30,31,33,34,35,40,43,44,47,49,50,53],lib:[2,10,32,37,45,47,51],liber:5,libopenjfx:16,libor:[7,33,36],librari:[0,4,5,12,17,18,22,25,26,33,35,36,40,43,48,49,51],licat:18,licens:[5,43],license:51,life:[12,49],lifecycl:[],lifetim:[7,9,22],lightweight:[13,17],like:[3,4,5,7,11,12,13,21,22,23,25,28,29,30,31,32,33,36,40,41,43,47,48,49,51],likewis:[36,49],limit:[3,6,17,29,33,49,54],linear:[25,28,35],linearhead:47,linearheadsoftyp:47,linearid:47,linearst:[25,47],liner:5,link:[5,12,16,23,36,39,40,45,51,52],linkag:23,linux:[10,15,33,40],list:[0,2,3,8,9,12,22,23,27,29,30,31,35,36,38,40,41,42,43,47,48,49,50,51,54],listen:[0,1,5,31,35,40,48,51],listof:[13,36,38,47,48,49,51,52],littl:[5,12,49,53],live:[7,9,12,35,40,43],lizard:17,llc:37,load:[],loadtest:29,loan:[6,7,36],local:[],local_branch_nam:51,localcertificatesbasedirectori:29,locald:36,localhost:[1,8,33,34,43,45,51],localtunnelstartingport:29,locat:[],lock:[5,6,8,28,38,49],log4j2:[33,45],log4j:[40,51],log:[],logger:[12,33],loggerfor:33,logic:[3,11,12,13,17,21,22,23,24,31,38,40,44,46,47,49,50],login:[10,34,39,43,48],loglevel:33,london:[8,10,37,45,46,51],longer:[0,5,7,8,12,37,40],longrang:29,look:[0,1,3,5,7,12,13,22,29,31,33,36,41,43,46,49,50,51,53],lookup:[8,31],loop:[5,7,29,48,49,52],loquitur:36,loss:36,lot:[5,7,40,43,44,49],low:[12,21],lower:[5,12,15,27,47],lowest:31,lurch:12,machin:[],macos:[10,40],made:[5,7,12,22,35,36,40,41,46,47,48,51],magicnumb:54,mai:[0,1,4,5,10,12,15,16,17,18,21,22,23,24,25,26,27,28,29,31,32,33,34,35,36,38,40,41,43,44,45,47,48,49,50,51,52,53],mail:41,mailbox:35,main:[0,8,11,12,16,23,29,31,35,40,46,48,50,51],mainstream:19,maintain:[17,21,36,49,54],mainten:31,major:[0,12,40,41,43],make:[],maker:14,maketransact:13,malici:[12,27,40,44,47],man:40,manag:[],managa:28,mandatori:49,mani:[5,10,11,12,13,16,21,22,23,25,27,29,36,40,46,49,51],manifest:0,manipul:[22,25,47],manner:[12,23,31,40,48,49,50],manual:[0,10,11,12,26,32,47,54],map:[],mappabl:49,mappedschema:38,mappedtyp:38,margin:[],mark:[4,5,6,12,17,38,49],markdown:5,marker:[12,44],market:51,marshal:4,master:[15,16,41,51],match:[3,4,8,12,22,23,24,30,31,36,44,47,48,50,52],materi:50,math:[],mathemat:22,matter:[12,36,43,49],matur:[6,7,21,27,32,33,36,49,53],maturityd:[49,53],maven:[],mavenloc:10,mavenpubl:10,maximis:23,maybestx:12,maybetraderequest:12,mbean:33,mean:[4,5,9,11,12,13,16,17,21,23,25,26,27,29,30,36,40,43,47,48,50],meandref:48,meaning:[6,21],meaningfulli:46,meant:[12,29,51],meantim:52,meanwhil:[48,50],measur:[7,28,43],mechan:[9,17,28,31,36,40],meet:[3,35,47,49,51],mega:37,mega_corp:[13,53],mega_corp_key:13,mega_corp_pubkey:53,megacorp:[13,53],member:[7,8,40,43],membership:26,memori:[],menlo:5,mention:[11,12,36,49],menu:[1,51],mere:7,merg:[25,28,40,47,49,51],mergeabl:49,merkl:[],merkleroot:[30,36],merkletreeexcept:[30,36],mess:12,messag:[],messagingserveraddress:[8,35],messagingservic:[31,35],met:[9,22,51],meta:[9,51],metadata:[33,46,51,54],method:[3,4,5,8,9,11,12,13,21,22,25,29,33,35,36,38,40,44,45,46,47,49,54],metric:[33,43],micro:[40,50],microsoft:1,mid:21,middl:[5,12,40],middlewar:[17,35],midpoint:51,might:[5,7,12,36,38,44,47,49,51],migrat:47,mileston:[],million:26,min:48,mind:[5,12,36],miner:23,mini_corp_pubkey:13,minim:[3,12,15],minimis:[6,21,31],minimum:[4,7,22,23,47],minor:[31,40,41],minu:49,minut:[0,1,12,14,36,39,51],mismatch:[49,53],miss:[],mission:33,mistak:[40,44,47],mix:[0,5,40],mobil:23,mock:[13,51],mocknetwork:[13,32],mocknod:[13,35],mockservic:22,modal:51,mode:[8,32,34,37,40],model:[],modif:[35,47,49],modifi:[1,6,7,9,10,12,17,22,47,49,51,53],modul:[5,8,13],moment:[12,13,40],monei:[36,47,49],monitor:[],month:[7,12,41],monthli:51,more:[0,1,3,4,5,6,7,8,10,12,13,14,16,17,18,21,22,23,24,25,27,30,31,32,33,35,36,37,38,40,42,43,46,47,48,49,50,51,52,54],moreexecutor:5,mortensen:40,most:[0,3,5,7,12,15,31,32,33,45,49,50,51],mostli:[23,49],motiv:[18,51],move:[3,6,9,12,13,23,34,40,41,43,47,48,49,50,51,53,54],movement:[12,25,49],movetransact:54,movetransactionbuild:54,much:[5,12,14,27,36,38,40,44,47,49],multi:[],multigraph:48,multilater:[6,40],multipl:[],multipli:7,must:[3,4,5,6,8,9,10,11,12,21,22,23,25,27,31,33,35,36,38,39,40,44,45,46,47,48,49,50,51],mustafa:40,mutabl:[5,22,49],mutablelistof:47,mutat:[35,47],mutual:[6,12,21,44],myfil:33,myident:[36,54],myinfo:[36,47,54],mykei:22,mykeypair:12,mylegalnam:[8,37,45],mynodeinfo:36,mypublickei:12,mysigningkei:[36,54],mysql:19,nail:5,name:[],namedbyhash:[],namespac:12,narrow:[3,5,34],nativ:[12,47],natixi:40,natur:[0,23,47,49],naval:21,navig:[1,10,39,43,51],navistar:21,nearestc:[8,10,37,45,51],neat:53,necessari:[5,17,24,36,40,41,51],necessarili:[22,38],nee:40,need:[0,1,2,3,5,7,9,11,12,13,15,16,17,21,22,23,24,25,29,30,33,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54],neg:[25,51],negoti:[22,47],neither:12,nest:[12,52],net:[3,6,7,8,9,10,12,13,33,35,37,38,39,40,42,43,45,46,47,48,49,51,52,53],network:[],networkmap:[10,31,51],networkmapcach:[8,9,12,35,54],networkmapservic:[],networkmapupd:48,neutral:19,never:[5,17,21,49],newdeal:36,newli:[11,51,54],newnotari:21,newowner:[49,54],newsecurerandom:40,newstat:47,nextdoubl:48,nextfixingof:11,nextlong:48,nextscheduledact:11,nfinal:46,nice:[36,49],nio:5,noddi:33,node:[],node_dir:10,node_directory:45,nodea:[1,10,51],nodeb:[1,10,51],nodec:[1,51],nodefilt:29,nodehandl:[29,52],nodehost:29,nodeident:48,nodeinfo:[8,12,35,52],nodeinterestr:[9,36,47],nodenam:51,nodex:51,nodisruptionwindowm:29,non:[],nonc:50,nondeterminist:52,none:[3,11,12,30,36,38,43,50],nonemptyset:40,nordea:40,normal:[3,4,6,7,9,10,12,22,29,30,31,32,34,35,40,46,47,49,50,54],north:49,notabl:[5,51],notari:[],notaris:[],notary:12,notary_committed_states:43,notarychang:[40,47],notarychangeflow:21,notaryclusteraddress:[8,35],notaryexcept:54,notaryflow:[12,26,35,40,47,54],notaryident:[12,13,48,52],notarynod:[12,13],notarynodeaddress:8,notarysig:12,notarysignatur:[12,54],notarytous:22,note:[],noth:[5,11,12,23,40,44,49,51],notic:[5,43,50,53],notif:[26,29,31,35,46],notifi:[31,32,54],notion:[],notnul:[49,50],now:[1,5,10,12,13,22,30,33,39,40,43,45,47,48,49,51,52,53,54],nugget:49,nullabl:[12,49],nullpublickei:49,number:[0,3,5,6,7,13,15,17,22,25,29,31,34,35,36,38,39,41,43,45,47,49,51],numer:9,obj:[49,50],object:[],oblig:[6,7,25,40,47,51],obligat:[],obligor:6,observ:[4,7,11,12,21,26,29,32,40,46,51],observatori:21,obsolet:[11,40],obtain:[5,8,11,12,13,15,21,24,27,30,36,37,40,43,51,54],obviou:[5,21,36],obvious:[0,7,17,32],occasion:0,occur:[11,12,21,35,49,52],occurr:[12,21],odd:49,off:[],offer:[12,27,35,38,51],offici:15,offlin:31,offset:7,ofsecond:47,often:[5,6,7,12,16,36,47,49],oftenor:36,oil:[25,40],old:[12,17,21,39,40,47,49,54],older:15,omit:[11,43],onc:[4,5,9,12,17,21,22,26,37,41,47,49,52],once:[1,2,7,10,11,12,15,17,18,22,31,32,37,38,39,43,45,46,47,49,51],one:[3,21,24,30,36,43,47,51],ongo:4,onledgerasset:[6,49],onli:[0,3,4,5,7,8,10,11,12,14,17,21,22,23,24,25,30,31,32,33,34,35,36,37,40,41,43,44,45,47,48,49,50,51,52,53,54],only:[12,31,35,39,45],onto:[4,5,12,31,49,53],opaquebyt:[40,48,52,53],open:[0,1,3,4,10,12,15,16,18,21,23,31,33,35,40,43,48,51,52],opengamma:[40,43],openjdk:[15,16],openjfx:[15,16],openssl:29,oper:[1,7,8,11,12,17,24,25,31,33,35,36,40,44,45,47,48,49,54],oppos:0,opposit:3,opt:[1,10,29,51],optim:5,optimis:[28,40],option:[0,1,2,5,7,8,11,12,17,29,32,36,37,38,40,47,49,50,51,52,54],optional:[8,47],oracl:[],oracleparti:36,orang:26,orchestr:[19,23,40],ordain:7,order:[0,2,4,5,6,7,12,19,21,22,23,24,28,29,32,35,36,38,40,43,45,46,48,49,50,51,52],ordernumb:51,ordinari:[12,23,40,49],ordinarili:36,org:[2,8,45,49,50,51],organis:[0,16,28,38,39],orient:[],origin:[23,30,38,40,46,47,49,50,51,53],originalst:21,orm:[38,40],osx:51,otc:38,other:[],otherparti:[12,36],othersid:[12,46],otherwis:[1,4,5,8,9,10,11,12,31,35,36,44,47,48,49,52],our:[0,5,11,12,13,14,15,18,22,29,30,31,35,36,39,40,41,46,47,48,49,50,51,54],ourkei:47,ournotari:54,ourselv:[12,36,49,54],oursign:47,oursignatur:12,ourstat:47,out:[0,3,5,6,11,12,15,16,18,21,22,23,30,31,33,35,36,40,41,42,43,44,46,47,49,50,51,54],outcom:12,outer:50,outlin:[12,36,40],output:[],outref:[13,47],outsid:[10,12,23,35,36,45],outstand:6,over:[0,1,5,7,8,10,12,13,17,21,22,23,24,29,30,31,33,36,38,40,43,47,49,51],overal:[11,21,47,53],overdu:11,overflow:5,overhead:33,overidden:[8,10],overload:[12,25],overlord:17,overnight:22,overrid:[3,9,11,12,29,36,38,48,49,50],overridden:[9,10],overutilis:29,overview:[],overwrit:39,own:[],ownablest:[12,22,49],ownedquant:48,owner:[11,12,22,28,38,47,49,50,53,54],owner_kei:38,ownership:[12,13,43,49,54],owningkei:[12,30,36,47,49,54],ozturk:40,p2p:[31,40],pack:49,packag:[9,15,22,25,38,40,51],packet:23,page:[1,8,15,16,36,41,43,51],pai:[],paid:[6,7,43,49],pair:[1,12,13,22,35,36,37,47,49],pan:40,pane:16,paper:[],paragraph:29,parallel:[4,29,36,40,52],param:[29,38,54],paramet:[4,5,9,11,12,22,29,33,36,40,46,47,49,50],parameteris:[23,29,47],parent:[12,17],pars:[22,36,49],part:[0,3,4,5,6,8,9,10,11,12,21,22,23,29,30,31,34,35,36,37,38,40,44,45,47,49,50,51],parti:[],partial:[],partialmerkletx:36,partialtx:[12,30],particip:[21,22,23,24,26,27,28,34,35,36,40,49,54],particular:[],partner:[43,47],partyandrefer:[5,25,48,49,53],partyfromnam:46,partynod:13,partyrefer:[5,49],pascal:5,pass:[1,3,9,12,22,26,28,29,30,33,35,36,38,40,43,46,47,49,50,52,54],passphras:39,password:[1,4,8,10,27,31,33,34,37,40,43,45,48],past:[1,5,43,49,51],patch:[5,40],path:[5,8,9,10,11,16,29,31,33,40,43,47,48,49,51],path_to_loadtest_conf:29,pattern:[5,47,48],paus:[10,26,32],paycash:[48,52],payer:7,payload:36,payment:[1,6,7,11,12,17,34,36,43,49],pdf:[36,46],peer:[12,19,24,30,31,34,35,36,49,51],penni:[25,38,49],peopl:[5,12,14,17,26,49],per:[],perfect:50,perform:[0,1,5,7,11,12,17,21,22,23,26,27,28,29,31,36,40,43,46,49,50,51],perhap:[5,31,45,49],period:[7,37,43,47],perman:[12,46,47,49,53],permiss:[],persist:[],persistentcashst:38,persistentst:38,perspect:[12,23,27,35,49],pertin:51,pervas:27,phase:40,phrase:36,physic:[1,21,35,40,45],pick:[0,12,15,31,40,41,49],piec:[5,12,17,21,23,25,29,45,49,53],pip:2,pki:[23,40],place:[2,5,7,9,11,12,19,22,23,24,30,31,36,40,41,43,48,49,50,51],plai:[],plain:8,plan:[12,23,36,39,40],platform:[7,9,10,11,12,14,15,18,20,21,22,23,24,30,40,43,44,49,51],plc:34,pleas:[1,5,8,15],ploadtest:29,plu:[8,22,35,53],pluggabl:[21,24,27,40],plugin:[],pluginservicehub:[9,10,12,35,36,40],pluginserviceregistri:51,point:[4,5,6,9,10,12,16,17,21,22,23,29,33,35,36,38,40,41,44,47,48,49,50,51],pointer:[12,22],pointless:5,polish:40,polit:43,poll:[29,37],pool:5,pop:[16,51],popul:[35,47],popular:14,popup:[15,16],port:[0,1,8,10,29,34,35,40,41,43,45,51],portal:1,portfolio:[],portion:[23,47],posit:[5,12,18,49,54],possess:[12,21,54],possibl:[3,12,15,16,23,28,29,35,36,37,40,43,46,47,49,53],post:[24,35,51],postgr:19,potenti:[5,12,14,21,26,36,43,49,51],pound:[25,49],pour:25,power:35,practic:[8,40,43,47,49],preced:[0,49],precis:[19,21,23],precondit:[5,49],predic:52,predict:29,predominantli:[],prefer:[0,1,5,16,34,38,51],prefix:[5,38],preliminari:43,prepar:[40,49],prescrib:45,present:[1,3,4,6,7,8,9,10,12],preserv:[21,28,47],press:51,pretend:[22,33,40],pretti:12,prevent:[28,31,40,43,44,47,49],previou:[12,22,29,40,50,51,53,54],previous:[7,11,21,22,23,36,40,51,54],price:[12,23,36],primari:[23,36],primarili:[0,6,15],primit:[22,53],print:[4,33,40,43,44,45,46,48,52],println:[46,48,52],printorvisualis:48,prior:54,privaci:[5,12,19,21,23,27,28,36,40,47,49],privat:[1,5,8,9,12,13,24,27,28,31,36,37,38,45,47,49,51,53],privatefoo:5,privatekei:[12,35],probabl:[0,49],problem:[12,15,16,36,45],proce:[1,12],procedur:[12,37,49],process:[],processor:29,produc:[2,11,16,23,32,47,49,52,53],product:[0,5,10,11,14,19,25,40,41,43,47,51],profil:[33,39],program:[4,5,22,23,33,35,40,43,49],programmat:48,progress:[],progresstrack:[12,36],project:[],prolif:40,promis:40,prompt:[15,51],proof:[6,23,30],propag:[4,12,33,49,50,51,53],properli:[12,35,44],properti:[],proport:43,propos:[12,23,35,44,47,51],proprietari:[24,40,43],prose:[23,36,49],prospectus_hash:46,protect:[12,27,35,37,43],protocolhandl:46,protocolvers:4,prototyp:[5,19,36,40,42,49],provabl:47,prove:[21,49],proven:[27,43],provid:[],provis:24,provision:22,proxi:[4,46,48,52],prune:[27,28],pseudo:36,pseudonym:22,ptx:[12,36,46],pubkei:53,publicfoo:5,publickei:[12,35,49],publish:[],publishtomavenloc:39,pull:[47,51],punish:36,purchas:[1,12,43,51],purchaseord:51,purchaseordercontract:51,purchaseorderst:51,pure:[6,23,36,52],purpos:[1,6,12,17,21,22,27,28,31,38,42,43,45,47,48,49,51,52],push:[4,31,41],put:[],putti:1,python:[2,40,51],qualifi:[8,9,38],qualiti:47,quantifi:25,quantiti:[3,25,28,29,47,48,49,51,52],quasar:[9,10,12,17,35,36,47,51],quasar_vers:51,queri:[],queryablest:[35,38],queryrequest:36,question:[5,11,21,22,31,36,50],queu:[17,31],queue:[],quick:[36,51],quickcheck:40,quickli:[17,37,44,49],quit:[4,5,12,21,49],r3cev:29,r3corda:[10,40,51],r3dlg:41,r3prototyp:[2,47],radic:23,raft:[],rais:[3,21,43,50],ran:0,random63bitvalu:50,random:[11,22,23,29,31,34,40,43,47,48,54],randomis:[27,40,46],randomli:[29,34,48],rang:[1,3,21,38,51],rapid:[5,10,19,41],rare:[8,25],rate:[],ratesfixflow:[30,36,47],rather:[3,5,12,15,16,31,32,40,45,47,48,49],rational:20,raw:[1,31,33,43],rdbms:[38,40],rdms:40,reach:[7,11,21,23,24,27,36,40,43],reachabl:12,react:29,reactiv:40,read:[1,5,8,10,12,14,18,19,30,33,35,36,40,49,51],readabl:[8,12,14,23,43],reader:18,readi:[1,3,41,49,51],readili:50,readm:[18,51],readme:[5,51],real:[5,22,32,36,37,40,43,47,49],realis:12,realist:22,realiti:[7,52],realli:[5,12,30,36,49],reason:[5,7,12,21,23,25,29,40,44,49],reassign:49,recal:7,receipt:[35,43],receiv:[4,6,7,9,12,17,26,29,31,35,36,40,41,43,44,46,47,49,51,52],receiveandcheckproposedtransact:12,receiveandvalidatetraderequest:12,received:36,receiving:12,recent:[1,40,51],recheck:47,recipi:[6,43,46,49,52],recognis:[9,12,23,49],recommend:[0,1,5,15,31,42,43,51],record:[11,13,17,21,25,26,28,35,38,43,46,47,51,54],recordtransact:[13,35,47,54],recreat:[12,16],red:[7,30,51],redeem:[3,6,34,49,50],redempt:49,redeploi:51,redesign:40,redirect:45,redownload:16,reduc:[5,10,43],redund:5,ref:[12,13,22,36,47,48,52,53],refactor:40,refer:[],referenc:[46,51],refin:40,reflect:[1,12,18,29,40,47,49,50,51],refresh:[0,15,40,51],refus:16,regard:[21,45,47],regardless:12,regener:[7,41],regist:[],registerflowiniti:[9,12,36],registerrpckryotyp:[9,48],registr:[9,35],registri:9,regress:40,regul:[23,47,49],regular:[1,12,17,25,33,43,45,49],reifi:47,reissu:49,reject:[8,21,23,31,35,36,37,47,49],rel:[8,14,33,36,40,47],relabelablestep:12,relai:46,relat:[],relationship:[35,49],relax:[29,37,40],releas:[],relev:[3,9,10,11,17,22,23,28,35,36,40,47,49,50,54],reli:[4,10,23,40,43,44],reliabl:35,relic:33,religi:5,remain:[10,11,12,36,40,47,49,51],rememb:[5,11,44,47],remind:[12,44,50],remot:[0,9,10,16,27,29,32,35,43,45,47,51],remote_branch_nam:51,remotemessagingport:29,remotenodedirectori:29,remotesystemdservicenam:29,remov:[12,30,34,40,41,49],renam:[12,40],render:[5,12,32,34,40],renderifsupport:46,repair:26,repay:50,repeat:[0,5,7,12,46],replac:[4,7,22,33,40,41,43,47,48,49,51],replai:40,replic:[8,42,43],repo:[0,1,15,16,18,51],repoint:21,report:[12,26,28,34,40,50],repositori:[0,5,10,16,39,40,41,43,51],repres:[1,5,6,7,9,12,22,23,24,25,28,29,34,35,36,38,40,47,48,49],represent:[],reproduc:47,republish:51,request:[],requestingparti:54,requir:[],requiredcommand:[3,40,50],requiredflow:9,requiresinglecommand:[49,50],requirethat:[49,50],research:40,resel:36,resend:35,resent:35,reserv:28,reset:[7,32],resid:35,residu:47,residualamount:47,residualoutput:47,resolut:[12,23,26,40,54],resolv:[5,12,13,22,27,36,43,45,49],resolvetransact:23,resolvetransactionsflow:[12,13,26,46],resolvetransactionsflowtest:13,resourc:[0,1,4,8,9,12,23,29,36,46,47,51],resp:36,respect:[0,5,12,22,28,47,51,52],respond:[12,35],respons:[4,9,11,12,16,21,23,28,31,35,36,38,47,48,51,52,54],rest:[9,12,19,23,31,33,40,50,51],restart:[9,12,26,35,37],restor:[9,12,17],restrict:[1,3,5,23,32,43,47],restructur:[40,50,51],restructuredtext:2,result:[5,7,8,12,13,21,23,34,35,36,37,38,40,43,44,46,47,49,51,54],resultfutur:13,resum:[12,35,37,40],resurrect:12,resync:15,retain:31,rethrown:4,retri:[12,19,31],retriev:[7,12,37,42,46],retrieveoutput:53,returnvalu:[46,52],reus:[4,23],reusabl:[3,17,23,36,40,46,49],reveal:[12,21,27,30,36,40],revers:[12,35],revert:6,review:[5,12,23,27,40,41,51],revis:[7,27,47],rewrit:12,richer:10,right:[1,5,12,15,16,22,33,36,40,41,43,44,47,51],rightmost:30,rigidli:5,risk:[12,43],robert:40,robust:40,rogerwilli:51,role:[11,27,34,35,43,48],roll:[7,12,40,43],rollov:[22,49],root:[1,8,10,24,27,30,31,35,37,41,45,47,51],roothash:36,rotat:[33,40],roughli:[21,41],rout:[12,13,27,31,40],row:[23,33,34,38,43,49],rpcclienttonod:[48,52],rpcexception:4,rpckryo:4,rpcreturnsobserv:4,rpcsincevers:4,rpcuser:[8,34,45,48,51,52],rui:40,ruin:53,rule:[5,12,23,28,35,36,40,43,49],run:[],runbuy:43,runconfigur:[15,16],rundemonod:[34,40],runexampleclientrpc:51,runnetwork:13,runnod:[0,10,40,43,48,51],runparamet:29,runrecipi:43,runrpccashissu:43,runsel:43,runsend:[0,43],runshellcommandgetoutput:29,runsimulationnod:34,runtim:[5,12,51],runwebcashissu:43,sacrif:51,safe:[4,5,9,12,37,44,48,52],sai:[5,21,29,43,45,49,50,54],sake:[43,52],sale:49,same:[0,1,4,5,6,7,8,10,11,12,21,22,23,25,28,29,31,35,36,37,40,43,45,47,48,49,50,51,53],sampl:[0,9,10,12,15,16,18,26,32,33,34,40,43,46,51],sanction:49,sandbox:[11,19,23,27,40,44],saniti:12,santiago:40,sate:54,satisfi:[22,43,49,50],save:[5,12,40,49],saw:52,scala:[14,49],scalabl:[5,21],scale:[7,44],scenario:[22,26,27,32,35,47,51,52],scene:[12,49],schedul:[],schedulablest:[11,22,35],scheduledact:11,schedulerservic:35,schema:[],schemafamili:38,schemaopt:38,schemaservic:38,scheme:[30,35],schroeter:40,scienc:51,scope:[3,9,34,46,50],scotiabank:40,scotland:50,scrape:33,scratch:[22,49,51],screen:[1,5,15,16,34,40,49],script:[0,2,10,40,43,46,51],scroll:43,scrub:12,seamless:14,seamlessli:[],search:[1,23,34,35,47,49],sec:51,second:[3,7,9,12,13,22,29,36,43,46,47,49,51,52],secondari:12,secp256r1:40,secret:8,section:[8,20,21,26,27,28,29,36,40,41,47,51,54],securehash:[13,22,30,36,49,50,54],securerandom:40,see:[1,2,3,4,5,6,7,8,10,11,12,13,15,16,21,22,23,24,25,27,29,30,32,36,37,38,39,40,42,43,45,46,47,48,49,50,51,52],seed:12,seek:40,seen:[5,7,9,12,36,49],segment:10,select:[1,3,16,21,27,28,38,40,43,47,49,50,51],selector:3,selectschema:38,self:[10,28,29,40,43,52],selfissuecommand:29,selfissuest:29,selfissuetest:29,selfsignedtx:47,sell:[12,47,49,50,53],sellamount:47,sellerownerkei:12,sellersig:12,sellertradeinfo:12,semant:26,semi:[1,24,27],send:[1,5,12,13,21,24,26,28,30,31,33,35,36,40,41,43,46,47,49,51,52,54],sendandrec:[12,36],sender:[12,43,46],sending:36,sending_offer_and_receiving_partial_transaction:12,sendrec:26,sendsignatur:12,sens:[7,36,49,50],sensit:[11,21,23,30,43,44],sent:[11,12,22,26,31,36,40,46,47,49],separ:[0,1,3,8,9,10,12,22,30,31,33,36,40,43,47,49,51],septemb:43,sequenc:[26,35,40,52],sequenti:[12,52],seri:[12,22],serial:[4,9,19,35,49],serialis:[4,5,9,12,17,19,36,40,49],seriou:41,serv:[10,51,52],server:[4,8,9,10,19,31,33,35,37,40,48,51],servic:[],servicehub:[9,10,12,31,35,36,47,54],servicehubintern:40,serviceident:36,serviceinfo:[43,48,51,52],serviceload:[9,36],serviceplugin:[9,36],servicetyp:[8,35,43,54],servlet:51,session:[11,31,35,40],sessionid:11,set:[],setlifecycl:3,setof:[3,12,13,43,46,47,48,50,51,52,54],setter:[38,49],settim:[12,22,36,47],settl:[3,6,13,25,46],settlement:[6,12],setup:[],sever:[0,8,10,12,31,35,36,38,42,43,45,48,49,52,53],sha256:[22,30,49,50],sha256sum:33,sha:[23,33],shade:23,shadow:28,share:[0,1,6,7,12,17,22,23,24,25,35,36,40,44,46,47,49,51],shasum:33,she:49,shell:[29,51],ship:[1,23],shoot:44,shortcut:19,shorthand:53,shortli:0,should:[0,1,3,5,6,9,10,11,12,15,16,18,19,21,22,24,26,29,30,35,36,37,38,39,40,43,44,45,46,47,48,49,50,51,52,53],shoulder:5,shouldn:[12,23,30,47,49,51],shoutout:40,show:[1,14,23,32,34,35,40,43,49,50,51],shown:[1,4,8,12,13,22,32,47,51],shut:52,shutdown:[12,35],side:[4,11,12,15,25,26,32,36,43,44,46,47,51],sidebar:32,sidenot:45,sig:[36,40,49],sign:[],signal:[17,47],signatori:47,signatur:[],signaturesfromsel:12,signedtransact:[],signer:[30,36,43,47,49,50,53],signfirsttx:13,signific:[0,36,40],significantli:[7,21,22,29,46],signing:[12,36],signingkei:36,signrequest:36,signwith:[12,13,22,46,47,49,54],signwithecdsa:[12,36],signwithourkei:12,silver:5,similar:[5,12,31,36,40,47,48,49,50],similarli:[27,38,47],simmvaluationdemo:[1,43],simpl:[],simplecp:53,simplecpdoesntcompil:53,simplecpmov:53,simplecpmovefail:53,simplecpmovesuccess:53,simpleissuancewithtweak:53,simpleissuancewithtweaktopleveltx:53,simplenam:38,simpler:[14,23,50],simplest:[12,49],simpli:[1,5,10,12,13,22,29,35,38,40,42,49,51,53],simplic:47,simplif:40,simplifi:[3,5,6,23,25,35,42,47,49],simul:[],simultan:[12,22,28,43,49],sinc:[49,50,51],singl:[],singlemessagerecipi:31,singleownerst:54,singleton:[9,12,36,49,50],singletonserializeastoken:[9,36],site:[5,40,41],situat:[5,30,40,47],size:[1,5,7,12,33,36,49,50,51],skeleton:13,skip:[12,22,49,51],sl4j:33,slack:[15,18],sleep:[29,48],slf4j:12,slightli:[0,42,47,49],slip:41,slot:40,slow:[5,29],small:[3,4,11,12,23,24,25,33,36,40,44,46,49],smaller:[3,40,50],smallest:25,smart:[],smooth:49,snapshot:[],snapshots:51,snide:2,snippet:[12,51],socket:33,soft:28,softwar:12,sofu:40,sold:[12,22],sole:[21,31,40],solut:[12,27],solv:[12,16,36],solvenc:36,some:[0,1,4,5,6,9,11,12,13,16,18,19,21,22,23,24,25,26,29,30,33,34,35,36,38,40,43,45,47,48,49,50,51,52,53,54],somed:49,somehow:29,someon:[21,28,49,54],someth:[4,5,7,12,36,40,49],sometim:[0,12,17,22,23,33,47],someusernam:29,somewhat:[4,12,29,40,43],somewher:49,sonatyp:39,soon:[40,49],sophist:[],sort:[12,36,40],sound:[5,12,49],sourc:[],sourcejar:10,sourcenotari:47,sourceset:33,sparingli:5,spawn:[9,52],speak:40,spec:40,special:[3,4,12,21,23,50,53],specif:[3,4,6,9,10,11,12,17,21,22,23,25,28,29,31,33,35,40,47,49,50,51,52],specifi:[1,2,3,4,5,6,8,10,12,17,19,21,22,23,29,30,37,38,40,45,46,47,49,50,51,52,53,54],speed:[12,14,51],spend:[12,13,19,21,26,28,34,35,44,45,47,49,52,53],spent:[23,28,49,53],sphere:23,sphinx:2,sphinx_rtd_them:2,spin:29,spirit:40,splash:[15,16],spline:22,split:[3,25,28,30,31,40,47,49,50],splittabl:49,splittablerandom:[29,48],spot:40,spread:[12,21],spreadsheet:36,spuriou:3,sql:[19,24,38,40,43,51],src:[8,12,35,46,51,52],ssd:1,ssh:[1,29],sshuser:29,ssl:[8,40],sslkeystor:[8,37,51],stabil:51,stabilis:41,stabl:[4,9,16,18,41,48,51],stack:[9,12,33,35,36],stage:[5,6,12,22,26,47,49],stai:[23,35,47,49,50],standalon:[24,32,36,40,48],standard:[3,5,9,10,12,15,17,21,22,25,28,32,33,35,40,43,45,47,48,49,50,51],standardis:[3,22,47],start:[],startflow:[12,13,40,46,48,52],startflowdynam:[12,48],startflowpermiss:[48,52],startnod:[48,51,52],startprotocol:[8,45],startup:[8,9,33,40],startwith:48,state:[],stateandref:[12,21,22,36,40,47,49,54],statehistori:54,statemachinemanag:[],statemachinerunid:12,statement:[5,12,36,49],stateref:[11,22,25,30,38,47,54],statesoftyp:[47,49],staticservedir:9,statist:33,statu:[47,51],status:23,stdlib:51,stem:49,stereotyp:47,still:[11,12,16,21,32,36,40,43,47,49],stock:[23,28,36],stone:29,stood:38,stop:[5,12,35,51],stopnod:13,storag:[],store:[8,9,10,12,13,16,21,22,28,33,35,37,40,42,43,47,49,51,54],stori:[5,40],straight:1,straightforward:[12,49],strain:29,straincpu:29,stream:[4,12,31,32,40,46,48,52],strength:15,stress:[5,29,40],strictli:[7,9],string:[0,8,12,22,29,36,38,43,48,49,51,54],strip:49,strong:14,strongli:15,stub:[40,43],stuck:18,studi:49,stuff:5,stx1:13,stx2:13,stx:[12,22,46],sub:[],subclass:[6,12,22,38,49],subclaus:50,subcompon:27,subdirectori:33,subflow:[9,12,21,35,36,47,54],subfold:[9,35],subgroup:23,subject:[8,10,17,27,31,43,51],submiss:36,submit:[1,5,12,21,29,31,37,40,43,51],subnet:51,subscrib:[4,31,40,46,48],subscript:1,subsequ:[17,28,37,47,49,52,53],subset:[6,30,40,50],substanc:51,substitut:[8,9,47],subsystem:[9,31],subtask:12,subtl:5,subtract:25,subvert:44,success:[3,28,31,43,47,52],successfulli:[23,43,45,46,48],successor:[11,14,21],succinct:5,sudo:[2,16],suffer:43,suffic:12,suffici:[22,31,36,40,41,43,47,48],suffix:51,suggest:[10,15,31,33,49],suggestinterestrateannouncementtimewindow:[11,36],suit:[40,46],suitabl:[11,31,35,36,41],suitablecashst:47,sukrit:40,sum:[29,43,47,48,49,51],sumcashbi:[12,49],summari:[],sumorthrow:3,sumorzero:3,sun:5,superclass:[6,40],superior:5,superset:8,supertyp:49,suppli:[6,29,48],support:[],supportedschema:38,suppos:[12,23,49],suppress:[5,40],suppresswarn:5,sure:[15,18,21,39,40,41,44,46,49,51,52],surfac:12,surround:5,surviv:12,suspend:[],suspens:[9,35],swap:[],swapping_signatures:12,swapsignatureswithsel:12,sync:[35,49,51],synchronis:[5,21,35,43],syntax:[0,14,49],system:[0,4,8,10,12,19,21,27,28,29,30,31,33,34,35,38,40,49,51],systemd:[29,45],systemus:31,tab:[1,5,10,15,16,40,43,51],tabl:[10,33,34,35,38,40,43,51],tableprefix:38,tackl:40,tag:[4,5,17,41,51],tag_nam:51,take:[1,3,5,7,9,11,12,13,19,22,23,24,26,29,30,33,36,37,40,41,43,44,47,49,50,51,53],taken:[1,9,49],talk:[13,50],tamper:12,target:[2,5,8,13,14,15,23,32,33,51],tasknam:15,tcp:[10,33,43,51],tear:[],teardown:13,techniqu:[5,19,27,36,51],tell:[2,12,48,51],templat:[],tempor:23,temporari:[10,12,31],temporarili:[12,41],tempt:[44,49],ten:49,tend:17,tenor:[7,22,33,36],term:[1,3,6,8,11,17,22,25,27,31,43,45,50],termin:[7,10,12,33,35,40,43,48,51],test:[],test_tx_time:53,testcompil:51,testnam:29,testnet:[8,10,37,40,45,51],testpassword:52,testtimelock:49,testuser:52,texa:25,text:[1,5,33,40,51,53],textual:28,than:[3,4,5,10,12,15,16,21,22,23,27,31,32,33,36,37,40,47,49,51,53],thank:40,thei:[0,1,3,4,5,6,7,9,10,11,12,16,17,18,21,23,24,25,26,27,29,30,31,32,33,35,36,38,40,41,43,44,46,47,49,50,51],theirsign:47,theirstat:47,them:[],theme:[40,44],themselv:[4,12,13,22,29,31,32,35,36,43,44,48,49,50,51],therefor:[0,4,9,10,12,17,19,35,41,43,44,47,49],thi:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,15,16,17,18,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,43,44,45,46,47,48,49,50,51,52,53,54],thin:31,thing:[],think:[5,12,20,31,44,49],third:[24,30,40,43,51],thisstateref:11,thoma:40,thorough:12,those:[0,1,4,11,12,21,23,24,33,36,43,44,49,50,51],though:[12,30,33,36,49],thought:[14,23,24],threadsaf:5,three:[1,3,10,12,23,30,34,43,49,50,52],threshold:[17,22,33,35,40],through:[3,4,7,9,11,12,23,24,25,31,32,33,35,36,40,47,49,51,53],throughout:51,throughput:21,thrown:[4,12,44,49],thu:[3,5,8,11,21,22,23,27,28,33,35,36,40,47,49,50],tick:51,ticket:12,tidi:13,tighten:49,tightli:12,time:[],timelin:49,timem:49,timeout:4,timestamp:[],titl:16,tls1:35,tls:[8,24,27,31,40],toblock:[46,52],todo:[5,12,36,46,49],togeth:[1,3,6,9,23,28,30,40,49,50,51],toinstant:51,token:[3,9,12,25,47,50],tokeypair:36,told:5,toledgertransact:[22,47],toler:[11,21],tolist:47,too:[5,12,15,40,47,49],took:[12,50],tool:[0,12,14,15,17,23,24,29,31,32,33,34,38,40,43,46,51],toolbar:[],top:[1,3,5,9,12,16,29,31,34,40,43,48,50,51,53],topic:[21,31,49],topicsess:[31,40],topolog:34,topriv:12,torn:40,toset:47,tosignedtransact:[12,13,22,46,47,49,54],tostateandref:47,tostr:[5,12,38,49],total:[0,22,29,33,47],totypedarrai:47,touch:[15,18],toward:[40,41],towiretransact:[22,30,36],trace:[12,33,50],track:[],tracker:[12,26,40],trade:[],tradeapprovalcontract:47,tradeoff:[5,36,40],trader:[],traderequest:12,traffic:[8,32],transact:[],transactionbuild:[12,22,36,40,46,47,49,54],transactionforcontract:[3,49,50],transactionforverif:49,transactionst:[21,22,30,40],transactionstorag:35,transactiontyp:[12,40,46,47,54],transactionverificationexcept:53,transfer:[28,43,44,47,49,53,54],transferedfundsoutput:47,transform:26,transit:[22,23,25,27,35,44,47,49],translat:35,transmit:[],transport:[0,8,10,51],travel:49,treat:[10,31,40,44,49],tree:[],tri:[0,40,49],tricki:12,trigger:[3,6,11,12,29,35,36,43,50],trivial:[5,46],troubl:16,trust:[6,8,23,27,35,37,44,47],trustpass:[8,45],truststor:[8,35,51],truststorepassword:[8,45],truth:12,tune:[],tunnel:45,tupl:5,ture:23,turn:[3,12,25,49,50,53],tutori:[],tweak:[29,40,53],twice:53,two:[],twopartydealflow:11,twopartytradeflow:[12,26],txb:22,txhash:[12,48,49,54],txid:47,txstate:36,txt:[33,51],type:[],typenam:12,typeonlycommanddata:[49,50],typetobui:12,typic:[0,1,9,11,12,22,25,31,33,35,36,38,44,46,47,49],ugli:12,ultim:[35,47],ultimat:33,unaccept:12,unacceptablepriceexcept:12,unavoid:12,uncertain:43,unchang:40,unclutt:12,unconfirm:47,unconsum:[28,35,38],undelet:[15,16],under:[2,10,22,29,35,40,41,43,48,49,50,53],undergo:40,underli:[6,7,12,22,25,27,40],underpin:20,underscor:5,understand:[0,32,33,36,47,49,50,51],unencrypt:8,unexpect:[12,44,51],unfamiliar:15,unfinish:12,unfortun:[12,33,44,49],unicredit:40,unifi:40,uniform:11,unilater:47,unindex:16,union:47,uniqu:[11,12,21,22,23,24,25,31,35,36,37,39,40,46],uniqueidentifi:[],uniquenessprovid:35,unit:[0,3,12,13,21,22,28,29,31,35,36,40,47,49,51,53],univers:40,unknow:21,unknown:[22,47],unknownfix:36,unless:[5,12,36,41,49,51],unlik:[35,49],unlike:[6,9],unlink:16,unlock:8,unmerg:51,unpack:[10,35,49],unpars:23,unprocess:[3,50],unread:12,unrecognis:49,unrel:[49,50,51],unresolv:[],unschedul:11,unserialis:12,unset:7,unspecifi:52,unspent:[17,23,28],unstabl:15,unstarted:12,unsubscrib:4,unsubscript:4,unsupportedoperationexcept:[4,49],until:[4,7,11,12,13,21,35,36,40,41,43,45,51,53],untrust:12,untrustworthi:27,untrustworthydata:[12,40,44],unverifiedtransact:53,unwrap:[12,36,40,47],upcom:[11,40],updat:[4,9,10,12,15,16,23,28,29,31,35,40,41,47,48,49,51,52],update:52,upgrad:[12,16,26,38,40,49],upgrade:40,uphold:49,upload:[],uploadattach:46,uploadrat:43,upon:[7,10,12,16,17,24,28,35,43,47,49,51],upward:41,urandom:29,url:[8,10,15,33,37,40,43,45,51],usa:34,usabl:[0,40,41,49],usag:[],usage:[3,48],usb:51,usd:[29,34,48],use:[1,5,6,34,43,51],usehttps:[8,45],useless:49,user1:[8,34,43,45,51],usernam:[1,4,8,27,31,33,34,39,43,48],using:[],usr:2,usual:[5,10,16,23,28,43,47,49,50,51],usualli:[3,41,50,51],utc:11,util:[],utilis:[32,48],utiliti:37,utxo:[11,17,23],uuid:[22,40],vagu:5,val:[3,5,11,12,13,21,22,29,30,36,38,46,47,48,49,50,51,52,53,54],valid:[],validatedtransact:13,validfrom:49,valu:[5,6,7,8,9,12,21,28,30,34,35,36,40,42,43,47,49,50,51,53],valuabl:36,valueof:48,vanilla:[6,7],vari:[],variabl:[5,7,10,12,39,49],variant:[35,49],variou:[5,9,12,23,31,33,35,40,43,44,49,51],vault:[],vaultandupdat:[48,52],vaultservic:[9,12,35,47],vaultsselfissu:29,vcs:[],vega:40,vendor:[19,33],verbos:49,verdict:47,veri:[5,6,8,12,17,33,35,36,43,44,49,53],verif:[],verifi:[],verifiedtransact:[46,48],verifyclaus:[3,50],verifying:12,verifylifecycl:3,verifypropos:40,verifysignatur:[12,47],versa:[6,7,12,23,25],versionnumb:51,versu:12,vertic:5,vet:44,vice:[6,7,12,23,25],video:40,virtual:[1,9,17,23,44],visibl:[],vision:[18,51],visit:[1,8],visual:[34,40,43],visualis:[31,32,48,51],visualvm:33,vital:12,vpn:45,wai:[3,4,5,10,11,12,15,16,17,21,23,29,30,31,33,34,36,38,40,43,45,47,49,51,53],wait:[11,12,13,16,29,35,36,40,43,46,51,52],waitforallnodestofinish:[48,51],wake:40,walk:23,wallet:[11,12,17,28,40,49],want:[0,3,4,5,12,15,18,22,29,30,33,36,40,43,44,49,50,51,52,53,54],warn:[],watch:[18,44,46],weak:[22,36],wear:41,web:[],webaddress:[8,45],webapi:9,webapp:40,webinar:18,webport:[10,51],webserv:[40,45],websit:[1,15,16],week:14,weekend:7,weight:22,well:[0,2,5,7,9,11,12,17,19,23,24,30,33,35,38,40,46,47,49,50,51],went:5,were:[3,5,12,35,36,43,47,49,51],west:25,what:[],whatev:[5,12,25,32,35,36,47],when:[0,1,3,4,5,6,7,8,9,10,11,12,13,15,16,21,22,23,25,26,29,31,32,33,34,35,36,37,38,40,43,44,46,47,48,49,50,51,53],whenev:[5,15],where:[],wherea:[7,43],wherebi:[1,50],wherev:33,whether:[3,4,6,12,21,22,26,29,35,36,40,45,49,50],which:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,15,16,17,18,19,21,22,23,24,25,26,27,28,29,30,31,32,33,35,36,38,40,41,43,45,46,47,48,49,50,51,52,53,54],whilst:[12,32,35,36,40,44,49],white:[9,18,20,21,23,26,27,28,40,51],whitelist:[6,9,10,11,12,48],who:[5,8,12,14,21,22,23,27,31,36,40,43,49,51],whole:[30,35,42,53],whom:6,whose:[6,21,33],why:[],wide:[4,5,30],widescreen:5,widespread:5,widget:[34,51],width:5,wiki:[49,50],wikipedia:[49,50],wipe:16,wiretransact:[],wish:[1,10,12,25,36,38,39,40,43,47,49,51],wit:45,withattach:13,within:[],withitem:[22,47,49],withkei:[12,47],withnewown:[12,49],without:[],withoutissu:[12,49],withoutown:[49,50],withowner:[49,53],won:[12,16,31,34,36,40,48,49,51,52,53],word:[5,8,21],work:[],worker:5,workflow:[1,9,23,26,47],workflowtransactionbuildtutori:47,workflowtransactionbuildtutorialtest:47,working:36,workspac:[8,9,10,35,37,47],world:[8,12,23,32,34,36,43,45,47,49,53],worn:49,worri:[5,12,49,51],worth:[5,44,49,50,51],worthless:36,would:[0,4,5,6,7,9,10,12,17,19,22,23,32,33,36,43,44,46,47,49,50,51,52,54],wouldn:36,wow:51,wrap:[3,5,12,22,25,31,33,35,40,44,49,50],wrapper:[0,5,12,15,21,48,51],write:[],written:[2,3,4,7,14,15,23,26,36,40,47,49,51,52],wrong:[4,5,12,53],wtx:[12,30,36,46,47],www:2,xcode:[],xml:33,xmx1024m:33,xsrf:51,xss:51,xterm:10,year:[7,12],yellow:26,yet:[5,7,12,17,19,22,28,32,34,37,40,47,52],yield:[23,33],york:10,you:[0,1,2,3,4,5,10,11,12,13,14,15,16,18,19,22,25,29,30,31,32,33,34,36,37,38,39,40,42,43,44,45,48,49,50,51,52,53],your:[],yourself:[11,18,22,44,50,51],zero:[3,17,23,24,36,49,51],zip:[23,33,43,46],zone:11,zoneddatetim:11,zoom:40},titles:["CLI vs IDE","Working with the Corda Demo on Azure Marketplace","Building the documentation","Clauses","Client RPC","Code style guide","Contract catalogue","Interest rate swaps","Node configuration","The Corda plugin framework","CorDapp basics","Event scheduling","Writing flows","Writing flow tests","Further notes on Kotlin","Getting set up","Troubleshooting","Glossary","Welcome to the Corda documentation!","What’s included?","Overview","Consensus and notaries","Core types","Data model","Corda ecosystem","Financial model","Flow framework","Security model","Vault","Load testing","Transaction tear-offs","Networking and messaging","Network Simulator","Node administration","Node Explorer","Brief introduction to the node services","Writing oracle services","Network permissioning","Persistence","Publishing Corda","Release notes","Release process","Running a notary service","Running the demos","Secure coding guidelines","What is a corda network?","Using attachments","Building transactions","Client RPC API tutorial","Writing a contract","Writing a contract using clauses","The CorDapp template","Integration testing","Writing a contract test","Using a notary service"],titleterms:{"class":[4,36,48,49,50],"function":[12,49],"import":16,"try":16,about:16,abstractconserveamount:3,abstractissu:3,access:33,across:51,adding:49,administr:33,advanc:1,again:16,against:10,agreement:43,aka:43,allof:3,amount:25,anyof:3,api:[48,49],app:10,approach:36,artemismessagingserv:35,assert:36,assertion:5,asset:49,assign:54,attach:[33,46],attachment:[43,46],azure:1,background:[43,51],bank:43,basic:[3,10,36,47],befor:39,bind:36,brief:35,build:[2,10,37,47,51],buyer:12,cash:6,catalogu:6,central:39,certif:[37,45],chain:53,chang:21,check:49,claus:[3,49,50],cli:0,client:[4,36,48,51],cluster:29,code:[5,15,44,49],command:[0,16,47,49,51],comment:5,commerci:[6,49,50],commit:47,commod:6,common:16,compil:5,complain:16,complet:47,composit:[3,22],compositekei:22,configur:[8,16,29,45,51],connect:45,consensu:21,consol:51,construct:49,content:18,continu:36,contract:[6,23,44,49,50,53],control:[],corda:[1,9,10,15,18,24,30,39,43,45],cordapp:[10,15,24,36,48,51],cordform:10,core:[22,36],creat:7,cryptographi:22,cut:41,data:[23,30,36],databas:33,date:22,dbcheckpointstorag:35,dbtransactionmappingstorag:35,dbtransactionstorag:35,debug:[0,10,50,51],demo:[1,34,43,46],deploi:[1,51],detail:7,document:[2,18],download:33,e2etestkeymanagementservic:35,ecosystem:24,encumbranc:49,error:[4,5],event:[11,35],exampl:[8,11,30,51],execut:43,explorer:34,extend:51,featur:12,field:8,file:[8,16,51],filteron:3,financi:25,firstof:3,fix:33,flow:[12,13,26,35,36,44],format:8,found:16,framework:[9,26,35],frequent:0,from:[36,48,51],further:14,futur:12,gather:47,gener:[5,47,49],get:[15,39,51],git:15,glossari:17,gradl:[0,10,15,16,51],group:[49,50],groupclauseverifi:3,guid:5,guidelin:44,handl:4,happen:[43,49],hibernateobserv:35,hide:[30,36],how:[11,29,49,50],http:51,ide:[0,15],idea:[15,16],ident:35,implement:[11,12,35,36],includ:19,individu:29,initial:43,inmemoryidentityservic:35,inmemorynetworkmapcach:35,inmemorystatemachinerecordedtransactionmappingstorag:35,inmemoryuniquenessprovid:35,input:47,install:10,installat:[],instanc:7,integrat:52,intellij:[0,51],interact:51,interest:[6,7,33],interfac:[32,34],introduct:[11,12,35,36,43,47],irs:[1,43],issu:16,java:16,javafx:16,jcenter:39,jdk:16,jvm:15,kei:[22,35],kotlin:[14,15,16],kryo:[4,48],lack:16,length:5,lifecycl:[7,22,47],line:[0,5,51],load:29,local:[39,51],locat:8,log:[1,33,45],mac:0,machin:51,make:[16,49],manag:35,map:[31,38],margin:43,marketplac:1,math:22,maven:39,memori:33,merkl:30,messag:[31,35],mileston:[16,40,51],miss:16,model:[21,23,25,27],modul:16,monitor:33,multi:[22,49],multipl:21,name:5,namedbyhash:22,network:[31,32,35,36,37,45],networkmapservic:35,next:[1,15],node:[8,10,33,34,35,45,51],nodeattachmentservic:35,nodemessagingcli:35,nodeschedulerservic:35,nodeschemaservic:35,nodevaultservic:35,non:[16,49],notari:[21,35,42,43,54],notaris:54,notaryservic:35,note:[14,40],notion:43,nozerosizedoutput:3,object:38,obligat:6,observabl:4,off:30,opene:[15,51],oracl:[16,36],orient:49,other:[3,16],outdat:16,output:47,overview:[20,23],own:45,pai:36,paper:[6,49,50],parti:[12,22,49],partial:47,particular:49,per:36,permiss:37,persist:[10,35,38],persistentkeymanagementservic:35,persistentnetworkmapservic:35,persistentuniquenessprovid:35,plai:36,pleas:16,plugin:[9,10,16,36],portfolio:43,pre:1,present:16,process:41,progress:12,project:[16,51],properti:5,protocol:4,provid:[36,51],publish:39,put:49,queri:36,queue:31,raft:43,raftuniquenessprovid:35,raftvalidatingnotaryservic:35,rate:[6,7,33],refer:[16,22],regist:[4,48],relat:[16,35,38],releas:[16,40,41,51],represent:23,request:37,requir:[2,15,49],requisit:1,rpc:[4,48,51],run:[16,29,34,37,42,43,51],safeti:4,schedul:[11,35],schema:38,sdk:16,secur:[4,27,31,44,48],seller:12,servic:[10,31,35,36,42,51,54],set:[15,45],setup:39,sign:[36,37],signatur:22,signedtransact:47,simm:[1,43],simpl:50,simplenotaryservic:35,simul:32,singl:53,smart:49,snapshot:51,softwar:15,sourc:[15,16],space:5,start:[10,12,45,49,51],state:[10,22,23,25,49],statemachinemanag:35,step:[1,15,41,43],storag:35,storageserviceimpl:35,structur:[3,51],style:5,sub:[12,36],summari:50,support:22,suspend:12,swap:[6,7],task:0,tear:30,technic:7,templat:[10,51],test:[13,29,49,52,53],them:50,theori:12,thing:49,thread:[4,5],time:49,timestamp:21,track:12,trade:12,trader:43,transact:[22,23,30,36,47,49,53,54],transmit:49,tree:30,troubleshoot:16,tune:33,tutori:48,two:[12,36],type:[3,22,31],unabl:16,uniqueidentifi:22,unix:0,unresolv:16,upload:33,usag:[30,33],used:0,user:1,using:[10,36,46,49,51,54],util:37,valid:[21,23],validatingnotaryservic:35,valuat:1,vari:36,vault:[28,35],verif:22,verifi:49,version:[4,12],via:[0,36,51],view:[1,10],visibl:47,warn:5,web:51,welcom:18,what:[19,32,43,45,50],where:49,why:50,window:0,wire:4,wiretransact:47,within:35,without:[],work:[1,50,51],write:[12,13,29,36,49,50,53],xterm:16,your:[10,12,33,45,48,49,51]}}) \ No newline at end of file diff --git a/docs/build/html/secure-coding-guidelines.html b/docs/build/html/secure-coding-guidelines.html index 5c0cb84421..696532f386 100644 --- a/docs/build/html/secure-coding-guidelines.html +++ b/docs/build/html/secure-coding-guidelines.html @@ -34,6 +34,9 @@ + + @@ -104,11 +107,15 @@ API reference: Kotlin/ Key concepts

                              CorDapps

                                @@ -146,6 +153,8 @@ API reference: Kotlin/ Other

                                Component library

                                diff --git a/docs/build/html/setting-up-a-corda-network.html b/docs/build/html/setting-up-a-corda-network.html index e8b5038b5b..9432a768b6 100644 --- a/docs/build/html/setting-up-a-corda-network.html +++ b/docs/build/html/setting-up-a-corda-network.html @@ -34,6 +34,9 @@ + + @@ -104,11 +107,15 @@ API reference: Kotlin/ Key concepts

                                CorDapps

                                  @@ -146,6 +153,8 @@ API reference: Kotlin/ Other

                                  Component library

                                  diff --git a/docs/build/html/tutorial-attachments.html b/docs/build/html/tutorial-attachments.html index 8502ca2e16..46d2c06c6f 100644 --- a/docs/build/html/tutorial-attachments.html +++ b/docs/build/html/tutorial-attachments.html @@ -34,6 +34,9 @@ + + @@ -104,11 +107,15 @@ API reference: Kotlin/ Key concepts

                                  CorDapps

                                    @@ -149,6 +156,8 @@ API reference: Kotlin/ Other

                                    Component library

                                    diff --git a/docs/build/html/tutorial-building-transactions.html b/docs/build/html/tutorial-building-transactions.html index 597df1b3de..91e6b09fe4 100644 --- a/docs/build/html/tutorial-building-transactions.html +++ b/docs/build/html/tutorial-building-transactions.html @@ -34,6 +34,9 @@ + + @@ -104,11 +107,15 @@ API reference: Kotlin/ Key concepts

                                    CorDapps

                                      @@ -157,6 +164,8 @@ API reference: Kotlin/ Other

                                      Component library

                                      diff --git a/docs/build/html/tutorial-clientrpc-api.html b/docs/build/html/tutorial-clientrpc-api.html index de6d7e4f65..75f314b21e 100644 --- a/docs/build/html/tutorial-clientrpc-api.html +++ b/docs/build/html/tutorial-clientrpc-api.html @@ -34,6 +34,9 @@ + + @@ -104,11 +107,15 @@ API reference: Kotlin/ Key concepts

                                      CorDapps

                                        @@ -150,6 +157,8 @@ API reference: Kotlin/ Other

                                        Component library

                                        diff --git a/docs/build/html/tutorial-contract-clauses.html b/docs/build/html/tutorial-contract-clauses.html index d58aeffe85..9fd893b4a9 100644 --- a/docs/build/html/tutorial-contract-clauses.html +++ b/docs/build/html/tutorial-contract-clauses.html @@ -34,6 +34,9 @@ + + @@ -104,11 +107,15 @@ API reference: Kotlin/ Key concepts

                                        CorDapps

                                          @@ -155,6 +162,8 @@ API reference: Kotlin/ Other

                                          Component library

                                          diff --git a/docs/build/html/tutorial-contract.html b/docs/build/html/tutorial-contract.html index 449e61da52..0e7c36970f 100644 --- a/docs/build/html/tutorial-contract.html +++ b/docs/build/html/tutorial-contract.html @@ -34,6 +34,9 @@ + + @@ -104,11 +107,15 @@ API reference: Kotlin/ Key concepts

                                          CorDapps

                                          @@ -791,7 +801,7 @@ issuance requires that the issuing party sign, so we put the key of the party th any StateAndRef (input), ContractState (output) or Command objects and it’ll build up the transaction for you.

                                          There’s one final thing to be aware of: we ask the caller to select a notary that controls this state and -prevents it from being double spent. You can learn more about this topic in the Consensus model article.

                                          +prevents it from being double spent. You can learn more about this topic in the consensus article.

                                          Note

                                          For now, don’t worry about how to pick a notary. More infrastructure will come later to automate this diff --git a/docs/build/html/tutorial-cordapp.html b/docs/build/html/tutorial-cordapp.html index 61306e85de..fcb6309e26 100644 --- a/docs/build/html/tutorial-cordapp.html +++ b/docs/build/html/tutorial-cordapp.html @@ -34,6 +34,9 @@ + + @@ -104,11 +107,15 @@ API reference: Kotlin/ Key concepts

                                          CorDapps

                                            @@ -176,6 +183,8 @@ API reference: Kotlin/ Other

                                            Component library

                                            @@ -693,7 +703,7 @@ section, above. Change directories to the bin folder:

                                            The h2 web console should start up in a web browser tab. To connect we first need to obtain a JDBC connection string. Each node outputs its connection string in the terminal window as it starts up. In a terminal window where a node is running, look for the following string:

                                            -

                                            Database connection URL is              : jdbc:h2:tcp://10.18.0.150:56736/node

                                            +

                                            Database connection URL is              : jdbc:h2:tcp://10.18.0.150:56736/node

                                            you can use the string on the right to connect to the h2 database: just paste it in to the JDBC URL field and click Connect. You will be presented with a web application that enumerates all the available tables and provides an interface for you to query them using SQL.

                                            diff --git a/docs/build/html/tutorial-integration-testing.html b/docs/build/html/tutorial-integration-testing.html index 546e235dd0..84af20ff8f 100644 --- a/docs/build/html/tutorial-integration-testing.html +++ b/docs/build/html/tutorial-integration-testing.html @@ -34,6 +34,9 @@ + + @@ -104,11 +107,15 @@ API reference: Kotlin/ Key concepts

                                            CorDapps

                                              @@ -146,6 +153,8 @@ API reference: Kotlin/ Other

                                              Component library

                                              diff --git a/docs/build/html/tutorial-test-dsl.html b/docs/build/html/tutorial-test-dsl.html index 34bea019c2..68da1ae5e1 100644 --- a/docs/build/html/tutorial-test-dsl.html +++ b/docs/build/html/tutorial-test-dsl.html @@ -34,6 +34,9 @@ + + @@ -104,11 +107,15 @@ API reference: Kotlin/ Key concepts

                                              CorDapps

                                                @@ -150,6 +157,8 @@ API reference: Kotlin/ Other

                                                Component library

                                                diff --git a/docs/build/html/using-a-notary.html b/docs/build/html/using-a-notary.html index a5bd0ac40b..e475d179b1 100644 --- a/docs/build/html/using-a-notary.html +++ b/docs/build/html/using-a-notary.html @@ -34,6 +34,9 @@ + + @@ -104,11 +107,15 @@ API reference: Kotlin/ Key concepts

                                                CorDapps

                                                  @@ -150,6 +157,8 @@ API reference: Kotlin/ Other

                                                  Component library

                                                  diff --git a/docs/source/consensus.rst b/docs/source/consensus.rst deleted file mode 100644 index 8ca2826622..0000000000 --- a/docs/source/consensus.rst +++ /dev/null @@ -1,141 +0,0 @@ -Consensus model -=============== - -The fundamental unit of consensus in Corda is the **state**. The concept of consensus can be divided into two parts: - -1. Consensus over state **validity** -- parties can reach certainty that a transaction defining output states is accepted by the contracts pointed to by the 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 -- a state has not been used as an input by more than one transaction) - -This article presents an initial model for addressing the **uniqueness** problem. - -.. note:: The current model is still a **work in progress** and everything described in this article can and is likely to change - -Notary ------- - -We introduce the concept of a **notary**, which is an authority responsible for attesting that for a given transaction, it had not signed another transaction consuming any of its input states. -The data model is extended so that 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) { - ... - } - -All transactions have to be signed by their input state notary for the output states to be **valid** (apart from *issue* transactions, containing no input states). - -.. 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 over it, attesting that the outputs are the **unique** successors of the inputs, -or provides conflict information for any input state that had been consumed by another transaction it had signed before. -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 the 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 - -A transaction should only be signed by a notary if all of its input states point to it. -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 that doesn't modify anything but the notary pointer of the state. -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**) - -Changing notaries -~~~~~~~~~~~~~~~~~ - -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.Instigator(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 this will be handled automatically on demand. - -Validation ----------- - -One of the design decisions for a notary is whether or not to **validate** a transaction before committing its input states. - -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, validation of a transaction 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. - -Our platform is flexible and we currently support 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 requested the commit. If the - conflicting transaction is valid, the current one gets aborted; if not - a dispute can be raised and the input states - of the conflicting invalid transaction are "un-committed" (to be covered by legal process). - -.. note:: At present all notaries can see the entire contents of a transaction, but we have a separate piece of work to - replace the parts of the transaction it does not require knowing about with hashes (only input references, timestamp - information, overall transaction ID and the necessary digests of the rest of the transaction to prove that the - referenced inputs/timestamps really do form part of the stated transaction ID should be visible). - -Timestamping ------------- - -In this model the notary also acts 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 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 -as well, or even requesting human signoff. Thus the time observed by the notary may be quite different to the -time observed in step 1. - -For this reason, times in transactions are specified as time *windows*, not absolute times. 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 for e.g. display purposes, there is a utility method on ``Timestamp`` to -calculate the mid point -- but in a distributed system there can never be "true time", only an approximation of it. - -In this way we express 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. diff --git a/docs/source/corda-configuration-file.rst b/docs/source/corda-configuration-file.rst index 680ceb2023..48468a0f56 100644 --- a/docs/source/corda-configuration-file.rst +++ b/docs/source/corda-configuration-file.rst @@ -82,13 +82,16 @@ path to the node's base directory. :messagingServerAddress: The address of the ArtemisMQ broker instance. If not provided the node will run one locally. -:webAddress: The host and port on which the node is available for web operations. +:webAddress: The host and port on which the bundled webserver will listen if it is started. .. note:: If HTTPS is enabled then the browser security checks will require that the accessing url host name is one of either the machine name, fully qualified machine name, or server IP address to line up with the Subject Alternative Names contained within the development certificates. This is addition to requiring the ``/config/dev/corda_dev_ca.cer`` root certificate be installed as a Trusted CA. + .. note:: The driver will not automatically create a webserver instance, but the Cordformation will. If this field + is present the web server will start. + :extraAdvertisedServiceIds: A list of ServiceType id strings to be advertised to the NetworkMapService and thus be available when other nodes query the NetworkMapCache for supporting nodes. This can also include plugin services loaded from .jar files in the plugins folder. Optionally, a custom advertised service name can be provided by appending it to the service diff --git a/docs/source/corda-plugins.rst b/docs/source/corda-plugins.rst index 2ae98e536d..33cb79d963 100644 --- a/docs/source/corda-plugins.rst +++ b/docs/source/corda-plugins.rst @@ -34,21 +34,16 @@ of the node internal subsystems. 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 embedded web server - and must have a single argument constructor taking a ``ServiceHub`` - reference. This reference provides access to functions such as querying - for states through the ``VaultService`` interface, or access to the - ``NetworkMapCache`` to identify services on remote nodes. The framework will - provide a database transaction in scope during the lifetime of the web - call, so full access to database data is valid. Unlike - ``servicePlugins`` the ``webApis`` cannot register new protocols, or - initiate threads. (N.B. The intent is to move the Web support into a - separate helper process using the RPC mechanism to control 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. (N.B. The intent is to move the Web support into a separate helper - process using the RPC mechanism to control access.) + jars. These static serving directories will not be available if the + bundled web server is not started. c. The ``requiredFlows`` property is used to declare new protocols in the plugin jar. Specifically the property must return a map with a key diff --git a/docs/source/creating-a-cordapp.rst b/docs/source/creating-a-cordapp.rst index d2babbbff5..a95eef423a 100644 --- a/docs/source/creating-a-cordapp.rst +++ b/docs/source/creating-a-cordapp.rst @@ -12,10 +12,10 @@ App plugins To create an app plugin you must you must extend from `CordaPluginRegistry`_. The JavaDoc contains specific details of the implementation, but you can extend the server in the following ways: -1. Required flows: Specify which flows will be whitelisted for use in your web APIs. +1. Required flows: Specify which flows will be whitelisted for use in your RPC calls. 2. Service plugins: Register your services (see below). -3. Web APIs: You may register your own endpoints under /api/ of the built-in web server. -4. Static web endpoints: You may register your own static serving directories for serving web content. +3. Web APIs: You may register your own endpoints under /api/ of the bundled web server. +4. Static web endpoints: You may register your own static serving directories for serving web content from the web server. 5. Registering your additional classes used in RPC. Services diff --git a/docs/source/data-model.rst b/docs/source/data-model.rst deleted file mode 100644 index b4fd05b58c..0000000000 --- a/docs/source/data-model.rst +++ /dev/null @@ -1,275 +0,0 @@ -Data model -========== - -This article covers the data model: how *states*, *transactions* and *code contracts* interact with each other and -how they are represented in software. - -Overview --------- - -We begin with the idea of a global ledger. In our model 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 should be possible to keep the relevant data purely within that group. - -To ensure consistency in a global, shared system where not all data may be visible to all participants, we rely -heavily on secure hashes like SHA-256 to identify things. The 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**. - -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, so states currently point at - statically created object instances. This will change in the near future. - -Contracts define a **verify function**, which is a pure function given the entire transaction as input. To be considered -valid, the transaction must be **accepted** by the verify function of every contract pointed to by the input and output -states. - -Beyond inputs and outputs, transactions may also contain **commands**, small data packets that -the platform does not interpret itself but which can parameterise execution of the contracts. They can be thought of as -arguments to the verify function. Each command has a list of **public keys** associated with it. The platform ensures -that the transaction is signed by 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:: Attachments must be opened explicitly in the current code. - -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, with the signature of a special kind of service called a **notary**. A notary is -a (very likely) decentralised service which fulfils the role that miners play in other blockchain systems: -notaries ensure only one transaction can consume any given output. Additionally they may verify a **timestamping -command** placed inside the transaction, which 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. Each state points to the notary that -controls it. Whilst a single transaction may only consume states if they are all controlled by the same notary, -a special type of transaction is provided that moves a state (or set of states) from one notary to another. - -.. note:: Currently the platform code will not re-assign states to a single notary as needed for you, in case of - a mismatch. This is a future planned feature. - -As the same terminology often crops up in different distributed ledger designs, let's compare this to other -systems you may be familiar with. The key differences are: - -* Improved contract flexibility vs Bitcoin -* Improved scalability vs Ethereum, as well as ability to keep parts of the transaction graph private (yet still uniquely addressable) -* No reliance on proof of work -* Re-use of existing sandboxing virtual machines -* Use of type safe GCd implementation languages -* Simplified auditing - -Comparison with Bitcoin ------------------------ - -Similarities: - -* The basic notion of immutable states that are consumed and created by transactions is the same. -* The notion of transactions having multiple inputs and outputs is the same. Bitcoin sometimes refers to the ledger - as the unspent transaction output set (UTXO set) as a result. -* Like in Bitcoin, a contract is pure function. Contracts do not have storage or the ability to interact with anything. - Given the same transaction, a contract's accept function always yields exactly the same result. -* Bitcoin output scripts are parameterised by the input scripts in the spending transaction. This is somewhat similar - to our notion of a *command*. -* Bitcoin has a global distributed notary service; that's the famous block chain. However, there is only one. Whilst - there is a notion of a "side chain", this isn't integrated with the core Bitcoin data model and thus adds large - amounts of additional complexity meaning in practice side chains are not used. -* Bitcoin transactions, like ours, refer to the states they consume by using a (txhash, index) pair. The Bitcoin - protocol calls these "outpoints". In our code they are known as ``StateRefs`` but the concept is identical. -* Bitcoin transactions have an associated timestamp (the time at which they are mined). - -Differences: - -* A Bitcoin transaction has a single, rigid data format. A "state" in Bitcoin is always a (quantity of bitcoin, script) - pair and cannot hold any other data. Some people have been known to try and hack around this limitation by embedding - data in semi-standardised places in the contract code so the data can be extracted through pattern matching, but this - is a poor approach. Our states can include arbitrary typed data. -* A Bitcoin transaction's acceptance is controlled only by the contract code in the consumed input states. In practice - this has proved limiting. Our transactions invoke not only input contracts but also the contracts of the outputs. -* A Bitcoin script can only be given a fixed set of byte arrays as the input. This means there's no way for a contract - to examine the structure of the entire transaction, which severely limits what contracts can do. -* Our contracts are Turing-complete and can be written in any ordinary programming language that targets the JVM. -* Our transactions and contracts get their time from an attached timestamp rather than a block. This is - important given that we use block-free conflict resolution algorithms. The timestamp can be arbitrarily precise. -* We use the term "contract" to refer to a bundle of business logic that may handle various different tasks, beyond - transaction verification. For instance, currently our contracts also include code for creating valid transactions - (this is often called "wallet code" in Bitcoin). - -Comparison with Ethereum ------------------------- - -Similarities: - -* Like Ethereum, code runs inside a relatively powerful virtual machine and can contain complex logic. Non-assembly - based programming languages can be used for contract programming. -* They are both intended for the modelling of many different kinds of financial contract. - -Differences: - -* The term "contract" in Ethereum refers to an *instantiation* of a program that is replicated and maintained by - every participating node. This instantiation is very much like an object in an OO program: it can receive and send - messages, update local storage and so on. In contrast, we use the term "contract" to refer to a set of functions, only - one of which is a part of keeping the system synchronised (the verify function). That function is pure and - stateless i.e. it may not interact with any other part of the system whilst executing. -* There is no notion of an "account", as there is in Ethereum. -* As contracts don't have any kind of mutable storage, there is no notion of a "message" as in Ethereum. -* Ethereum claims to be a platform not only for financial logic, but literally any kind of application at all. Our - platform considers non-financial applications to be out of scope. - -Rationale for and tradeoffs in adopting a UTXO-style model ----------------------------------------------------------- - -As discussed above, Corda uses the so-called "UTXO set" model (unspent transaction output). In this model, the database -does not track accounts or balances. Instead all database entries are immutable. An entry is either spent or not spent -but it cannot be changed. In Bitcoin, spentness is implemented simply as deletion – the inputs of an accepted transaction -are deleted and the outputs created. - -This approach has some advantages and some disadvantages, which is why some platforms like Ethereum have tried -(or are trying) to abstract this choice away and support a more traditional account-like model. We have explicitly -chosen *not* to do this and our decision to adopt a UTXO-style model is a deliberate one. In the section below, -the rationale for this decision and its pros and cons of this choice are outlined. - -Rationale ---------- - -Corda, in common with other blockchain-like platforms, is designed to bring parties to shared sets of data into -consensus as to the existence, content and allowable evolutions of those data sets. However, Corda is designed with the -explicit aim of avoiding, to the extent possible, the scalability and privacy implications that arise from those platforms' -decisions to adopt a global broadcast model. - -Whilst the privacy implications of a global consensus model are easy to understand, the scalability implications are -perhaps more subtle, yet serious. In a consensus system, it is critical that all processors of a transaction reach -precisely the same conclusion as to its effects. In situations where two transactions may act on the same data set, -it means that the two transactions must be processed in the same *order* by all nodes. If this were not the case then it -would be possible to devise situations where nodes processed transactions in different orders and reached different -conclusions as to the state of the system. It is for this reason that systems like Ethereum effectively run -single-threaded, meaning the speed of the system is limited by the single-threaded performance of the slowest -machine on the network. - -In Corda, we assume the data being processed represents financial agreements between identifiable parties and that these -institutions will adopt the system only if a significant number of such agreements can be managed by the platform. -As such, the system has to be able to support parallelisation of execution to the greatest extent possible, -whilst ensuring correct transaction ordering when two transactions seek to act on the same piece of shared state. - -To achieve this, we must minimise the number of parties who need to receive and process copies of any given -transaction and we must minimise the extent to which two transactions seek to mutate (or supersede) any given piece -of shared state. - -A key design decision, therefore, is what should be the most atomic unit of shared data in the system. This decision -also has profound privacy implications: the more coarsely defined the shared data units, the larger the set of -actors who will likely have a stake in its accuracy and who must process and observe any update to it. - -This becomes most obvious when we consider two models for representing cash balances and payments. - -A simple account model for cash would define a data structure that maintained a balance at a particular bank for each -"account holder". Every holder of a balance would need a copy of this structure and would thus need to process and -validate every payment transaction, learning about everybody else's payments and balances in the process. -All payments across that set of accounts would have to be single-threaded across the platform, limiting maximum -throughput. - -A more sophisticated example might create a data structure per account holder. -But, even here, I would leak my account balance to anybody to whom I ever made -a payment and I could only ever make one payment at a time, for the same reasons above. - -A UTXO model would define a data structure that represented an *instance* of a claim against the bank. An account -holder could hold *many* such instances, the aggregate of which would reveal their balance at that institution. However, -the account holder now only needs to reveal to their payee those instances consumed in making a payment to that payee. -This also means the payer could make several payments in parallel. A downside is that the model is harder to understand. -However, we consider the privacy and scalability advantages to overwhelm the modest additional cognitive load this places -on those attempting to learn the system. - -In what follows, further advantages and disadvantages of this design decision are explored. - -Pros ----- - -The UTXO model has these advantages: - -* Immutable ledger entries gives the usual advantages that a more functional approach brings: it's easy to do analysis - on a static snapshot of the data and reason about the contents. -* Because there are no accounts, it's very easy to apply transactions in parallel even for high traffic legal entities - assuming sufficiently granular entries. -* Transaction ordering becomes trivial: it is impossible to mis-order transactions due to the reliance on hash functions - to identify previous states. There is no need for sequence numbers or other things that are hard to provide in a - fully distributed system. -* Conflict resolution boils down to the double spending problem, which places extremely minimal demands on consensus - algorithms (as the variable you're trying to reach consensus on is a set of booleans). - -Cons ----- - -It also comes with some pretty serious complexities that in practice must be abstracted from developers: - -* Representing numeric amounts using immutable entries is unnatural. For instance, if you receive $1000 and wish - to send someone $100, you have to consume the $1000 output and then create two more: a $100 for the recipient and - $900 back to yourself as change. The fact that this happens can leak private information to an observer. -* Because users do need to think in terms of balances and statements, you have to layer this on top of the - underlying ledger: you can't just read someone's balance out of the system. Hence, the "wallet" / position manager. - Experience from those who have developed wallets for Bitcoin and other systems is that they can be complex pieces of code, - although the bulk of wallets' complexity in public systems is handling the lack of finality (and key management). -* Whilst transactions can be applied in parallel, it is much harder to create them in parallel due to the need to - strictly enforce a total ordering. - -With respect to parallel creation, if the user is single threaded this is fine, but in a more complex situation -where you might want to be preparing multiple transactions in flight this can prove a limitation – in -the worst case where you have a single output that represents all your value, this forces you to serialise -the creation of every transaction. If transactions can be created and signed very fast that's not a concern. -If there's only a single user, that's not a concern. - -Both cases are typically true in the Bitcoin world, so users don't suffer from this much. In the context of a -complex business with a large pool of shared funds, in which creation of transactions may be very slow due to the -need to get different humans to approve a tx using a signing device, this could quickly lead to frustrating -conflicts where someone approves a transaction and then discovers that it has become a double spend and -they must sign again. In the absolute worst case you could get a form of human livelock. - -The tricky part about solving these problems is that the simplest way to express a payment request -("send me $1000 to public key X") inherently results in you receiving a single output, which then can -prove insufficiently granular to be convenient. In the Bitcoin space Mike Hearn and Gavin Andresen designed "BIP 70" -to solve this: it's a simple binary format for requesting a payment and specifying exactly how you'd like to get paid, -including things like the shape of the transaction. It may seem that it's an over complex approach: could you not -just immediately respend the big output back to yourself in order to split it? And yes, you could, until you hit -scenarios like "the machine requesting the payment doesn't have the keys needed to spend it", -which turn out to be very common. So it's really more effective for a recipient to be able to say to the -sender, "here's the kind of transaction I want you to send me". The :doc:`flow framework ` -may provide a vehicle to make such negotiations simpler. - -A further challenge is privacy. Whilst our goal of not sending transactions to nodes that don't "need to know" -helps, to verify a transaction you still need to verify all its dependencies and that can result in you receiving -lots of transactions that involve random third parties. The problems start when you have received lots of separate -payments and been careful not to make them linkable to your identity, but then you need to combine them all in a -single transaction to make a payment. - -Mike Hearn wrote an article about this problem and techniques to minimise it in -`this article `_ from 2013. This article -coined the term "merge avoidance", which has never been implemented in the Bitcoin space, -although not due to lack of practicality. - -A piece of future work for the wallet implementation will be to implement automated "grooming" of the wallet -to "reshape" outputs to useful/standardised sizes, for example, and to send outputs of complex transactions -back to their issuers for reissuance to "sever" long privacy-breaching chains. - -Finally, it should be noted that some of the issues described here are not really "cons" of -the UTXO model; they're just fundamental. If you used many different anonymous accounts to preserve some privacy -and then needed to spend the contents of them all simultaneously, you'd hit the same problem, so it's not -something that can be trivially fixed with data model changes. diff --git a/docs/source/example-code/src/integration-test/kotlin/net/corda/docs/IntegrationTestingTutorial.kt b/docs/source/example-code/src/integration-test/kotlin/net/corda/docs/IntegrationTestingTutorial.kt index d02b9b33b2..687bc46515 100644 --- a/docs/source/example-code/src/integration-test/kotlin/net/corda/docs/IntegrationTestingTutorial.kt +++ b/docs/source/example-code/src/integration-test/kotlin/net/corda/docs/IntegrationTestingTutorial.kt @@ -9,9 +9,9 @@ import net.corda.core.messaging.startFlow import net.corda.core.node.services.ServiceInfo import net.corda.core.node.services.Vault import net.corda.core.serialization.OpaqueBytes +import net.corda.core.toFuture import net.corda.flows.CashCommand import net.corda.flows.CashFlow -import net.corda.flows.CashFlowResult import net.corda.node.driver.driver import net.corda.node.services.User import net.corda.node.services.startFlowPermission @@ -87,7 +87,7 @@ class IntegrationTestingTutorial { amount = i.DOLLARS.issuedBy(alice.nodeInfo.legalIdentity.ref(issueRef)), recipient = alice.nodeInfo.legalIdentity )) - assert(flowHandle.returnValue.toBlocking().first() is CashFlowResult.Success) + flowHandle.returnValue.toFuture().getOrThrow() } aliceVaultUpdates.expectEvents { 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 71f3af45c1..9a1cba3b93 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 @@ -1,5 +1,6 @@ package net.corda.docs +import net.corda.core.crypto.Party import net.corda.core.contracts.* import net.corda.core.getOrThrow import net.corda.core.node.services.ServiceInfo @@ -9,6 +10,7 @@ import net.corda.core.utilities.DUMMY_NOTARY import net.corda.core.utilities.DUMMY_NOTARY_KEY import net.corda.flows.CashCommand import net.corda.flows.CashFlow +import net.corda.core.node.ServiceEntry import net.corda.node.services.network.NetworkMapService import net.corda.node.services.transactions.ValidatingNotaryService import net.corda.node.utilities.databaseTransaction @@ -27,10 +29,11 @@ class FxTransactionBuildTutorialTest { @Before fun setup() { net = MockNetwork(threadPerNode = true) + val notaryService = ServiceInfo(ValidatingNotaryService.type) notaryNode = net.createNode( legalName = DUMMY_NOTARY.name, - keyPair = DUMMY_NOTARY_KEY, - advertisedServices = *arrayOf(ServiceInfo(NetworkMapService.type), ServiceInfo(ValidatingNotaryService.type))) + overrideServices = mapOf(Pair(notaryService, 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) 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 8e553f4f75..70558a35a6 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,6 +4,7 @@ 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 @@ -35,10 +36,11 @@ class WorkflowTransactionBuildTutorialTest { @Before fun setup() { net = MockNetwork(threadPerNode = true) + val notaryService = ServiceInfo(ValidatingNotaryService.type) notaryNode = net.createNode( legalName = DUMMY_NOTARY.name, - keyPair = DUMMY_NOTARY_KEY, - advertisedServices = *arrayOf(ServiceInfo(NetworkMapService.type), ServiceInfo(ValidatingNotaryService.type))) + overrideServices = mapOf(Pair(notaryService, 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) diff --git a/docs/source/flow-state-machines.rst b/docs/source/flow-state-machines.rst index 460425e7d0..f01b24d79c 100644 --- a/docs/source/flow-state-machines.rst +++ b/docs/source/flow-state-machines.rst @@ -111,8 +111,8 @@ each side. object TwoPartyTradeFlow { - class UnacceptablePriceException(val givenPrice: Amount) : Exception("Unacceptable price: $givenPrice") - class AssetMismatchException(val expectedTypeName: String, val typeName: String) : Exception() { + class UnacceptablePriceException(val givenPrice: Amount) : FlowException("Unacceptable price: $givenPrice") + class AssetMismatchException(val expectedTypeName: String, val typeName: String) : FlowException() { override fun toString() = "The submitted asset didn't match the expected type: $expectedTypeName vs $typeName" } @@ -241,17 +241,11 @@ Let's implement the ``Seller.call`` method. This will be run when the flow is in .. container:: codeset - .. sourcecode:: kotlin - - @Suspendable - override fun call(): SignedTransaction { - val partialTX: SignedTransaction = receiveAndCheckProposedTransaction() - val ourSignature: DigitalSignature.WithKey = computeOurSignature(partialTX) - val allPartySignedTx = partialTX + ourSignature - val notarySignature = getNotarySignature(allPartySignedTx) - val result: SignedTransaction = sendSignatures(allPartySignedTx, ourSignature, notarySignature) - return result - } + .. literalinclude:: ../../finance/src/main/kotlin/net/corda/flows/TwoPartyTradeFlow.kt + :language: kotlin + :start-after: DOCSTART 4 + :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 @@ -265,31 +259,11 @@ Let's fill out the ``receiveAndCheckProposedTransaction()`` method. .. container:: codeset - .. sourcecode:: kotlin - - @Suspendable - private fun receiveAndCheckProposedTransaction(): SignedTransaction { - // Make the first message we'll send to kick off the flow. - val myPublicKey = myKeyPair.public.composite - val hello = SellerTradeInfo(assetToSell, price, myPublicKey) - - val maybeSTX = sendAndReceive(otherSide, hello) - - maybeSTX.unwrap { - // Check that the tx proposed by the buyer is valid. - val wtx: WireTransaction = it.verifySignatures(myPublicKey, 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(myPublicKey).withoutIssuer() != price) - throw IllegalArgumentException("Transaction is not sending us the right amount of cash") - - return it - } - } + .. literalinclude:: ../../finance/src/main/kotlin/net/corda/flows/TwoPartyTradeFlow.kt + :language: kotlin + :start-after: DOCSTART 5 + :end-before: DOCEND 5 + :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: @@ -333,6 +307,26 @@ Our "scrubbing" has three parts: 2. We resolve the transaction, which we will cover below. 3. We verify that the transaction is paying us the demanded price. +Exception handling +------------------ + +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. + +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. + +.. note:: A future version will extend this to give the node administrator more control on what to do with such erroring + flows. + +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 --------- @@ -340,13 +334,11 @@ Flows can be composed via nesting. Invoking a sub-flow looks similar to an ordin .. container:: codeset - .. sourcecode:: kotlin - - @Suspendable - private fun getNotarySignature(stx: SignedTransaction): DigitalSignature.LegallyIdentifiable { - progressTracker.currentStep = NOTARY - return subFlow(NotaryFlow.Client(stx)) - } + .. literalinclude:: ../../finance/src/main/kotlin/net/corda/flows/TwoPartyTradeFlow.kt + :language: kotlin + :start-after: DOCSTART 6 + :end-before: DOCEND 6 + :dedent: 4 In this code snippet we are using the ``NotaryFlow.Client`` to request notarisation of the transaction. We simply create the flow object via its constructor, and then pass it to the ``subFlow`` method which @@ -372,18 +364,11 @@ Here's the rest of the code: .. container:: codeset - .. sourcecode:: kotlin - - open fun calculateOurSignature(partialTX: SignedTransaction) = myKeyPair.signWithECDSA(partialTX.id) - - @Suspendable - private fun sendSignatures(allPartySignedTX: SignedTransaction, ourSignature: DigitalSignature.WithKey, - notarySignature: DigitalSignature.WithKey): SignedTransaction { - val fullySigned = allPartySignedTX + notarySignature - logger.trace { "Built finished transaction, sending back to secondary!" } - send(otherSide, SignaturesFromSeller(ourSignature, notarySignature)) - return fullySigned - } + .. literalinclude:: ../../finance/src/main/kotlin/net/corda/flows/TwoPartyTradeFlow.kt + :language: kotlin + :start-after: DOCSTART 7 + :end-before: DOCEND 7 + :dedent: 4 It's all pretty straightforward from now on. Here ``id`` is the secure hash representing the serialised transaction, and we just use our private key to calculate a signature over it. As a reminder, in Corda signatures do @@ -413,7 +398,7 @@ OK, let's do the same for the buyer side: :language: kotlin :start-after: DOCSTART 1 :end-before: DOCEND 1 - :dedent: 8 + :dedent: 4 This code is longer but no more complicated. Here are some things to pay attention to: @@ -453,7 +438,6 @@ A flow might declare some steps with code inside the flow class like this: :end-before: DOCSTART 1 :dedent: 4 - .. sourcecode:: java private final ProgressTracker progressTracker = new ProgressTracker( @@ -547,7 +531,7 @@ The flow framework is a key part of the platform and will be extended in major w the features we have planned: * Identity based addressing -* Exception propagation and management, with a "flow hospital" tool to manually provide solutions to unavoidable +* Exception management, with a "flow hospital" tool to manually provide solutions to unavoidable problems (e.g. the other side doesn't know the trade) * Being able to interact with internal apps and tools via RPC * Being able to interact with people, either via some sort of external ticketing system, or email, or a custom UI. diff --git a/docs/source/getting-set-up-fault-finding.rst b/docs/source/getting-set-up-fault-finding.rst index 1a72385894..a814b65f85 100644 --- a/docs/source/getting-set-up-fault-finding.rst +++ b/docs/source/getting-set-up-fault-finding.rst @@ -1,83 +1,83 @@ Troubleshooting =============== -IntelliJ issues ---------------- +Milestone releases +------------------ -Run configurations are missing +When you clone the corda or cordapp-template repos, they will default to the master branch. The master branch is being continuously developed upon, and its features may not align with the state of Corda as described in the docs. Additionally, the master branch of the CorDapp Template may break in response to changes in the main corda repo. + +When developing on Corda, you should always check out the latest stable branch instead, by running ``git checkout release-M7``. + +Java issues +----------- + +Outdated/non-Oracle JDKs +************************ + +Many users have faced issues when running versions of Java that are either outdated, or are produced by organisations other than Oracle (e.g. OpenJDK). The errors generated by these issues will not always clearly point to the JDK as the cause. If in doubt, check your JDK version by following the instructions `here `_. You can download the latest version of Oracle's JDK `here `_. + +"Unresolved reference: javafx" ****************************** -If you opened the Corda project using "Import" from the IntelliJ splash screen rather than using "Open" and then -importing the Gradle build system from the popup bubble, then a bug in IntelliJ will cause it to wipe and recreate -the ``.idea`` directory where the run configurations are stored. The fix is simple and doesn't require you to -re-import the project: just undelete the files! You can do that by either: +JavaFX is not bundled with OpenJDK. If you are using OpenJDK and get an 'Unresolved reference: javafx' error, this means that you need to install OpenJFX. Do this by running ``sudo apt install openjfx``, and possibly ``sudo apt install libopenjfx-jav``. -1. Running ``git checkout .idea/runConfigurations`` to restore that part of the tree to its normal state. -2. Using the "Version Control" pane in IntelliJ to undelete the files via the GUI. +IDEA issues +--------------- -If IntelliJ complains about lack of an SDK -****************************************** +No source files are present +*************************** -If on attempting to open the project (including importing Gradle project), IntelliJ refuses because an SDK was not selected, -you may need to fix the project structure. Do this by following `these instructions `_. The correct JDK is often found at a path such as ``jdk1.8.0_xx…/Contents/Home`` - -Ensure that you have the Project language level set at as 8. If you are having trouble selecting the correct JDK, the -JetBrains website offers the `following guidelines `_. - -Kotlin issues -------------- - -Installation -************ - -There are two ways to configure Kotlin from IntelliJ. One way is via the initial project opening screen in which you will -need to use the ``Configure > Plugins`` tab. The other way is when you are in an open project, then you will need to -configure it via (on Mac) ``IntelliJ -> Preferences ...``, whereas on PC it is ``File -> Settings``. Select the plugins -bar, confirm that Kotlin is installed and up to date. - -If you are having trouble installing Kotlin, first try upgrading the Kotlin plugin. At the time of writing, you can -confirm what is the latest version of the Kotlin plugin on `this page `_. - - -Gradle issues -------------- - -Gradle within IntelliJ -********************** - -After you have updated your code to the latest version from git, ensure that the gradle project is imported. Although -gradle is used via the command line, it is also integrated with IntelliJ in order for IntelliJ to determine dependencies -and index the project correctly. - -When opening a project for the first time, you should see the "Unlinked Gradle project?" pop-up window in the IntelliJ top -right corner or in a popup alert window. If you miss this, it will also appear in the "Event Log" windows which can be -opened by clicking on "Event Log" at the bottom right of the IntelliJ window. Either way, click on "Import Gradle Project". +When opening a project in IDEA for the first time, you will need to build the project. You should see "Unlinked Gradle project?" +in a pop-up window in the top-right corner or in a popup alert window. It will also appear in the "Event Log" window which can be +opened by clicking on "Event Log" at the bottom right of the IDEA window. Find one of these links and click on "Import Gradle Project". .. image:: resources/unlinked-gradle.png :height: 50 px :width: 410 px - :alt: IntelliJ Gradle Prompt + :alt: IDEA Gradle Prompt -Wait for it to think and download the dependencies. After that you might have another popup titled "Unindexed remote maven repositories found." This is a general IntelliJ question and doesn't affect Corda, therefore you can decided to index them or not. Next click on the "green arrow" next to "All tests" pop-up on the top toolbar. +Wait for it to download the dependencies. You may then see another popup titled "Unindexed remote maven repositories found." This won't affect Corda, +so you can choose to leave them unindexed. -The code should build, the unit tests should show as all green. +If still have problems, the JetBrains website has more information on `here `_. -If still have problems, the JetBrains website has more information on `gradle here `_. +Run configurations are missing +****************************** -Gradle via the CLI -****************** +If you opened the Corda project by clicking "Import Project" on the IDEA splash screen rather than clicking "Open", a bug +in IDEA will cause it to wipe and recreate the ``.idea`` directory where the run configurations are stored. The fix is +simple and doesn't require you to re-import the project: just undelete the files! You can do that by either: -Gradle commands can also be run from the command line - further details of command line gradle can be found `here `_. +1. Running ``git checkout .idea/runConfigurations`` to redownload the files. +2. Using the "Version Control" pane in IDEA to undelete the files via the GUI. -Doing it without IntelliJ -------------------------- +IDEA complains about lack of an SDK +*************************************** -If you don't want to explore or modify the code in a local IDE, you can also just use the command line and a text editor: +If IDEA refuses to open a project because an SDK has not been selected, you may need to fix the project structure. Do this by following `these instructions `_. The correct JDK is often found on a path such as ``jdk1.8.0_xx…/Contents/Home``. Ensure that you have the Project language level set at 8. -* First run ``git clone https://github.com/corda/corda`` to download Corda core source code +If you are having trouble selecting the correct JDK, the JetBrains website provides the `following guidelines `_. -* Next ensure that you are in correct directory ``cd corda`` +Kotlin plugin +************* -* Then you can run ``./gradlew test`` to run the unit tests. +There are two ways to configure Kotlin in IDEA: -* Finally remember to run ``git pull`` occasionally to upgrade the source code to the latest revision +1. Via the initial project opening screen, by using the ``Configure > Plugins`` tab. +2. From an open IDEA project, by clicking ``IDEA -> Preferences ...`` (on OS X) or ``File -> Settings`` (on Windows). Select the Plugins bar to confirm that Kotlin is installed and up-to-date. + +If you are still having trouble installing Kotlin, first try upgrading the Kotlin plugin. At the time of writing, you can +identify the latest version of the Kotlin plugin on `this page `_. + +"Unable to make the module: related gradle configuration was not found. Please, re-import the Gradle project and try again" +*************************************************************************************************************************** + +This can usually be solved by updating IDEA. Check that you have the latest version `here `_. + +Other common issues +------------------- + +“xterm: command not found” +************************** + +On some machines, running the samples requires xterm. You can download it `here `_. \ No newline at end of file diff --git a/docs/source/getting-set-up.rst b/docs/source/getting-set-up.rst index 45d37547aa..85a178a566 100644 --- a/docs/source/getting-set-up.rst +++ b/docs/source/getting-set-up.rst @@ -1,83 +1,103 @@ Getting set up ============== -We have tried to make access to Corda as relatively simple as possible, using industry standard established tools. -Although it is possible to replace any of the recommendations below, we will find it a lot easier to support your efforts -if you follow our guidelines. Saying that, we are also interested in problems that arise due to different configurations. +Software requirements +--------------------- -A JVM ------ +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're interested to hear about any issues that arise. -Corda runs in a JVM and is written predominantly in Kotlin with some example use cases demonstrated in Java that we have -incorporated to demonstrate that Kotlin and Java can work seamlessly together. We recommend the most recent production -version of Java 8. The JDK can be obtained `from Oracle `_. -Other implementations of the JVM are not actively supported, but as mentioned, we are interested in finding out any issues you -do have with them. +JVM +~~~ -.. note:: If you are using a JVM implementation other than Oracle's you may get errors similar to ``Unresolved reference: javafx``. - This means JavaFX is not bundled with the JVM and you will need to install it separately (e.g. OpenJFX is needed - with OpenJDK). +Corda is written in Kotlin and runs in a JVM. We develop against Oracle JDK 8, and other JVM implementations are not actively +supported. Oracle JDK 8 can be obtained directly from +`Oracle `_. Installation instructions are +available for `Windows `_, +`Linux `_ and +`OS X `_. -IntelliJ --------- -We strongly recommend the use of IntelliJ's Development Environment known as IDEA. Download it for free from -`JetBrains `_. The primary reason we recommend this particular IDE is that it integrates -very well with our choice of language for Corda, "Kotlin", as JetBrains also support the development of Kotlin. +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. -.. warning:: When opening the Corda project for the first time from the IntelliJ splash screen, please use "Open" - and then agree to import the Gradle project from the popup bubble. Don't pick "Import" on the splash screen, - because a bug in IntelliJ will cause the pre-packaged run configurations to be erased. If you see this warning - too late, it's no problem, just use ``git checkout .idea/runConfiguration`` or the version control tab in IntelliJ - to undelete the files. +If you do choose to use OpenJDK instead of Oracle's JDK, you will also need to install OpenJFX. +Additional troubleshooting information can be found `here `_. Kotlin ------- -Kotlin is available as a downloadable plugin to IntelliJ. Refer to IntelliJ's instructions on -`getting Started with Kotlin and IntelliJ `_. Additionally, -if you would like to start getting to grips with the Kotlin language, then we strongly recommend you work through some -of the tutorials (known as "koans") as well. Also see our :doc:`further-notes-on-kotlin`. +~~~~~~ +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`. -Version control via Git ------------------------ +IDE +~~~ -We use git to version control Corda. The authoritative place to obtain git is from the main `git website `_ -but it may be the case that your operating system provides git with a supported utility (e.g. for Apple, git is provided along -with XCode - their free development environment). If this is the case, we would recommend you obtain git via that -supported route. +We strongly recommend the use of IntelliJ IDEA as an IDE, primarily due to the strength of its Kotlin integration. The free Community +Edition can be downloaded from `JetBrains `_. -You will need the command line package installed which you can then use natively (via the command line) or via IntelliJ -(in which case you may need to configure IntelliJ to recognise where git has been installed on your system). IntelliJ and -git configuration are quite seamless although the first time you use it, you will have to configure IntelliJ the location -of your git command installation. More details regarding this can be found -on the `JetBrains website `_ +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. + +You'll also want to install the Kotlin IDEA plugin by following the instructions +`here `_. + +Additional troubleshooting information can be found `here `_. + +Git +~~~ + +We use git to version-control Corda. Instructions on installing git can be found +`here `_. + +Following these instructions will give you access to git via the command line. It can also be useful to control git via IDEA. Instructions +for doing so can be found on the `JetBrains website `_. Gradle ------- +~~~~~~ -Gradle is our primary means of building Corda and managing dependencies. IntelliJ has its own view of this and occasionally -may need to be resynced from time to time. This can be done within IntelliJ by pressing the "gradle refresh" icon located -on the gradle tab (generally found on the right hand side), or by following the gradle commands specific for the task you -are performing (details expounded later). Whenever prompted about gradle, accept the defaults suggested by IntelliJ. +We use Gradle as the build tool for Corda. However, you do not need to install Gradle itself, as a wrapper is provided. +The wrapper can be run from the command line by using ``./gradlew [taskName]`` on OS X/Linux, or ``gradlew.bat [taskName]`` on Windows. Corda source code ----------------- -You can check out the Corda platform source code from this repository: +The Corda platform source code is available here: https://github.com/corda/corda.git -and a template app that you can use as a basis for experimenting with app development from: +and a basic CorDapp that you can use as the basis for your own CorDapps is available here: https://github.com/corda/cordapp-template.git -You can catch up with the latest code by selecting "VCS -> Update Project" in the IntelliJ menu. +You can clone both of these repos to your local machine by running the command ``git clone [repo URL]``. +By default, both repos will be on the ``master`` branch. However, this is an unstable development branch. You should check +out the latest milestone release (currently Milestone 7) instead by running ``git checkout release-M7``. -Troubleshooting ---------------- +Opening Corda/CorDapps in IDEA +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -See :doc:`getting-set-up-fault-finding`, or get in touch with us either on the `forums `_ or via `slack `_. +When opening a Corda project for the first time from the IDEA splash screen, please click "Open" rather than "Import Project", +and then import the Gradle project by clicking "Import Gradle project" in the popup bubble on the lower right-hand side of the screen. +If you instead pick "Import Project" on the splash screen, a bug in IDEA will cause Corda's pre-packaged run configurations to be erased. +If you see this warning too late, that's not a problem - just use ``git checkout .idea/runConfiguration`` or the version control tab in +IDEA to undelete the files. + +IDEA's build of the project may need to be resynced from time to time. This can be done from within IDEA by going to "View" -> "Tool Windows" -> "Gradle" +and clicking "Refresh all Gradle projects". Whenever prompted about Gradle, accept the defaults suggested by IDEA. + +Next steps +---------- + +The best way to check that everything is working fine is by :doc:`running-the-demos`. + +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 +`forums `_ or via `slack `_. \ No newline at end of file diff --git a/docs/source/index.rst b/docs/source/index.rst index 8149311a19..e198c2450b 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -14,17 +14,18 @@ they become more familiar with Corda, readers with a technical background will a which describes the platform's envisioned end-state. Corda is designed so that developers can easily extend its functionality by writing CorDapps -(**Cor**\ da **D**\ istributed **App**\ lication\ **s**\ ). An example CorDapp is available on +(**Cor**\ da **D**\ istributed **App**\ lication\ **s**\ ). Some example CorDapps are available in the Corda repo's +`samples `_ directory. To run these yourself, make +sure you follow the instructions in :doc:`getting-set-up`, then go to +:doc:`running-the-demos`. + +If, after running the demos, you're interested in writing your own CorDapps, a template CorDapp is available on `Github `_. To get it running, follow the instructions in the `readme `_, or watch the `Corda Developers Tutorial `_. -Additional CorDapp samples are available in the Corda repo's `samples `_ -directory. These are sophisticated CorDapps that implement more complex functionality. You can find directions for -running these samples `here `_. - From there, you'll be in a position to start extending the example CorDapp yourself (e.g. by writing new states, contracts, -and/or flows). For this, you'll want to refer to this docsite, and to the `tutorials `_ +and/or flows). For this, you'll want to refer to this docsite, and to the `tutorials `_ in particular. If you get stuck, get in touch on `Slack `_ or the `forum `_. Once you're familiar with Corda and CorDapp development, we'd encourage you to get involved in the development of the @@ -50,11 +51,15 @@ Documentation Contents: :maxdepth: 2 :caption: Key concepts - data-model - transaction-data-types - merkle-trees - consensus - clauses + 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 .. toctree:: :maxdepth: 2 @@ -100,6 +105,8 @@ Documentation Contents: :caption: Other network-simulator + clauses + merkle-trees .. toctree:: :maxdepth: 2 @@ -119,6 +126,7 @@ Documentation Contents: release-notes codestyle building-the-docs + further-notes-on-kotlin publishing-corda azure-vm diff --git a/docs/source/key-concepts-consensus-notaries.rst b/docs/source/key-concepts-consensus-notaries.rst new file mode 100644 index 0000000000..5d13e4e552 --- /dev/null +++ b/docs/source/key-concepts-consensus-notaries.rst @@ -0,0 +1,163 @@ +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.Instigator(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). + +.. note:: At present, all notaries can see the entire contents of a submitted transaction. A future piece of work + will enable the processing of :doc:`merkle-trees`, thus providing data hiding of sensitive information. + +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/transaction-data-types.rst b/docs/source/key-concepts-core-types.rst similarity index 57% rename from docs/source/transaction-data-types.rst rename to docs/source/key-concepts-core-types.rst index ba27f42f72..a052a2cebd 100644 --- a/docs/source/transaction-data-types.rst +++ b/docs/source/key-concepts-core-types.rst @@ -1,73 +1,30 @@ -Data types +Core types ========== -Corda provides a large standard library of data types used in financial transactions and contract state objects. -These provide a common language for states and contracts. +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. -Amount ------- +State and References +-------------------- +State objects contain mutable data which we would expect to evolve over the lifetime of a contract. -The `Amount `_ class is used to represent an amount of some -fungible asset. It is a generic class which wraps around a type used to define the underlying product, called -the *token*. For instance it can be the standard JDK type ``Currency``, or an ``Issued`` instance, or this can be -a more complex type such as an obligation contract issuance definition (which in turn contains a token definition -for whatever the obligation is to be settled in). - -.. note:: Fungible is used here to mean that instances of an asset is interchangeable for any other identical instance, - and that they can be split/merged. For example a £5 note can reasonably be exchanged for any other £5 note, and a - £10 note can be exchanged for two £5 notes, or vice-versa. - -Here are some examples: - -.. container:: codeset - - .. sourcecode:: kotlin - - // A quantity of some specific currency like pounds, euros, dollars etc. - Amount - // A quantity of currency that is issued by a specific issuer, for instance central bank vs other bank dollars - Amount> - // A quantity of obligations to deliver currency of any issuer. - Amount> - -``Amount`` represents quantities as integers. For currencies the quantity represents pennies, cents or whatever -else the smallest integer amount for that currency is. You cannot use ``Amount`` to represent negative quantities -or fractional quantities: if you wish to do this then you must use a different type e.g. ``BigDecimal``. ``Amount`` -defines methods to do addition and subtraction and these methods verify that the tokens on both sides of the operator -are equal (these are operator overloads in Kotlin and can be used as regular methods from Java). There are also -methods to do multiplication and division by integer amounts. - -State ------ - -A Corda contract is composed of three parts; the executable code, the legal prose, and the state objects that represent -the details of a specific deal or asset (see :doc:`data-model` for further detail). In relational database terms -a state is like a row in a database. 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. +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:`consensus`). +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: +of state such as: - ``OwnableState`` - A state which has an owner (represented as a ``PublicKey``, discussed later). Exposes the owner and a function - for replacing the owner e.g. when an asset is sold. + ``OwnableState`` + A state which has an owner (represented as a ``CompositeKey``, discussed later). Exposes the owner and a function + for replacing the owner e.g. when an asset is sold. - ``LinearState`` - A state which links back to its previous state, creating a thread of states over time. A linear state is - useful when modelling an indivisible/non-fungible thing like a specific deal, or an asset that can't be - split (like a rare piece of art). - - ``DealState`` - A LinearState representing an agreement between two or more parties. Intended to simplify implementing generic - flows that manipulate many agreement types. - - ``FixableDealState`` - A deal state, with further functions exposed to support fixing of interest rates. + ``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. NamedByHash and UniqueIdentifier -------------------------------- @@ -81,30 +38,27 @@ 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. -FungibleAssets and Cash ------------------------ - -There is a common ``FungibleAsset`` superclass for contracts which model fungible assets, which also provides a standard -interface for its subclasses' state objects to implement. The clear use-case is ``Cash``, however ``FungibleAsset`` is -intended to be readily extensible to cover other assets, for example commodities could be modelled by using a subclass -whose state objects include further details (location of the commodity, origin, grade, etc.) as needed. Transaction lifecycle types --------------------------- The ``WireTransaction`` class contains the core of a transaction without signatures, and with references to attachments -in place of the attachments themselves (see also :doc:`data-model`). Once signed these are encapsulated in the -``SignedTransaction`` class. For processing a transaction (i.e. to verify it) it is first converted to a +in place of the attachments themselves (see also :doc:`key-concepts-data-model`). Once signed these are encapsulated in the +``SignedTransaction`` class. 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 contracts be run, and thus could be contract-invalid - (but not signature-invalid). You can use the ``verify`` method as shown below to run the contracts. +.. 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 modification of the internals is complete. It is typical for contract classes to expose helper -methods that can contribute to a ``TransactionBuilder``. +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, this class can be used as a holding bucket to gather signatures from multiple parties. +It is typical for contract classes to expose helper methods that can contribute to a ``TransactionBuilder``. Once a transaction +has been constructed using the builders ``toWireTransaction`` or ``toSignedTransaction`` function, it shared with 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): @@ -127,25 +81,22 @@ contract type in the library): 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 PublicKey -------------------- +Party and CompositeKey +---------------------- Entities using the network are called *parties*. Parties can sign structures using keys, and a party may have many keys under their control. -Parties may sometimes be identified pseudonymously, for example, in a transaction sent to your node as part of a +Parties may sometimes be identified pseudonymously. For example, in a transaction sent to your node as part of a chain of custody it is important you can convince yourself of the transaction's validity, but equally important that you don't learn anything about who was involved in that transaction. In these cases a public key may be present without any identifying information about who owns it. -Identities of parties involved in signing a transaction can be represented simply by a ``PublicKey``, or by further +Identities of parties involved in signing a transaction can be represented simply by a ``CompositeKey``, or by further information (such as name) using the ``Party`` class. An ``AuthenticatedObject`` represents an object (like a command) that has been signed by a set of parties. -.. note:: These types are provisional and will change significantly in future as the identity framework becomes more - fleshed out. - -.. _composite-keys: +.. note:: These types are provisional and will change significantly in future as the identity framework becomes more fleshed out. Multi-signature support ----------------------- @@ -153,6 +104,8 @@ Multi-signature support Corda supports scenarios where more than one key or party is required to authorise a state object transition, for example: "Either the CEO or 3 out of 5 of his assistants need to provide signatures". +.. _composite-keys: + Composite Keys ^^^^^^^^^^^^^^ @@ -163,13 +116,15 @@ node specifies a *threshold* of how many child signatures it requires. An illustration of an *"either Alice and Bob, or Charlie"* composite key: .. image:: resources/composite-key.png - :width: 300px + :align: center + :width: 300px To allow further flexibility, each child node can have an associated custom *weight* (the default is 1). The *threshold* then specifies the minimum total weight of all children required. Our previous example can also be expressed as: .. image:: resources/composite-key-2.png - :width: 300px + :align: center + :width: 300px Verification ^^^^^^^^^^^^ @@ -184,7 +139,7 @@ Signature verification is performed in two stages: Date support ------------ -There are a number of supporting interfaces and classes for use by contract which deal with dates (especially in the +There are a number of supporting interfaces and classes for use by contracts which deal with dates (especially in the context of deadlines). As contract negotiation typically deals with deadlines in terms such as "overnight", "T+3", etc., it's desirable to allow conversion of these terms to their equivalent deadline. ``Tenor`` models the interval before a deadline, such as 3 days, etc., while ``DateRollConvention`` describes how deadlines are modified to take @@ -196,11 +151,11 @@ bank holidays). The ``BusinessCalendar`` class models these calendars of busines from files on disk, but in future this is likely to involve reference data oracles in order to ensure consensus on the dates used. -Cryptography & maths support ----------------------------- +Cryptography and maths support +------------------------------ The ``SecureHash`` class represents a secure hash of unknown algorithm. We currently define only a single subclass, ``SecureHash.SHA256``. There are utility methods to create them, parse them and so on. We also provide some mathematical utilities, in particular a set of interpolators and classes for working with -splines. These can be found in the `maths package `_. +splines. These can be found in the `maths package `_. diff --git a/docs/source/key-concepts-data-model.rst b/docs/source/key-concepts-data-model.rst new file mode 100644 index 0000000000..43d43c7cd6 --- /dev/null +++ b/docs/source/key-concepts-data-model.rst @@ -0,0 +1,142 @@ +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 +------------ +Transaction 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 new file mode 100644 index 0000000000..5c4df45442 --- /dev/null +++ b/docs/source/key-concepts-ecosystem.rst @@ -0,0 +1,47 @@ +Corda ecosystem +=============== + +A Corda network consists of the following components: + +* 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. + +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 diff --git a/docs/source/key-concepts-financial-model.rst b/docs/source/key-concepts-financial-model.rst new file mode 100644 index 0000000000..ca35a0cd64 --- /dev/null +++ b/docs/source/key-concepts-financial-model.rst @@ -0,0 +1,71 @@ +Financial model +=============== + +Corda provides a large standard library of data types used in financial applications and contract state objects. +These provide a common language for states and contracts. + +Amount +------ + +The `Amount `_ class is used to represent an amount of some +fungible asset. It is a generic class which wraps around a type used to define the underlying product, called +the *token*. For instance it can be the standard JDK type ``Currency``, or an ``Issued`` instance, or this can be +a more complex type such as an obligation contract issuance definition (which in turn contains a token definition +for whatever the obligation is to be settled in). + +.. note:: Fungible is used here to mean that instances of an asset is interchangeable for any other identical instance, + and that they can be split/merged. For example a £5 note can reasonably be exchanged for any other £5 note, and + a £10 note can be exchanged for two £5 notes, or vice-versa. + +Here are some examples: + +.. container:: codeset + + .. sourcecode:: kotlin + + // A quantity of some specific currency like pounds, euros, dollars etc. + Amount + // A quantity of currency that is issued by a specific issuer, for instance central bank vs other bank dollars + Amount> + // A quantity of a product governed by specific obligation terms + Amount> + +``Amount`` represents quantities as integers. For currencies the quantity represents pennies, cents or whatever +else the smallest integer amount for that currency is. You cannot use ``Amount`` to represent negative quantities +or fractional quantities: if you wish to do this then you must use a different type e.g. ``BigDecimal``. ``Amount`` +defines methods to do addition and subtraction and these methods verify that the tokens on both sides of the operator +are equal (these are operator overloads in Kotlin and can be used as regular methods from Java). There are also +methods to do multiplication and division by integer amounts. + +``Issued`` refers to a product (which can be cash, a cash-like thing, assets, or generally anything else that's +quantifiable with integer quantities) and an associated ``PartyAndReference`` that describes the issuer of that contract. +An issued product typically follows a lifecycle which includes issuance, movement and exiting from the ledger (for example, +see the ``Cash`` contract and its associated *state* and *commands*) + +Financial states +---------------- +In additional to the common state types, a number of interfaces extend ``ContractState`` to model financial state such as: + + ``LinearState`` + A state which has a unique identifier beyond its StateRef and carries it through state transitions. + Such a state cannot be duplicated, merged or split in a transaction: only continued or deleted. A linear state is + useful when modelling an indivisible/non-fungible thing like a specific deal, or an asset that can't be + split (like a rare piece of art). + + ``DealState`` + A LinearState representing an agreement between two or more parties. Intended to simplify implementing generic + protocols that manipulate many agreement types. + + ``FungibleAsset`` + A FungibleAsset is intended to be used for contract states representing assets which are fungible, countable and issued by a + specific party. States contain assets which are equivalent (such as cash of the same currency), so records of their existence + can be merged or split as needed where the issuer is the same. For instance, dollars issued by the Fed are fungible and + countable (in cents), barrels of West Texas crude are fungible and countable (oil from two small containers can be poured into one large + container), shares of the same class in a specific company are fungible and countable, and so on. + +The following diagram illustrates the complete Contract State hierarchy: + +.. image:: resources/financialContractStateModel.png + +Note there are currently two packages, a core library and a finance model specific library. +Developers may re-use or extend the Finance types directly or write their own by extending the base types from the Core library. diff --git a/docs/source/key-concepts-flow-framework.rst b/docs/source/key-concepts-flow-framework.rst new file mode 100644 index 0000000000..81d744e7d3 --- /dev/null +++ b/docs/source/key-concepts-flow-framework.rst @@ -0,0 +1,37 @@ + +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-security-model.rst b/docs/source/key-concepts-security-model.rst new file mode 100644 index 0000000000..f4d8076906 --- /dev/null +++ b/docs/source/key-concepts-security-model.rst @@ -0,0 +1,46 @@ +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:: Future notary algorithms may include BFT and hardware assisted non-BFT algorithms (where non-BFT algorithms + are converted into a more trusted form using remote attestation and hardware protection). + +* 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. + This is subject to design review with views to selecting a proven, mature entitlements solution. + +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-vault.rst b/docs/source/key-concepts-vault.rst new file mode 100644 index 0000000000..19d1ca811e --- /dev/null +++ b/docs/source/key-concepts-vault.rst @@ -0,0 +1,52 @@ +Vault +===== + +The vault contains data extracted from the ledger that is considered relevant to the node’s owner, stored in a relational model +that can be easily queried and worked with. + +The vault keeps track of both unconsumed and consumed states: + + * Unconsumed (or unspent) states represent fungible states available for spending (including spend-to-self transactions) + and linear states available for evolution (eg. in response to a lifecycle event on a deal) or transfer to another party. + * Consumed (or spent) states represent ledger immutable state for the purpose of transaction reporting, audit and archival, including the ability to perform joins with app-private data (like customer notes) + +By fungible we refer to assets of measurable quantity (eg. a cash currency, units of stock) which can be combined +together to represent a single ledger state. + +Like with a cryptocurrency wallet, the Corda vault can create transactions that send value (eg. transfer of state) to someone else +by combining fungible states and possibly adding a change output that makes the values balance (this process is usually referred to as ‘coin selection’). +Vault spending ensures that transactions respect the fungibility rules in order to ensure that the issuer and reference data is preserved as the assets pass from hand to hand. + +.. note:: Basic 'coin selection' is currently implemented. Future work includes fungible state optimisation (splitting and + merging of states in the background), 'soft locking' (ability to automatically or explicitly reserve states to prevent + multiple transactions trying to use the same output simultaneously), 'state re-issuance' (sending of states back to the + issuer for re-issuance, thus pruning long transaction chains and improving privacy). + +There is also a facility for attaching descriptive textual notes against any transaction stored in the vault. + +The vault supports the management of data in both authoritative ("on-ledger") form and, where appropriate, shadow ("off-ledger") form: + +* "On-ledger" data refers to distributed ledger state (cash, deals, trades) to which a firm is participant. +* "Off-ledger" data refers to a firm's internal reference, static and systems data. + +The following diagram illustrates the breakdown of the vault into sub-system components: + +.. image:: resources/vault.png + +Note the following: + +* the vault "On Ledger" store tracks unconsumed state and is updated internally by the node upon recording of a transaction on the ledger + (following successful smart contract verification and signature by all participants) +* the vault "Off Ledger" store refers to additional data added by the node owner subsequent to transaction recording +* the vault performs fungible state spending (and in future, fungible state optimisation management including merging, splitting and re-issuance) +* vault extensions represent additional custom plugin code a developer may write to query specific custom contract state attributes. +* customer "Off Ledger" (private store) represents internal organisational data that may be joined with the vault data to perform additional reporting or processing +* a vault query API is exposed to developers using standard Corda RPC and CorDapp plugin mechanisms +* a vault update API is internally used by transaction recording flows. +* the vault database schemas are directly accessible via JDBC for customer joins and queries + +Section 8 of the `Technical white paper`_ describes features of the vault yet to be implemented including private key managament, +soft state locking, state splitting and merging, asset re-issuance and node event scheduling. + +.. _`Technical white paper`: _static/corda-technical-whitepaper.pdf + diff --git a/docs/source/key-concepts.rst b/docs/source/key-concepts.rst new file mode 100644 index 0000000000..f2675129d4 --- /dev/null +++ b/docs/source/key-concepts.rst @@ -0,0 +1,21 @@ +Overview +======== + +This section describes the fundamental concepts and features that underpin the Corda platform, to include: + + * :doc:`key-concepts-ecosystem` + * :doc:`key-concepts-data-model` + * :doc:`key-concepts-core-types` + * :doc:`key-concepts-financial-model` + * :doc:`key-concepts-flow-framework` + * :doc:`key-concepts-consensus-notaries` + * :doc:`key-concepts-vault` + * :doc:`key-concepts-security-model` + +Detailed thinking and rationale behind these concepts are presented in the following published white papers: + + * `Corda: An Introduction`_ + * `Corda: A Distributed Ledger`_ (Technical White Paper) + +.. _`Corda: An Introduction`: _static/corda-introductory-whitepaper.pdf +.. _`Corda: A Distributed Ledger`: _static/corda-technical-whitepaper.pdf diff --git a/docs/source/network-simulator.png b/docs/source/network-simulator.png index 3706064338..b87420e504 100644 Binary files a/docs/source/network-simulator.png and b/docs/source/network-simulator.png differ diff --git a/docs/source/node-administration.rst b/docs/source/node-administration.rst index aa5f61a233..04aea26784 100644 --- a/docs/source/node-administration.rst +++ b/docs/source/node-administration.rst @@ -1,8 +1,9 @@ Node administration =================== -When a node is running, it exposes an embedded database server, an embedded web server that lets you monitor it, -you can upload and download attachments, access a REST API and so on. +When a node is running, it exposes an RPC interface that lets you monitor it, +you can upload and download attachments, access a REST API and so on. A bundled +Jetty web server exposes the same interface over HTTP. Logging ------- diff --git a/docs/source/node-services.rst b/docs/source/node-services.rst index 6fded8143a..c08e17ddda 100644 --- a/docs/source/node-services.rst +++ b/docs/source/node-services.rst @@ -346,3 +346,11 @@ external legacy systems by insertion of unpacked data into existing tables. To enable these features the contract state must implement the ``QueryableState`` interface to define the mappings. +Node Web Server +--------------- + +A web server comes bundled with the node by default, but is not started +automatically. This web server exposes both RPC backed API calls and +static content serving. The web server is not automatically started, +you must explicitly start it in the node driver or define a web port +in your `Cordformation`_ configuration. diff --git a/docs/source/release-notes.rst b/docs/source/release-notes.rst index 245b0afdef..5d2d25e9e7 100644 --- a/docs/source/release-notes.rst +++ b/docs/source/release-notes.rst @@ -3,6 +3,14 @@ Release notes Here are brief summaries of what's changed between each snapshot release. +Milestone 8 +----------- + +* API: + + * ``Party`` equality is now based on the owning key, rather than the owning key and name. This is important for + party anonymisation to work, as each key must identify exactly one party. + Milestone 7 ----------- diff --git a/docs/source/resources/contract.png b/docs/source/resources/contract.png new file mode 100644 index 0000000000..de151044d6 Binary files /dev/null and b/docs/source/resources/contract.png differ diff --git a/docs/source/resources/cordaNetwork.png b/docs/source/resources/cordaNetwork.png new file mode 100644 index 0000000000..907a0172ba Binary files /dev/null and b/docs/source/resources/cordaNetwork.png differ diff --git a/docs/source/resources/financialContractStateModel.png b/docs/source/resources/financialContractStateModel.png new file mode 100644 index 0000000000..6c5a275580 Binary files /dev/null and b/docs/source/resources/financialContractStateModel.png differ diff --git a/docs/source/resources/flowFramework.png b/docs/source/resources/flowFramework.png new file mode 100644 index 0000000000..639658506a Binary files /dev/null and b/docs/source/resources/flowFramework.png differ diff --git a/docs/source/resources/vault.png b/docs/source/resources/vault.png new file mode 100644 index 0000000000..608906712a Binary files /dev/null and b/docs/source/resources/vault.png differ diff --git a/docs/source/running-the-demos.rst b/docs/source/running-the-demos.rst index 5744dbc00e..73d6124a98 100644 --- a/docs/source/running-the-demos.rst +++ b/docs/source/running-the-demos.rst @@ -21,6 +21,8 @@ extend the demos. For more details about running via the command line or from wi .. note:: If any of the demos don't work, please raise an issue on GitHub. +.. _trader-demo: + Trader demo ----------- @@ -55,6 +57,8 @@ To run from IntelliJ: 5. In the "Trader Demo: Run Nodes" run configuration window, you should see some log lines scroll past. Within a few seconds, the message "Purchase complete - we are a happy customer!" should be printed. +.. _irs-demo: + IRS demo -------- @@ -260,6 +264,8 @@ Using the following login details: See https://docs.corda.net/node-explorer.html for further details on usage. +.. _simm-demo: + SIMM and Portfolio Demo - aka the Initial Margin Agreement Demo --------------------------------------------------------------- diff --git a/docs/source/setting-up-a-corda-network.rst b/docs/source/setting-up-a-corda-network.rst index 657b4b2e49..f45bd6b7ca 100644 --- a/docs/source/setting-up-a-corda-network.rst +++ b/docs/source/setting-up-a-corda-network.rst @@ -45,7 +45,8 @@ The most important fields regarding network configuration are: * ``artemisAddress``: This specifies a host and port. Note that the address bound will **NOT** be ``my-corda-node``, but rather ``::`` (all addresses on all interfaces). The hostname specified is the hostname *that must be externally resolvable by other nodes in the network*. In the above configuration this is the resolvable name of a machine in a vpn. -* ``webAddress``: The address the webserver should bind. Note that the port should be distinct from that of ``artemisAddress``. +* ``webAddress``: The address the webserver should bind. Note that the port should be distinct from that of ``artemisAddress`` + if they are on the same machine. * ``networkMapService``: Details of the node running the network map service. If it's this node that's running the service then this field must not be specified. diff --git a/finance/src/main/kotlin/net/corda/contracts/asset/OnLedgerAsset.kt b/finance/src/main/kotlin/net/corda/contracts/asset/OnLedgerAsset.kt index ad0637fb8c..1aa5c96ffb 100644 --- a/finance/src/main/kotlin/net/corda/contracts/asset/OnLedgerAsset.kt +++ b/finance/src/main/kotlin/net/corda/contracts/asset/OnLedgerAsset.kt @@ -38,13 +38,18 @@ abstract class OnLedgerAsset> : C * the responsibility of the caller to check that they do not exit funds held by others. * @return the public key of the assets issuer, who must sign the transaction for it to be valid. */ + @Throws(InsufficientBalanceException::class) fun generateExit(tx: TransactionBuilder, amountIssued: Amount>, - assetStates: List>): CompositeKey - = conserveClause.generateExit(tx, amountIssued, assetStates, - deriveState = { state, amount, owner -> deriveState(state, amount, owner) }, - generateMoveCommand = { -> generateMoveCommand() }, - generateExitCommand = { amount -> generateExitCommand(amount) } - ) + assetStates: List>): CompositeKey { + return conserveClause.generateExit( + tx, + amountIssued, + assetStates, + deriveState = { state, amount, owner -> deriveState(state, amount, owner) }, + generateMoveCommand = { -> generateMoveCommand() }, + generateExitCommand = { amount -> generateExitCommand(amount) } + ) + } abstract fun generateExitCommand(amount: Amount>): FungibleAsset.Commands.Exit abstract fun generateIssueCommand(): FungibleAsset.Commands.Issue diff --git a/finance/src/main/kotlin/net/corda/contracts/clause/AbstractConserveAmount.kt b/finance/src/main/kotlin/net/corda/contracts/clause/AbstractConserveAmount.kt index 86bd76c73d..d636ccd1e3 100644 --- a/finance/src/main/kotlin/net/corda/contracts/clause/AbstractConserveAmount.kt +++ b/finance/src/main/kotlin/net/corda/contracts/clause/AbstractConserveAmount.kt @@ -45,6 +45,7 @@ abstract class AbstractConserveAmount, C : CommandData, T : * the responsibility of the caller to check that they do not attempt to exit funds held by others. * @return the public key of the assets issuer, who must sign the transaction for it to be valid. */ + @Throws(InsufficientBalanceException::class) fun generateExit(tx: TransactionBuilder, amountIssued: Amount>, assetStates: List>, deriveState: (TransactionState, Amount>, CompositeKey) -> TransactionState, diff --git a/finance/src/main/kotlin/net/corda/flows/CashFlow.kt b/finance/src/main/kotlin/net/corda/flows/CashFlow.kt index 8ac1520f0b..5214ff907c 100644 --- a/finance/src/main/kotlin/net/corda/flows/CashFlow.kt +++ b/finance/src/main/kotlin/net/corda/flows/CashFlow.kt @@ -6,8 +6,8 @@ import net.corda.core.contracts.* import net.corda.core.crypto.Party import net.corda.core.crypto.keys import net.corda.core.crypto.toStringShort +import net.corda.core.flows.FlowException import net.corda.core.flows.FlowLogic -import net.corda.core.flows.StateMachineRunId import net.corda.core.serialization.OpaqueBytes import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.TransactionBuilder @@ -20,7 +20,7 @@ import java.util.* * * @param command Indicates what Cash transaction to create with what parameters. */ -class CashFlow(val command: CashCommand, override val progressTracker: ProgressTracker) : FlowLogic() { +class CashFlow(val command: CashCommand, override val progressTracker: ProgressTracker) : FlowLogic() { constructor(command: CashCommand) : this(command, tracker()) companion object { @@ -32,7 +32,8 @@ class CashFlow(val command: CashCommand, override val progressTracker: ProgressT } @Suspendable - override fun call(): CashFlowResult { + @Throws(CashException::class) + override fun call(): SignedTransaction { return when (command) { is CashCommand.IssueCash -> issueCash(command) is CashCommand.PayCash -> initiatePayment(command) @@ -42,84 +43,90 @@ class CashFlow(val command: CashCommand, override val progressTracker: ProgressT // TODO check with the recipient if they want to accept the cash. @Suspendable - private fun initiatePayment(req: CashCommand.PayCash): CashFlowResult { + private fun initiatePayment(req: CashCommand.PayCash): SignedTransaction { progressTracker.currentStep = PAYING val builder: TransactionBuilder = TransactionType.General.Builder(null) // TODO: Have some way of restricting this to states the caller controls - try { - val (spendTX, keysForSigning) = serviceHub.vaultService.generateSpend(builder, - req.amount.withoutIssuer(), req.recipient.owningKey, setOf(req.amount.token.issuer.party)) - - keysForSigning.keys.forEach { - val key = serviceHub.keyManagementService.keys[it] ?: throw IllegalStateException("Could not find signing key for ${it.toStringShort()}") - builder.signWith(KeyPair(it, key)) - } - - val tx = spendTX.toSignedTransaction(checkSufficientSignatures = false) - val flow = FinalityFlow(tx, setOf(req.recipient)) - subFlow(flow) - return CashFlowResult.Success( - stateMachine.id, - tx, - "Cash payment transaction generated" - ) - } catch(ex: InsufficientBalanceException) { - return CashFlowResult.Failed(ex.message ?: "Insufficient balance") + val (spendTX, keysForSigning) = try { + serviceHub.vaultService.generateSpend( + builder, + req.amount.withoutIssuer(), + req.recipient.owningKey, + setOf(req.amount.token.issuer.party)) + } catch (e: InsufficientBalanceException) { + throw CashException("Insufficent cash for spend", e) } + + keysForSigning.keys.forEach { + val key = serviceHub.keyManagementService.keys[it] ?: throw IllegalStateException("Could not find signing key for ${it.toStringShort()}") + builder.signWith(KeyPair(it, key)) + } + + val tx = spendTX.toSignedTransaction(checkSufficientSignatures = false) + finaliseTx(setOf(req.recipient), tx, "Unable to notarise spend") + return tx } @Suspendable - private fun exitCash(req: CashCommand.ExitCash): CashFlowResult { + private fun exitCash(req: CashCommand.ExitCash): SignedTransaction { progressTracker.currentStep = EXITING val builder: TransactionBuilder = TransactionType.General.Builder(null) + val issuer = serviceHub.myInfo.legalIdentity.ref(req.issueRef) try { - val issuer = PartyAndReference(serviceHub.myInfo.legalIdentity, req.issueRef) - Cash().generateExit(builder, req.amount.issuedBy(issuer), + Cash().generateExit( + builder, + req.amount.issuedBy(issuer), serviceHub.vaultService.currentVault.statesOfType().filter { it.state.data.owner == issuer.party.owningKey }) - val myKey = serviceHub.legalIdentityKey - builder.signWith(myKey) - - // Work out who the owners of the burnt states were - val inputStatesNullable = serviceHub.vaultService.statesForRefs(builder.inputStates()) - val inputStates = inputStatesNullable.values.filterNotNull().map { it.data } - if (inputStatesNullable.size != inputStates.size) { - val unresolvedStateRefs = inputStatesNullable.filter { it.value == null }.map { it.key } - throw InputStateRefResolveFailed(unresolvedStateRefs) - } - - // TODO: Is it safe to drop participants we don't know how to contact? Does not knowing how to contact them - // count as a reason to fail? - val participants: Set = inputStates.filterIsInstance().map { serviceHub.identityService.partyFromKey(it.owner) }.filterNotNull().toSet() - - // Commit the transaction - val tx = builder.toSignedTransaction(checkSufficientSignatures = false) - subFlow(FinalityFlow(tx, participants)) - return CashFlowResult.Success( - stateMachine.id, - tx, - "Cash destruction transaction generated" - ) - } catch (ex: InsufficientBalanceException) { - return CashFlowResult.Failed(ex.message ?: "Insufficient balance") + } catch (e: InsufficientBalanceException) { + throw CashException("Exiting more cash than exists", e) } + val myKey = serviceHub.legalIdentityKey + builder.signWith(myKey) + + // Work out who the owners of the burnt states were + val inputStatesNullable = serviceHub.vaultService.statesForRefs(builder.inputStates()) + val inputStates = inputStatesNullable.values.filterNotNull().map { it.data } + if (inputStatesNullable.size != inputStates.size) { + val unresolvedStateRefs = inputStatesNullable.filter { it.value == null }.map { it.key } + throw IllegalStateException("Failed to resolve input StateRefs: $unresolvedStateRefs") + } + + // TODO: Is it safe to drop participants we don't know how to contact? Does not knowing how to contact them + // count as a reason to fail? + val participants: Set = inputStates + .filterIsInstance() + .map { serviceHub.identityService.partyFromKey(it.owner) } + .filterNotNull() + .toSet() + + // Commit the transaction + val tx = builder.toSignedTransaction(checkSufficientSignatures = false) + finaliseTx(participants, tx, "Unable to notarise exit") + return tx } @Suspendable - private fun issueCash(req: CashCommand.IssueCash): CashFlowResult { + private fun finaliseTx(participants: Set, tx: SignedTransaction, message: String) { + try { + subFlow(FinalityFlow(tx, participants)) + } catch (e: NotaryException) { + throw CashException(message, e) + } + } + + // TODO This doesn't throw any exception so it might be worth splitting the three cash commands into separate flows + @Suspendable + private fun issueCash(req: CashCommand.IssueCash): SignedTransaction { progressTracker.currentStep = ISSUING val builder: TransactionBuilder = TransactionType.General.Builder(notary = null) - val issuer = PartyAndReference(serviceHub.myInfo.legalIdentity, req.issueRef) + val issuer = serviceHub.myInfo.legalIdentity.ref(req.issueRef) Cash().generateIssue(builder, req.amount.issuedBy(issuer), req.recipient.owningKey, req.notary) val myKey = serviceHub.legalIdentityKey builder.signWith(myKey) val tx = builder.toSignedTransaction(checkSufficientSignatures = true) // Issuance transactions do not need to be notarised, so we can skip directly to broadcasting it subFlow(BroadcastTransactionFlow(tx, setOf(req.recipient))) - return CashFlowResult.Success( - stateMachine.id, - tx, - "Cash issuance completed" - ) + return tx } } @@ -158,22 +165,4 @@ sealed class CashCommand { class ExitCash(val amount: Amount, val issueRef: OpaqueBytes) : CashCommand() } -sealed class CashFlowResult { - /** - * @param transaction the transaction created as a result, in the case where the flow completed successfully. - */ - class Success(val id: StateMachineRunId, val transaction: SignedTransaction?, val message: String?) : CashFlowResult() { - override fun toString() = "Success($message)" - } - - /** - * State indicating the action undertaken failed, either directly (it is not something which requires a - * state machine), or before a state machine was started. - */ - class Failed(val message: String?) : CashFlowResult() { - override fun toString() = "Failed($message)" - } -} - -class InputStateRefResolveFailed(stateRefs: List) : - Exception("Failed to resolve input StateRefs $stateRefs") +class CashException(message: String, cause: Throwable) : FlowException(message, cause) diff --git a/finance/src/main/kotlin/net/corda/flows/IssuerFlow.kt b/finance/src/main/kotlin/net/corda/flows/IssuerFlow.kt index 2e413fdcd8..ff946f0fa4 100644 --- a/finance/src/main/kotlin/net/corda/flows/IssuerFlow.kt +++ b/finance/src/main/kotlin/net/corda/flows/IssuerFlow.kt @@ -1,19 +1,14 @@ package net.corda.flows import co.paralleluniverse.fibers.Suspendable -import net.corda.core.ThreadBox import net.corda.core.contracts.* import net.corda.core.crypto.Party -import net.corda.core.crypto.SecureHash +import net.corda.core.flows.FlowException import net.corda.core.flows.FlowLogic -import net.corda.core.node.NodeInfo import net.corda.core.node.PluginServiceHub import net.corda.core.serialization.OpaqueBytes import net.corda.core.transactions.SignedTransaction import net.corda.core.utilities.ProgressTracker -import net.corda.flows.CashCommand -import net.corda.flows.CashFlow -import net.corda.flows.CashFlowResult import java.util.* /** @@ -27,22 +22,16 @@ object IssuerFlow { data class IssuanceRequestState(val amount: Amount, val issueToParty: Party, val issuerPartyRef: OpaqueBytes) /** - * IssuanceRequester should be used by a client to ask a remote note to issue some [FungibleAsset] with the given details. + * IssuanceRequester should be used by a client to ask a remote node to issue some [FungibleAsset] with the given details. * Returns the transaction created by the Issuer to move the cash to the Requester. */ class IssuanceRequester(val amount: Amount, val issueToParty: Party, val issueToPartyRef: OpaqueBytes, val issuerBankParty: Party): FlowLogic() { @Suspendable + @Throws(CashException::class) override fun call(): SignedTransaction { val issueRequest = IssuanceRequestState(amount, issueToParty, issueToPartyRef) - try { - return sendAndReceive(issuerBankParty, issueRequest).unwrap { it } - // catch and report exception before throwing back to caller - } catch (e: Exception) { - logger.error("IssuanceRequesterException: request failed: [${issueRequest}]") - // TODO: awaiting exception handling strategy (what action should be taken here?) - throw e - } + return sendAndReceive(issuerBankParty, issueRequest).unwrap { it } } } @@ -51,22 +40,25 @@ object IssuerFlow { * Returns the generated transaction representing the transfer of the [Issued] [FungibleAsset] to the issue requester. */ class Issuer(val otherParty: Party): FlowLogic() { - override val progressTracker: ProgressTracker = tracker() companion object { object AWAITING_REQUEST : ProgressTracker.Step("Awaiting issuance request") object ISSUING : ProgressTracker.Step("Self issuing asset") object TRANSFERRING : ProgressTracker.Step("Transferring asset to issuance requester") object SENDING_CONFIRM : ProgressTracker.Step("Confirming asset issuance to requester") fun tracker() = ProgressTracker(AWAITING_REQUEST, ISSUING, TRANSFERRING, SENDING_CONFIRM) + private val VALID_CURRENCIES = listOf(USD, GBP, EUR, CHF) } + override val progressTracker: ProgressTracker = tracker() + @Suspendable + @Throws(CashException::class) override fun call(): SignedTransaction { progressTracker.currentStep = AWAITING_REQUEST - val issueRequest = receive(otherParty).unwrap { it } - // validate request inputs (for example, lets restrict the types of currency that can be issued) - require(listOf(USD, GBP, EUR, CHF).contains(issueRequest.amount.token)) { - logger.error("Currency must be one of USD, GBP, EUR, CHF") + val issueRequest = receive(otherParty).unwrap { + // validate request inputs (for example, lets restrict the types of currency that can be issued) + if (it.amount.token !in VALID_CURRENCIES) throw FlowException("Currency must be one of $VALID_CURRENCIES") + it } // TODO: parse request to determine Asset to issue val txn = issueCashTo(issueRequest.amount, issueRequest.issueToParty, issueRequest.issuerPartyRef) @@ -79,52 +71,30 @@ object IssuerFlow { // state references (thus causing Notarisation double spend exceptions). @Suspendable private fun issueCashTo(amount: Amount, - issueTo: Party, issuerPartyRef: OpaqueBytes): SignedTransaction { + issueTo: Party, + issuerPartyRef: OpaqueBytes): SignedTransaction { // TODO: pass notary in as request parameter val notaryParty = serviceHub.networkMapCache.notaryNodes[0].notaryIdentity // invoke Cash subflow to issue Asset progressTracker.currentStep = ISSUING val bankOfCordaParty = serviceHub.myInfo.legalIdentity - try { - val issueCashFlow = CashFlow(CashCommand.IssueCash(amount, issuerPartyRef, bankOfCordaParty, notaryParty)) - val resultIssue = subFlow(issueCashFlow) - // NOTE: issueCashFlow performs a Broadcast (which stores a local copy of the txn to the ledger) - if (resultIssue is CashFlowResult.Failed) { - logger.error("Problem issuing cash: ${resultIssue.message}") - throw Exception(resultIssue.message) - } - // short-circuit when issuing to self - if (issueTo.equals(serviceHub.myInfo.legalIdentity)) - return (resultIssue as CashFlowResult.Success).transaction!! - // now invoke Cash subflow to Move issued assetType to issue requester - progressTracker.currentStep = TRANSFERRING - val moveCashFlow = CashFlow(CashCommand.PayCash(amount.issuedBy(bankOfCordaParty.ref(issuerPartyRef)), issueTo)) - val resultMove = subFlow(moveCashFlow) - // NOTE: CashFlow PayCash calls FinalityFlow which performs a Broadcast (which stores a local copy of the txn to the ledger) - if (resultMove is CashFlowResult.Failed) { - logger.error("Problem transferring cash: ${resultMove.message}") - throw Exception(resultMove.message) - } - val txn = (resultMove as CashFlowResult.Success).transaction - txn?.let { - return txn - } - // NOTE: CashFlowResult.Success should always return a signedTransaction - throw Exception("Missing CashFlow transaction [${(resultMove)}]") - } - // catch and report exception before throwing back to caller flow - catch (e: Exception) { - logger.error("Issuer Exception: failed for amount ${amount} issuedTo ${issueTo} with issuerPartyRef ${issuerPartyRef}") - // TODO: awaiting exception handling strategy (what action should be taken here?) - throw e - } + val issueCashFlow = CashFlow(CashCommand.IssueCash(amount, issuerPartyRef, bankOfCordaParty, notaryParty)) + val issueTx = subFlow(issueCashFlow) + // NOTE: issueCashFlow performs a Broadcast (which stores a local copy of the txn to the ledger) + // short-circuit when issuing to self + if (issueTo == serviceHub.myInfo.legalIdentity) + return issueTx + // now invoke Cash subflow to Move issued assetType to issue requester + progressTracker.currentStep = TRANSFERRING + val moveCashFlow = CashFlow(CashCommand.PayCash(amount.issuedBy(bankOfCordaParty.ref(issuerPartyRef)), issueTo)) + val moveTx = subFlow(moveCashFlow) + // 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.registerFlowInitiator(IssuanceRequester::class) { - Issuer(it) - } + services.registerFlowInitiator(IssuanceRequester::class, ::Issuer) } } } diff --git a/finance/src/main/kotlin/net/corda/flows/TwoPartyTradeFlow.kt b/finance/src/main/kotlin/net/corda/flows/TwoPartyTradeFlow.kt index ee5c2808c9..50341d8ded 100644 --- a/finance/src/main/kotlin/net/corda/flows/TwoPartyTradeFlow.kt +++ b/finance/src/main/kotlin/net/corda/flows/TwoPartyTradeFlow.kt @@ -4,6 +4,7 @@ import co.paralleluniverse.fibers.Suspendable import net.corda.contracts.asset.sumCashBy import net.corda.core.contracts.* import net.corda.core.crypto.* +import net.corda.core.flows.FlowException import net.corda.core.flows.FlowLogic import net.corda.core.node.NodeInfo import net.corda.core.seconds @@ -42,8 +43,8 @@ import java.util.* // and [AbstractStateReplacementFlow]. object TwoPartyTradeFlow { - class UnacceptablePriceException(val givenPrice: Amount) : Exception("Unacceptable price: $givenPrice") - class AssetMismatchException(val expectedTypeName: String, val typeName: String) : Exception() { + class UnacceptablePriceException(givenPrice: Amount) : FlowException("Unacceptable price: $givenPrice") + class AssetMismatchException(val expectedTypeName: String, val typeName: String) : FlowException() { override fun toString() = "The submitted asset didn't match the expected type: $expectedTypeName vs $typeName" } @@ -66,39 +67,39 @@ 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 NOTARY : ProgressTracker.Step("Getting notary signature") { override fun childProgressTracker() = FinalityFlow.tracker() } // DOCEND 3 - object SENDING_SIGS : ProgressTracker.Step("Sending transaction signatures to buyer") fun tracker() = ProgressTracker(AWAITING_PROPOSAL, VERIFYING, SIGNING, NOTARY, SENDING_SIGS) } + // DOCSTART 4 @Suspendable override fun call(): SignedTransaction { val partialTX: SignedTransaction = receiveAndCheckProposedTransaction() - - // These two steps could be done in parallel, in theory. Our framework doesn't support that yet though. - val ourSignature = calculateOurSignature(partialTX) - val allPartySignedTx = partialTX + ourSignature - val notarySignature = getNotarySignature(allPartySignedTx) - return sendSignatures(allPartySignedTx, ourSignature, notarySignature) + val ourSignature: DigitalSignature.WithKey = calculateOurSignature(partialTX) + val allPartySignedTx: SignedTransaction = partialTX + ourSignature + val notarySignature: DigitalSignature.WithKey = getNotarySignature(allPartySignedTx) + val result: SignedTransaction = sendSignatures(allPartySignedTx, ourSignature, notarySignature) + return result } + // DOCEND 4 + // DOCSTART 6 @Suspendable private fun getNotarySignature(stx: SignedTransaction): DigitalSignature.WithKey { progressTracker.currentStep = NOTARY return subFlow(NotaryFlow.Client(stx)) } + // DOCEND 6 + // DOCSTART 5 @Suspendable private fun receiveAndCheckProposedTransaction(): SignedTransaction { progressTracker.currentStep = AWAITING_PROPOSAL @@ -122,30 +123,36 @@ object TwoPartyTradeFlow { // even though it is missing signatures. subFlow(ResolveTransactionsFlow(wtx, otherParty)) - if (wtx.outputs.map { it.data }.sumCashBy(myPublicKey).withoutIssuer() != price) - throw IllegalArgumentException("Transaction is not sending us the right amount of cash") - - // There are all sorts of funny games a malicious secondary might play here, 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! - // - This tx may include output states that impose odd conditions on the movement of the cash, - // once we implement state pairing. - // - // 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. + if (wtx.outputs.map { it.data }.sumCashBy(myPublicKey).withoutIssuer() != price) { + throw FlowException("Transaction is not sending us the right amount of cash") + } return it } } + // DOCEND 5 + // 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: + // + // - 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! + // - This tx may include output states that impose odd conditions on the movement of the cash, + // once we implement state pairing. + // + // 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. + + // DOCSTART 7 open fun calculateOurSignature(partialTX: SignedTransaction): DigitalSignature.WithKey { progressTracker.currentStep = SIGNING return myKeyPair.signWithECDSA(partialTX.id) } @Suspendable - private fun sendSignatures(allPartySignedTx: SignedTransaction, ourSignature: DigitalSignature.WithKey, + private fun sendSignatures(allPartySignedTx: SignedTransaction, + ourSignature: DigitalSignature.WithKey, notarySignature: DigitalSignature.WithKey): SignedTransaction { progressTracker.currentStep = SENDING_SIGS val fullySigned = allPartySignedTx + notarySignature @@ -155,6 +162,7 @@ object TwoPartyTradeFlow { send(otherParty, SignaturesFromSeller(ourSignature, notarySignature)) return fullySigned } + // DOCEND 7 } // DOCSTART 2 @@ -164,11 +172,8 @@ object TwoPartyTradeFlow { val typeToBuy: Class) : FlowLogic() { 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 SWAPPING_SIGNATURES : ProgressTracker.Step("Swapping signatures with the seller") override val progressTracker = ProgressTracker(RECEIVING, VERIFYING, SIGNING, SWAPPING_SIGNATURES) diff --git a/finance/src/test/kotlin/net/corda/flows/IssuerFlowTest.kt b/finance/src/test/kotlin/net/corda/flows/IssuerFlowTest.kt index 92efac55b3..7009f6874e 100644 --- a/finance/src/test/kotlin/net/corda/flows/IssuerFlowTest.kt +++ b/finance/src/test/kotlin/net/corda/flows/IssuerFlowTest.kt @@ -5,7 +5,9 @@ import net.corda.core.contracts.Amount import net.corda.core.contracts.DOLLARS import net.corda.core.contracts.PartyAndReference import net.corda.core.contracts.currency +import net.corda.core.flows.FlowException import net.corda.core.flows.FlowStateMachine +import net.corda.core.getOrThrow import net.corda.core.map import net.corda.core.serialization.OpaqueBytes import net.corda.core.transactions.SignedTransaction @@ -29,18 +31,18 @@ class IssuerFlowTest { fun `test issuer flow`() { net = MockNetwork(false, true) ledger { - notaryNode = net.createNotaryNode(null, DUMMY_NOTARY.name, DUMMY_NOTARY_KEY) - bankOfCordaNode = net.createPartyNode(notaryNode.info.address, BOC.name, BOC_KEY) - bankClientNode = net.createPartyNode(notaryNode.info.address, MEGA_CORP.name, MEGA_CORP_KEY) + notaryNode = net.createNotaryNode(null, DUMMY_NOTARY.name) + bankOfCordaNode = net.createPartyNode(notaryNode.info.address, BOC.name) + bankClientNode = net.createPartyNode(notaryNode.info.address, MEGA_CORP.name) // using default IssueTo Party Reference - val issueToPartyAndRef = MEGA_CORP.ref(OpaqueBytes.Companion.of(123)) + val issueToPartyAndRef = bankClientNode.info.legalIdentity.ref(OpaqueBytes.Companion.of(123)) val (issuer, issuerResult) = runIssuerAndIssueRequester(1000000.DOLLARS, issueToPartyAndRef) assertEquals(issuerResult.get(), issuer.get().resultFuture.get()) // try to issue an amount of a restricted currency - assertFailsWith { - runIssuerAndIssueRequester(Amount(100000L, currency("BRL")), issueToPartyAndRef).issueRequestResult.get() + assertFailsWith { + runIssuerAndIssueRequester(Amount(100000L, currency("BRL")), issueToPartyAndRef).issueRequestResult.getOrThrow() } bankOfCordaNode.stop() diff --git a/gradle-plugins/cordformation/src/main/resources/net/corda/plugins/runnodes b/gradle-plugins/cordformation/src/main/resources/net/corda/plugins/runnodes index 36a47c8599..961d84f91d 100755 --- a/gradle-plugins/cordformation/src/main/resources/net/corda/plugins/runnodes +++ b/gradle-plugins/cordformation/src/main/resources/net/corda/plugins/runnodes @@ -24,6 +24,16 @@ if which osascript >/dev/null; then first=false fi done + for dir in `ls`; do + if [ -d $dir ]; then + cmd="bash -c 'cd $rootdir/$dir; /usr/libexec/java_home -v 1.8 --exec java -jar JAR_NAME --webserver && exit'" + script="$script + tell application \"System Events\" to tell process \"Terminal\" to keystroke \"t\" using command down + delay 0.5 + do script \"$cmd\" in window 1" + first=false + fi + done script="$script end tell" osascript -e "$script" @@ -39,6 +49,7 @@ else if [ -d $dir ]; then pushd $dir >/dev/null xterm -T "`basename $dir`" -e 'java -jar JAR_NAME' & + xterm -T "`basename $dir`" -e 'java -jar JAR_NAME --webserver' & popd >/dev/null fi done diff --git a/gradle-plugins/cordformation/src/main/resources/net/corda/plugins/runnodes.bat b/gradle-plugins/cordformation/src/main/resources/net/corda/plugins/runnodes.bat index 74d13d67f4..e2310ea434 100644 --- a/gradle-plugins/cordformation/src/main/resources/net/corda/plugins/runnodes.bat +++ b/gradle-plugins/cordformation/src/main/resources/net/corda/plugins/runnodes.bat @@ -6,6 +6,7 @@ Pushd %~dp0 FOR /D %%G in (.\*) DO ( Pushd %%G start java -jar corda.jar + start java -jar corda.jar --webserver Popd ) diff --git a/node/build.gradle b/node/build.gradle index 05ecb5ef25..44d5df7cdd 100644 --- a/node/build.gradle +++ b/node/build.gradle @@ -151,6 +151,9 @@ dependencies { compile 'io.atomix.copycat:copycat-server:1.1.4' compile 'io.atomix.catalyst:catalyst-netty:1.1.1' + // OkHTTP: Simple HTTP library. + compile "com.squareup.okhttp3:okhttp:$okhttp_version" + // Integration test helpers integrationTestCompile "junit:junit:$junit_version" diff --git a/node/capsule/build.gradle b/node/capsule/build.gradle index 908e271f2a..039639535e 100644 --- a/node/capsule/build.gradle +++ b/node/capsule/build.gradle @@ -69,6 +69,10 @@ task buildCordaJAR(type: FatCapsule, dependsOn: ['buildCertSigningRequestUtility // If you change these flags, please also update Driver.kt jvmArgs = ['-Xmx200m', '-XX:+UseG1GC'] } + + manifest { + attributes('Corda-Version': corda_version) + } } task buildCertSigningRequestUtilityJAR(type: FatCapsule) { diff --git a/node/src/integration-test/kotlin/net/corda/node/driver/DriverTests.kt b/node/src/integration-test/kotlin/net/corda/node/driver/DriverTests.kt index 7ac9736f9d..abd8330183 100644 --- a/node/src/integration-test/kotlin/net/corda/node/driver/DriverTests.kt +++ b/node/src/integration-test/kotlin/net/corda/node/driver/DriverTests.kt @@ -1,5 +1,6 @@ package net.corda.node.driver +import com.google.common.net.HostAndPort import net.corda.core.getOrThrow import net.corda.core.node.NodeInfo import net.corda.core.node.services.ServiceInfo @@ -25,6 +26,14 @@ class DriverTests { // Check that the port is bound addressMustNotBeBound(executorService, hostAndPort) } + + fun webserverMustBeUp(webserverAddr: HostAndPort) { + addressMustBeBound(executorService, webserverAddr) + } + + fun webserverMustBeDown(webserverAddr: HostAndPort) { + addressMustNotBeBound(executorService, webserverAddr) + } } @Test @@ -60,4 +69,15 @@ class DriverTests { } nodeMustBeDown(nodeInfo.nodeInfo) } + + @Test + fun `starting a node and independent web server works`() { + val addr = driver { + val node = startNode("test").getOrThrow() + val webserverAddr = startWebserver(node).getOrThrow() + webserverMustBeUp(webserverAddr) + webserverAddr + } + webserverMustBeDown(addr) + } } diff --git a/node/src/integration-test/kotlin/net/corda/node/services/DistributedServiceTests.kt b/node/src/integration-test/kotlin/net/corda/node/services/DistributedServiceTests.kt index 2455a0a696..3004eceb21 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/DistributedServiceTests.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/DistributedServiceTests.kt @@ -5,14 +5,15 @@ import net.corda.core.contracts.Amount import net.corda.core.contracts.POUNDS import net.corda.core.contracts.issuedBy import net.corda.core.crypto.Party +import net.corda.core.getOrThrow import net.corda.core.messaging.CordaRPCOps import net.corda.core.messaging.StateMachineUpdate import net.corda.core.messaging.startFlow import net.corda.core.node.NodeInfo import net.corda.core.serialization.OpaqueBytes +import net.corda.core.toFuture import net.corda.flows.CashCommand import net.corda.flows.CashFlow -import net.corda.flows.CashFlowResult import net.corda.node.driver.DriverBasedTest import net.corda.node.driver.NodeHandle import net.corda.node.driver.driver @@ -137,13 +138,13 @@ class DistributedServiceTests : DriverBasedTest() { val issueHandle = aliceProxy.startFlow( ::CashFlow, CashCommand.IssueCash(amount, OpaqueBytes.of(0), alice.nodeInfo.legalIdentity, raftNotaryIdentity)) - require(issueHandle.returnValue.toBlocking().first() is CashFlowResult.Success) + issueHandle.returnValue.toFuture().getOrThrow() } private fun paySelf(amount: Amount) { val payHandle = aliceProxy.startFlow( ::CashFlow, CashCommand.PayCash(amount.issuedBy(alice.nodeInfo.legalIdentity.ref(0)), alice.nodeInfo.legalIdentity)) - require(payHandle.returnValue.toBlocking().first() is CashFlowResult.Success) + payHandle.returnValue.toFuture().getOrThrow() } } \ No newline at end of file diff --git a/node/src/main/kotlin/net/corda/node/ArgsParser.kt b/node/src/main/kotlin/net/corda/node/ArgsParser.kt index 4716bbcc2c..7e3bbb6d79 100644 --- a/node/src/main/kotlin/net/corda/node/ArgsParser.kt +++ b/node/src/main/kotlin/net/corda/node/ArgsParser.kt @@ -21,6 +21,7 @@ class ArgsParser { .withRequiredArg() .defaultsTo("node.conf") private val logToConsoleArg = optionParser.accepts("log-to-console", "If set, prints logging to the console as well as to a file.") + private val isWebserverArg = optionParser.accepts("webserver") private val helpArg = optionParser.accepts("help").forHelp() fun parse(vararg args: String): CmdLineOptions { @@ -30,13 +31,14 @@ class ArgsParser { } val baseDirectory = Paths.get(optionSet.valueOf(baseDirectoryArg)).normalize().toAbsolutePath() val configFile = baseDirectory / optionSet.valueOf(configFileArg) - return CmdLineOptions(baseDirectory, configFile, optionSet.has(helpArg), optionSet.has(logToConsoleArg)) + val isWebserver = optionSet.has(isWebserverArg) + return CmdLineOptions(baseDirectory, configFile, optionSet.has(helpArg), optionSet.has(logToConsoleArg), isWebserver) } fun printHelp(sink: PrintStream) = optionParser.printHelpOn(sink) } -data class CmdLineOptions(val baseDirectory: Path, val configFile: Path?, val help: Boolean, val logToConsole: Boolean) { +data class CmdLineOptions(val baseDirectory: Path, val configFile: Path?, val help: Boolean, val logToConsole: Boolean, val isWebserver: Boolean) { fun loadConfig(allowMissingConfig: Boolean = false, configOverrides: Map = emptyMap()): Config { return ConfigHelper.loadConfig(baseDirectory, configFile, allowMissingConfig, configOverrides) } diff --git a/node/src/main/kotlin/net/corda/node/Corda.kt b/node/src/main/kotlin/net/corda/node/Corda.kt index ca7c9e969a..3afa27ffc1 100644 --- a/node/src/main/kotlin/net/corda/node/Corda.kt +++ b/node/src/main/kotlin/net/corda/node/Corda.kt @@ -7,6 +7,7 @@ import net.corda.core.utilities.Emoji import net.corda.node.internal.Node import net.corda.node.services.config.FullNodeConfiguration import net.corda.node.utilities.ANSIProgressObserver +import net.corda.node.webserver.WebServer import org.fusesource.jansi.Ansi import org.fusesource.jansi.AnsiConsole import org.slf4j.LoggerFactory @@ -57,7 +58,8 @@ fun main(args: Array) { drawBanner() - System.setProperty("log-path", (cmdlineOptions.baseDirectory / "logs").toString()) + val logDir = if (cmdlineOptions.isWebserver) "logs/web" else "logs" + System.setProperty("log-path", (cmdlineOptions.baseDirectory / logDir).toString()) val log = LoggerFactory.getLogger("Main") printBasicNodeInfo("Logs can be found in", System.getProperty("log-path")) @@ -78,33 +80,39 @@ fun main(args: Array) { log.info("VM ${info.vmName} ${info.vmVendor} ${info.vmVersion}") log.info("Machine: ${InetAddress.getLocalHost().hostName}") log.info("Working Directory: ${cmdlineOptions.baseDirectory}") + if(cmdlineOptions.isWebserver) { + log.info("Starting as webserver on ${conf.webAddress}") + } else { + log.info("Starting as node on ${conf.artemisAddress}") + } try { cmdlineOptions.baseDirectory.createDirectories() - val node = conf.createNode() - node.start() - printPluginsAndServices(node) + // TODO: Webserver should be split and start from inside a WAR container + if (!cmdlineOptions.isWebserver) { + val node = conf.createNode() + node.start() + printPluginsAndServices(node) - thread { - Thread.sleep(30.seconds.toMillis()) - while (!node.networkMapRegistrationFuture.isDone) { - printBasicNodeInfo("Waiting for response from network map ...") - Thread.sleep(30.seconds.toMillis()) + node.networkMapRegistrationFuture.success { + val elapsed = (System.currentTimeMillis() - startTime) / 10 / 100.0 + printBasicNodeInfo("Node started up and registered in $elapsed sec") + + if (renderBasicInfoToConsole) + ANSIProgressObserver(node.smm) + } failure { + log.error("Error during network map registration", it) + exitProcess(1) } - } - - node.networkMapRegistrationFuture.success { + node.run() + } else { + val server = WebServer(conf) + server.start() val elapsed = (System.currentTimeMillis() - startTime) / 10 / 100.0 - printBasicNodeInfo("Node started up and registered in $elapsed sec") - - if (renderBasicInfoToConsole) - ANSIProgressObserver(node.smm) - } failure { - log.error("Error during network map registration", it) - exitProcess(1) + printBasicNodeInfo("Webserver started up in $elapsed sec") + server.run() } - node.run() } catch (e: Exception) { log.error("Exception during node startup", e) exitProcess(1) diff --git a/node/src/main/kotlin/net/corda/node/api/APIServer.kt b/node/src/main/kotlin/net/corda/node/api/APIServer.kt deleted file mode 100644 index 95911fe7b7..0000000000 --- a/node/src/main/kotlin/net/corda/node/api/APIServer.kt +++ /dev/null @@ -1,153 +0,0 @@ -package net.corda.node.api - -import net.corda.core.contracts.* -import net.corda.node.api.StatesQuery -import net.corda.core.crypto.DigitalSignature -import net.corda.core.crypto.SecureHash -import net.corda.core.node.NodeInfo -import net.corda.core.serialization.SerializedBytes -import net.corda.core.transactions.SignedTransaction -import net.corda.core.transactions.WireTransaction -import java.time.Instant -import java.time.LocalDateTime -import javax.ws.rs.GET -import javax.ws.rs.Path -import javax.ws.rs.Produces -import javax.ws.rs.core.MediaType -import javax.ws.rs.core.Response - -/** - * Top level interface to external interaction with the distributed ledger. - * - * Wherever a list is returned by a fetchXXX method that corresponds with an input list, that output list will have optional elements - * where a null indicates "missing" and the elements returned will be in the order corresponding with the input list. - * - */ -@Path("") -interface APIServer { - - /** - * Report current UTC time as understood by the platform. - */ - @GET - @Path("servertime") - @Produces(MediaType.APPLICATION_JSON) - fun serverTime(): LocalDateTime - - /** - * Report whether this node is started up or not. - */ - @GET - @Path("status") - @Produces(MediaType.TEXT_PLAIN) - fun status(): Response - - /** - * Report this node's configuration and identities. - * Currently tunnels the NodeInfo as an encoding of the Kryo serialised form. - * TODO this functionality should be available via the RPC - */ - @GET - @Path("info") - @Produces(MediaType.APPLICATION_JSON) - fun info(): NodeInfo - - /** - * Query your "local" states (containing only outputs involving you) and return the hashes & indexes associated with them - * to probably be later inflated by fetchLedgerTransactions() or fetchStates() although because immutable you can cache them - * to avoid calling fetchLedgerTransactions() many times. - * - * @param query Some "where clause" like expression. - * @return Zero or more matching States. - */ - fun queryStates(query: StatesQuery): List - - fun fetchStates(states: List): Map?> - - /** - * Query for immutable transactions (results can be cached indefinitely by their id/hash). - * - * @param txs The hashes (from [StateRef.txhash] returned from [queryStates]) you would like full transactions for. - * @return null values indicate missing transactions from the requested list. - */ - fun fetchTransactions(txs: List): Map - - /** - * TransactionBuildSteps would be invocations of contract.generateXXX() methods that all share a common TransactionBuilder - * and a common contract type (e.g. Cash or CommercialPaper) - * which would automatically be passed as the first argument (we'd need that to be a criteria/pattern of the generateXXX methods). - */ - fun buildTransaction(type: ContractDefRef, steps: List): SerializedBytes - - /** - * Generate a signature for this transaction signed by us. - */ - fun generateTransactionSignature(tx: SerializedBytes): DigitalSignature.WithKey - - /** - * Attempt to commit transaction (returned from build transaction) with the necessary signatures for that to be - * successful, otherwise exception is thrown. - */ - fun commitTransaction(tx: SerializedBytes, signatures: List): SecureHash - - /** - * This method would not return until the flow is finished (hence the "Sync"). - * - * Longer term we'd add an Async version that returns some kind of FlowInvocationRef that could be queried and - * would appear on some kind of event message that is broadcast informing of progress. - * - * Will throw exception if flow fails. - */ - fun invokeFlowSync(type: FlowRef, args: Map): Any? - - // fun invokeFlowAsync(type: FlowRef, args: Map): FlowInstanceRef - - /** - * Fetch flows that require a response to some prompt/question by a human (on the "bank" side). - */ - fun fetchFlowsRequiringAttention(query: StatesQuery): Map - - /** - * Provide the response that a flow is waiting for. - * - * @param flow Should refer to a previously supplied FlowRequiringAttention. - * @param stepId Which step of the flow are we referring too. - * @param choice Should be one of the choices presented in the FlowRequiringAttention. - * @param args Any arguments required. - */ - fun provideFlowResponse(flow: FlowInstanceRef, choice: SecureHash, args: Map) - -} - -/** - * Encapsulates the contract type. e.g. Cash or CommercialPaper etc. - */ -interface ContractDefRef { - -} - -data class ContractClassRef(val className: String) : ContractDefRef -data class ContractLedgerRef(val hash: SecureHash) : ContractDefRef - - -/** - * Encapsulates the flow to be instantiated. e.g. TwoPartyTradeFlow.Buyer. - */ -interface FlowRef { - -} - -data class FlowClassRef(val className: String) : FlowRef - -data class FlowInstanceRef(val flowInstance: SecureHash, val flowClass: FlowClassRef, val flowStepId: String) - -/** - * Thinking that Instant is OK for short lived flow deadlines. - */ -data class FlowRequiringAttention(val ref: FlowInstanceRef, val prompt: String, val choiceIdsToMessages: Map, val dueBy: Instant) - - -/** - * Encapsulate a generateXXX method call on a contract. - */ -data class TransactionBuildStep(val generateMethodName: String, val args: Map) 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 3393fdde12..fef25192e9 100644 --- a/node/src/main/kotlin/net/corda/node/driver/Driver.kt +++ b/node/src/main/kotlin/net/corda/node/driver/Driver.kt @@ -2,8 +2,6 @@ package net.corda.node.driver -import com.fasterxml.jackson.databind.ObjectMapper -import com.fasterxml.jackson.databind.module.SimpleModule import com.google.common.net.HostAndPort import com.google.common.util.concurrent.Futures import com.google.common.util.concurrent.ListenableFuture @@ -12,6 +10,7 @@ import com.typesafe.config.Config import com.typesafe.config.ConfigRenderOptions import net.corda.core.* import net.corda.core.crypto.Party +import net.corda.core.messaging.CordaRPCOps import net.corda.core.node.NodeInfo import net.corda.core.node.services.ServiceInfo import net.corda.core.node.services.ServiceType @@ -19,12 +18,15 @@ import net.corda.core.utilities.loggerFor import net.corda.node.services.User import net.corda.node.services.config.ConfigHelper import net.corda.node.services.config.FullNodeConfiguration +import net.corda.node.services.config.SSLConfiguration +import net.corda.node.services.messaging.ArtemisMessagingComponent import net.corda.node.services.messaging.CordaRPCClient import net.corda.node.services.messaging.NodeMessagingClient import net.corda.node.services.network.NetworkMapService import net.corda.node.services.transactions.RaftValidatingNotaryService -import net.corda.node.utilities.JsonSupport import net.corda.node.utilities.ServiceIdentityGenerator +import okhttp3.OkHttpClient +import okhttp3.Request import org.slf4j.Logger import java.io.File import java.net.* @@ -34,14 +36,12 @@ import java.time.Instant import java.time.ZoneOffset.UTC import java.time.format.DateTimeFormatter import java.util.* -import java.util.concurrent.Executors -import java.util.concurrent.Future -import java.util.concurrent.ScheduledExecutorService +import java.util.concurrent.* import java.util.concurrent.TimeUnit.MILLISECONDS import java.util.concurrent.TimeUnit.SECONDS -import java.util.concurrent.TimeoutException import java.util.concurrent.atomic.AtomicInteger + /** * This file defines a small "Driver" DSL for starting up nodes that is only intended for development, demos and tests. * @@ -84,6 +84,13 @@ interface DriverDSLExposedInterface { type: ServiceType = RaftValidatingNotaryService.type, rpcUsers: List = emptyList()): Future>> + /** + * Starts a web server for a node + * + * @param handle The handle for the node that this webserver connects to via RPC. + */ + fun startWebserver(handle: NodeHandle): ListenableFuture + fun waitForAllNodesToFinish() } @@ -94,6 +101,7 @@ interface DriverDSLInternalInterface : DriverDSLExposedInterface { data class NodeHandle( val nodeInfo: NodeInfo, + val rpc: CordaRPCOps, val configuration: FullNodeConfiguration, val process: Process ) { @@ -187,6 +195,7 @@ fun genericD return returnValue } catch (exception: Throwable) { println("Driver shutting down because of exception $exception") + exception.printStackTrace() throw exception } finally { driverDsl.shutdown() @@ -318,24 +327,16 @@ open class DriverDSL( executorService.shutdown() } - private fun queryNodeInfo(webAddress: HostAndPort): NodeInfo? { - val url = URL("http://$webAddress/api/info") - try { - val conn = url.openConnection() as HttpURLConnection - conn.requestMethod = "GET" - if (conn.responseCode != 200) { - log.error("Received response code ${conn.responseCode} from $url during startup.") - return null + private fun establishRpc(nodeAddress: HostAndPort, sslConfig: SSLConfiguration): ListenableFuture { + val client = CordaRPCClient(nodeAddress, sslConfig) + return poll(executorService, "for RPC connection") { + try { + client.start(ArtemisMessagingComponent.NODE_USER, ArtemisMessagingComponent.NODE_USER) + return@poll client.proxy() + } catch(e: Exception) { + log.error("Exception $e, Retrying RPC connection at $nodeAddress") + null } - // For now the NodeInfo is tunneled in its Kryo format over the Node's Web interface. - val om = ObjectMapper() - val module = SimpleModule("NodeInfo") - module.addDeserializer(NodeInfo::class.java, JsonSupport.NodeInfoDeserializer) - om.registerModule(module) - return om.readValue(conn.inputStream, NodeInfo::class.java) - } catch(e: Exception) { - log.error("Could not query node info at $url due to an exception.", e) - return null } } @@ -375,10 +376,14 @@ open class DriverDSL( ) ) - val startNode = startNode(executorService, configuration, quasarJarPath, debugPort) - registerProcess(startNode) - return startNode.map { - NodeHandle(queryNodeInfo(apiAddress)!!, configuration, it) + val processFuture = startNode(executorService, configuration, quasarJarPath, debugPort) + registerProcess(processFuture) + return processFuture.flatMap { process -> + establishRpc(messagingAddress, configuration).flatMap { rpc -> + rpc.waitUntilRegisteredWithNetworkMap().toFuture().map { + NodeHandle(rpc.nodeIdentity(), rpc, configuration, process) + } + } } } @@ -413,12 +418,39 @@ open class DriverDSL( } } + private fun queryWebserver(configuration: FullNodeConfiguration): HostAndPort? { + val protocol = if (configuration.useHTTPS) { + "https://" + } else { + "http://" + } + val url = URL(protocol + configuration.webAddress.toString() + "/api/status") + val client = OkHttpClient.Builder().connectTimeout(5, TimeUnit.SECONDS).readTimeout(60, TimeUnit.SECONDS).build() + + while (true) try { + val response = client.newCall(Request.Builder().url(url).build()).execute() + if (response.isSuccessful && (response.body().string() == "started")) { + return configuration.webAddress + } + } catch(e: ConnectException) { + log.debug("Retrying webserver info at ${configuration.webAddress}") + } + } + + override fun startWebserver(handle: NodeHandle): ListenableFuture { + val debugPort = if (isDebug) debugPortAllocation.nextPort() else null + + return future { + registerProcess(DriverDSL.startWebserver(executorService, handle.configuration, debugPort)) + queryWebserver(handle.configuration)!! + } + } + override fun start() { startNetworkMapService() } private fun startNetworkMapService(): ListenableFuture { - val apiAddress = portAllocation.nextHostAndPort() val debugPort = if (isDebug) debugPortAllocation.nextPort() else null val baseDirectory = driverDirectory / networkMapLegalName @@ -428,7 +460,6 @@ open class DriverDSL( configOverrides = mapOf( "myLegalName" to networkMapLegalName, "artemisAddress" to networkMapAddress.toString(), - "webAddress" to apiAddress.toString(), "extraAdvertisedServiceIds" to "", "useTestClock" to useTestClock ) @@ -468,30 +499,66 @@ open class DriverDSL( else "" - val javaArgs = listOf( - path, - "-Dname=${nodeConf.myLegalName}", - "-javaagent:$quasarJarPath", - debugPortArg, - "-Dvisualvm.display.name=Corda", - "-Xmx200m", - "-XX:+UseG1GC", - "-cp", classpath, - className, - "--base-directory=${nodeConf.baseDirectory}" - ).filter(String::isNotEmpty) + val additionalKeys = listOf("amq.delivery.delay.ms") + + val systemArgs = mutableMapOf( + "name" to nodeConf.myLegalName, + "visualvm.display.name" to "Corda" + ) + + for (key in additionalKeys) { + if (System.getProperty(key) != null) { + systemArgs.set(key, System.getProperty(key)) + } + } + + val javaArgs = listOf(path) + + systemArgs.map { "-D${it.key}=${it.value}" } + + listOf( + "-javaagent:$quasarJarPath", + debugPortArg, + "-Xmx200m", + "-XX:+UseG1GC", + "-cp", classpath, + className, + "--base-directory=${nodeConf.baseDirectory}" + ).filter(String::isNotEmpty) val builder = ProcessBuilder(javaArgs) builder.redirectError(Paths.get("error.$className.log").toFile()) builder.inheritIO() builder.directory(nodeConf.baseDirectory.toFile()) val process = builder.start() - return Futures.allAsList( - addressMustBeBound(executorService, nodeConf.artemisAddress), - // TODO There is a race condition here. Even though the messaging address is bound it may be the case that - // the handlers for the advertised services are not yet registered. A hacky workaround is that we wait for - // the web api address to be bound as well, as that starts after the services. Needs rethinking. - addressMustBeBound(executorService, nodeConf.webAddress) - ).map { process } + // TODO There is a race condition here. Even though the messaging address is bound it may be the case that + // the handlers for the advertised services are not yet registered. Needs rethinking. + return addressMustBeBound(executorService, nodeConf.artemisAddress).map { process } + } + + private fun startWebserver( + executorService: ScheduledExecutorService, + nodeConf: FullNodeConfiguration, + debugPort: Int?): ListenableFuture { + val className = "net.corda.node.Corda" // cannot directly get class for this, so just use string + val separator = System.getProperty("file.separator") + val classpath = System.getProperty("java.class.path") + val path = System.getProperty("java.home") + separator + "bin" + separator + "java" + + val debugPortArg = if (debugPort != null) + listOf("-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=$debugPort") + else + emptyList() + + val javaArgs = listOf(path) + + listOf("-Dname=node-${nodeConf.artemisAddress}-webserver") + debugPortArg + + listOf( + "-cp", classpath, className, + "--base-directory", nodeConf.baseDirectory.toString(), + "--webserver") + val builder = ProcessBuilder(javaArgs) + builder.redirectError(Paths.get("error.$className.log").toFile()) + builder.inheritIO() + builder.directory(nodeConf.baseDirectory.toFile()) + val process = builder.start() + return addressMustBeBound(executorService, nodeConf.webAddress).map { process } } } } diff --git a/node/src/main/kotlin/net/corda/node/internal/APIServerImpl.kt b/node/src/main/kotlin/net/corda/node/internal/APIServerImpl.kt deleted file mode 100644 index f4835ed232..0000000000 --- a/node/src/main/kotlin/net/corda/node/internal/APIServerImpl.kt +++ /dev/null @@ -1,92 +0,0 @@ -package net.corda.node.internal - -import com.google.common.util.concurrent.ListenableFuture -import net.corda.core.contracts.ContractState -import net.corda.core.contracts.DealState -import net.corda.core.contracts.StateRef -import net.corda.core.contracts.TransactionState -import net.corda.core.crypto.DigitalSignature -import net.corda.core.crypto.SecureHash -import net.corda.core.node.services.linearHeadsOfType -import net.corda.core.serialization.SerializedBytes -import net.corda.core.transactions.SignedTransaction -import net.corda.core.transactions.WireTransaction -import net.corda.node.api.* -import java.time.LocalDateTime -import javax.ws.rs.core.Response - -class APIServerImpl(val node: AbstractNode) : APIServer { - - override fun serverTime(): LocalDateTime = LocalDateTime.now(node.services.clock) - - override fun status(): Response { - return if (node.started) { - Response.ok("started").build() - } else { - Response.status(Response.Status.SERVICE_UNAVAILABLE).entity("not started").build() - } - } - - override fun info() = node.services.myInfo - - override fun queryStates(query: StatesQuery): List { - // We're going to hard code two options here for now and assume that all LinearStates are deals - // Would like to maybe move to a model where we take something like a JEXL string, although don't want to develop - // something we can't later implement against a persistent store (i.e. need to pick / build a query engine) - if (query is StatesQuery.Selection) { - if (query.criteria is StatesQuery.Criteria.AllDeals) { - val states = node.services.vaultService.linearHeads - return states.values.map { it.ref } - } else if (query.criteria is StatesQuery.Criteria.Deal) { - val states = node.services.vaultService.linearHeadsOfType().filterValues { - it.state.data.ref == query.criteria.ref - } - return states.values.map { it.ref } - } - } - return emptyList() - } - - override fun fetchStates(states: List): Map?> { - return node.services.vaultService.statesForRefs(states) - } - - override fun fetchTransactions(txs: List): Map { - throw UnsupportedOperationException() - } - - override fun buildTransaction(type: ContractDefRef, steps: List): SerializedBytes { - throw UnsupportedOperationException() - } - - override fun generateTransactionSignature(tx: SerializedBytes): DigitalSignature.WithKey { - throw UnsupportedOperationException() - } - - override fun commitTransaction(tx: SerializedBytes, signatures: List): SecureHash { - throw UnsupportedOperationException() - } - - override fun invokeFlowSync(type: FlowRef, args: Map): Any? { - return invokeFlowAsync(type, args).get() - } - - private fun invokeFlowAsync(type: FlowRef, args: Map): ListenableFuture { - if (type is FlowClassRef) { - val flowLogicRef = node.services.flowLogicRefFactory.createKotlin(type.className, args) - val flowInstance = node.services.flowLogicRefFactory.toFlowLogic(flowLogicRef) - return node.services.startFlow(flowInstance).resultFuture - } else { - throw UnsupportedOperationException("Unsupported FlowRef type: $type") - } - } - - override fun fetchFlowsRequiringAttention(query: StatesQuery): Map { - throw UnsupportedOperationException() - } - - override fun provideFlowResponse(flow: FlowInstanceRef, choice: SecureHash, args: Map) { - throw UnsupportedOperationException() - } - -} 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 cdba196d02..126f53e23f 100644 --- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt @@ -24,7 +24,6 @@ import net.corda.flows.CashCommand import net.corda.flows.CashFlow import net.corda.flows.FinalityFlow import net.corda.flows.sendRequest -import net.corda.node.api.APIServer import net.corda.node.services.api.* import net.corda.node.services.config.NodeConfiguration import net.corda.node.services.config.configureWithDevSSLCertificate @@ -52,6 +51,7 @@ import net.corda.node.utilities.databaseTransaction import org.apache.activemq.artemis.utils.ReusableLatch import org.jetbrains.exposed.sql.Database import org.slf4j.Logger +import java.io.File import java.nio.file.FileAlreadyExistsException import java.nio.file.Path import java.security.KeyPair @@ -104,11 +104,6 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, // low-performance prototyping period. protected abstract val serverThread: AffinityExecutor - // Objects in this list will be scanned by the DataUploadServlet and can be handed new data via HTTP. - // Don't mutate this after startup. - protected val _servicesThatAcceptUploads = ArrayList() - val servicesThatAcceptUploads: List = _servicesThatAcceptUploads - private val flowFactories = ConcurrentHashMap, (Party) -> FlowLogic<*>>() protected val partyKeys = mutableSetOf() @@ -163,7 +158,6 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, lateinit var identity: IdentityService lateinit var net: MessagingServiceInternal lateinit var netMapCache: NetworkMapCache - lateinit var api: APIServer lateinit var scheduler: NodeSchedulerService lateinit var flowLogicFactory: FlowLogicRefFactory lateinit var schemas: SchemaService @@ -219,7 +213,6 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, // 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() - api = APIServerImpl(this@AbstractNode) flowLogicFactory = initialiseFlowLogicFactory() scheduler = NodeSchedulerService(database, services, flowLogicFactory, unfinishedSchedules = busyNodeLatch) @@ -228,6 +221,10 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, customServices.clear() customServices.addAll(buildPluginServices(tokenizableServices)) + val uploaders: List = listOf(storageServices.first.attachments as NodeAttachmentService) + + customServices.filterIsInstance(AcceptsFileUpload::class.java) + (storage as StorageServiceImpl).initUploaders(uploaders) + // TODO: uniquenessProvider creation should be inside makeNotaryService(), but notary service initialisation // depends on smm, while smm depends on tokenizableServices, which uniquenessProvider is part of advertisedServices.singleOrNull { it.type.isNotary() }?.let { @@ -275,16 +272,16 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, } private fun makeInfo(): NodeInfo { - val services = makeServiceEntries() + val advertisedServiceEntries = makeServiceEntries() val legalIdentity = obtainLegalIdentity() - return NodeInfo(net.myAddress, legalIdentity, services, findMyLocation()) + return NodeInfo(net.myAddress, legalIdentity, advertisedServiceEntries, findMyLocation()) } /** * A service entry contains the advertised [ServiceInfo] along with the service identity. The identity *name* is * taken from the configuration or, if non specified, generated by combining the node's legal name and the service id. */ - protected fun makeServiceEntries(): List { + protected open fun makeServiceEntries(): List { return advertisedServices.map { val serviceId = it.type.id val serviceName = it.name ?: "$serviceId|${configuration.myLegalName}" @@ -353,9 +350,6 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, val service = serviceConstructor.apply(services) serviceList.add(service) tokenizableServices.add(service) - if (service is AcceptsFileUpload) { - _servicesThatAcceptUploads += service - } } return serviceList } @@ -485,7 +479,6 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, val attachments = makeAttachmentStorage(dir) val checkpointStorage = DBCheckpointStorage() val transactionStorage = DBTransactionStorage() - _servicesThatAcceptUploads += attachments val stateMachineTransactionMappingStorage = DBTransactionMappingStorage() return Pair( constructStorageService(attachments, transactionStorage, stateMachineTransactionMappingStorage), diff --git a/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt b/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt index ec002c245d..38b95bf46d 100644 --- a/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt +++ b/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt @@ -112,7 +112,14 @@ class CordaRPCOpsImpl( override fun attachmentExists(id: SecureHash) = services.storageService.attachments.openAttachment(id) != null override fun uploadAttachment(jar: InputStream) = services.storageService.attachments.importAttachment(jar) override fun currentNodeTime(): Instant = Instant.now(services.clock) + override fun uploadFile(dataType: String, name: String?, file: InputStream): String { + val acceptor = services.storageService.uploaders.firstOrNull { it.accepts(dataType) } + return databaseTransaction(database) { + acceptor?.upload(file) ?: throw RuntimeException("Cannot find file upload acceptor for $dataType") + } + } + override fun waitUntilRegisteredWithNetworkMap() = services.networkMapCache.mapServiceRegistered.toObservable() override fun partyFromKey(key: CompositeKey) = services.identityService.partyFromKey(key) override fun partyFromName(name: String) = services.identityService.partyFromName(name) 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 2fe41bbfb8..b4b48d0101 100644 --- a/node/src/main/kotlin/net/corda/node/internal/Node.kt +++ b/node/src/main/kotlin/net/corda/node/internal/Node.kt @@ -6,13 +6,12 @@ import com.google.common.util.concurrent.Futures import com.google.common.util.concurrent.ListenableFuture import net.corda.core.div import net.corda.core.flatMap -import net.corda.core.messaging.CordaRPCOps +import net.corda.core.getOrThrow import net.corda.core.messaging.RPCOps import net.corda.core.node.ServiceHub 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.success import net.corda.core.utilities.loggerFor import net.corda.node.printBasicNodeInfo import net.corda.node.serialization.NodeClock @@ -20,39 +19,19 @@ import net.corda.node.services.RPCUserService import net.corda.node.services.RPCUserServiceImpl import net.corda.node.services.api.MessagingServiceInternal import net.corda.node.services.config.FullNodeConfiguration -import net.corda.node.services.messaging.ArtemisMessagingComponent.Companion.NODE_USER import net.corda.node.services.messaging.ArtemisMessagingComponent.NetworkMapAddress import net.corda.node.services.messaging.ArtemisMessagingServer -import net.corda.node.services.messaging.CordaRPCClient import net.corda.node.services.messaging.NodeMessagingClient import net.corda.node.services.transactions.PersistentUniquenessProvider import net.corda.node.services.transactions.RaftUniquenessProvider import net.corda.node.services.transactions.RaftValidatingNotaryService -import net.corda.node.servlets.AttachmentDownloadServlet -import net.corda.node.servlets.Config -import net.corda.node.servlets.DataUploadServlet -import net.corda.node.servlets.ResponseFilter import net.corda.node.utilities.AffinityExecutor import net.corda.node.utilities.databaseTransaction -import org.eclipse.jetty.server.* -import org.eclipse.jetty.server.handler.HandlerCollection -import org.eclipse.jetty.servlet.DefaultServlet -import org.eclipse.jetty.servlet.FilterHolder -import org.eclipse.jetty.servlet.ServletContextHandler -import org.eclipse.jetty.servlet.ServletHolder -import org.eclipse.jetty.util.ssl.SslContextFactory -import org.eclipse.jetty.webapp.WebAppContext -import org.glassfish.jersey.server.ResourceConfig -import org.glassfish.jersey.server.ServerProperties -import org.glassfish.jersey.servlet.ServletContainer import org.jetbrains.exposed.sql.Database import java.io.RandomAccessFile import java.lang.management.ManagementFactory -import java.lang.reflect.InvocationTargetException -import java.net.InetAddress import java.nio.channels.FileLock import java.time.Clock -import java.util.* import javax.management.ObjectName import javax.servlet.* import kotlin.concurrent.thread @@ -111,7 +90,6 @@ class Node(override val configuration: FullNodeConfiguration, // serialisation/deserialisation work. override val serverThread = AffinityExecutor.ServiceAffinityExecutor("Node thread", 1) - lateinit var webServer: Server var messageBroker: ArtemisMessagingServer? = null // Avoid the lock being garbage collected. We don't really need to release it as the OS will do so for us @@ -157,116 +135,6 @@ class Node(override val configuration: FullNodeConfiguration, return networkMapConnection.flatMap { super.registerWithNetworkMap() } } - // TODO: add flag to enable/disable webserver - private fun initWebServer(localRpc: CordaRPCOps): Server { - // Note that the web server handlers will all run concurrently, and not on the node thread. - val handlerCollection = HandlerCollection() - - // Export JMX monitoring statistics and data over REST/JSON. - if (configuration.exportJMXto.split(',').contains("http")) { - val classpath = System.getProperty("java.class.path").split(System.getProperty("path.separator")) - val warpath = classpath.firstOrNull { it.contains("jolokia-agent-war-2") && it.endsWith(".war") } - if (warpath != null) { - handlerCollection.addHandler(WebAppContext().apply { - // Find the jolokia WAR file on the classpath. - contextPath = "/monitoring/json" - setInitParameter("mimeType", "application/json") - war = warpath - }) - } else { - log.warn("Unable to locate Jolokia WAR on classpath") - } - } - - // API, data upload and download to services (attachments, rates oracles etc) - handlerCollection.addHandler(buildServletContextHandler(localRpc)) - - val server = Server() - - val connector = if (configuration.useHTTPS) { - val httpsConfiguration = HttpConfiguration() - httpsConfiguration.outputBufferSize = 32768 - httpsConfiguration.addCustomizer(SecureRequestCustomizer()) - val sslContextFactory = SslContextFactory() - sslContextFactory.keyStorePath = configuration.keyStoreFile.toString() - sslContextFactory.setKeyStorePassword(configuration.keyStorePassword) - sslContextFactory.setKeyManagerPassword(configuration.keyStorePassword) - sslContextFactory.setTrustStorePath(configuration.trustStoreFile.toString()) - sslContextFactory.setTrustStorePassword(configuration.trustStorePassword) - sslContextFactory.setExcludeProtocols("SSL.*", "TLSv1", "TLSv1.1") - sslContextFactory.setIncludeProtocols("TLSv1.2") - sslContextFactory.setExcludeCipherSuites(".*NULL.*", ".*RC4.*", ".*MD5.*", ".*DES.*", ".*DSS.*") - sslContextFactory.setIncludeCipherSuites(".*AES.*GCM.*") - val sslConnector = ServerConnector(server, SslConnectionFactory(sslContextFactory, "http/1.1"), HttpConnectionFactory(httpsConfiguration)) - sslConnector.port = configuration.webAddress.port - sslConnector - } else { - val httpConfiguration = HttpConfiguration() - httpConfiguration.outputBufferSize = 32768 - val httpConnector = ServerConnector(server, HttpConnectionFactory(httpConfiguration)) - httpConnector.port = configuration.webAddress.port - httpConnector - } - server.connectors = arrayOf(connector) - - server.handler = handlerCollection - runOnStop += Runnable { server.stop() } - server.start() - printBasicNodeInfo("Embedded web server is listening on", "http://${InetAddress.getLocalHost().hostAddress}:${connector.port}/") - return server - } - - private fun buildServletContextHandler(localRpc: CordaRPCOps): ServletContextHandler { - return ServletContextHandler().apply { - contextPath = "/" - setAttribute("node", this@Node) - addServlet(DataUploadServlet::class.java, "/upload/*") - addServlet(AttachmentDownloadServlet::class.java, "/attachments/*") - - val resourceConfig = ResourceConfig() - // Add your API provider classes (annotated for JAX-RS) here - resourceConfig.register(Config(services)) - resourceConfig.register(ResponseFilter()) - resourceConfig.register(api) - - val webAPIsOnClasspath = pluginRegistries.flatMap { x -> x.webApis } - for (webapi in webAPIsOnClasspath) { - log.info("Add plugin web API from attachment $webapi") - val customAPI = try { - webapi.apply(localRpc) - } catch (ex: InvocationTargetException) { - log.error("Constructor $webapi threw an error: ", ex.targetException) - continue - } - resourceConfig.register(customAPI) - } - - val staticDirMaps = pluginRegistries.map { x -> x.staticServeDirs } - val staticDirs = staticDirMaps.flatMap { it.keys }.zip(staticDirMaps.flatMap { it.values }) - staticDirs.forEach { - val staticDir = ServletHolder(DefaultServlet::class.java) - staticDir.setInitParameter("resourceBase", it.second) - staticDir.setInitParameter("dirAllowed", "true") - staticDir.setInitParameter("pathInfoOnly", "true") - addServlet(staticDir, "/web/${it.first}/*") - } - - // Give the app a slightly better name in JMX rather than a randomly generated one and enable JMX - resourceConfig.addProperties(mapOf(ServerProperties.APPLICATION_NAME to "node.api", - ServerProperties.MONITORING_STATISTICS_MBEANS_ENABLED to "true")) - - val container = ServletContainer(resourceConfig) - val jerseyServlet = ServletHolder(container) - addServlet(jerseyServlet, "/api/*") - jerseyServlet.initOrder = 0 // Initialise at server start - - // Wrap all API calls in a database transaction. - val filterHolder = FilterHolder(DatabaseTransactionFilter(database)) - addFilter(filterHolder, "/api/*", EnumSet.of(DispatcherType.REQUEST)) - addFilter(filterHolder, "/upload/*", EnumSet.of(DispatcherType.REQUEST)) - } - } - override fun makeUniquenessProvider(type: ServiceType): UniquenessProvider { return when (type) { RaftValidatingNotaryService.type -> with(configuration) { @@ -305,43 +173,27 @@ class Node(override val configuration: FullNodeConfiguration, super.initialiseDatabasePersistence(insideTransaction) } - private fun connectLocalRpcAsNodeUser(): CordaRPCOps { - val client = CordaRPCClient(configuration.artemisAddress, configuration) - client.start(NODE_USER, NODE_USER) - return client.proxy() - } - override fun start(): Node { alreadyRunningNodeCheck() super.start() - - // Only start the service API requests once the network map registration is successfully complete - networkMapRegistrationFuture.success { - // This needs to be in a seperate thread so that we can reply to our own request to become RPC clients - thread(name = "WebServer") { - try { - webServer = initWebServer(connectLocalRpcAsNodeUser()) - } catch(ex: Exception) { - // TODO: We need to decide if this is a fatal error, given the API is unavailable, or whether the API - // is not critical and we continue anyway. - log.error("Web server startup failed", ex) - } - // Begin exporting our own metrics via JMX. - JmxReporter. - forRegistry(services.monitoringService.metrics). - inDomain("net.corda"). - createsObjectNamesWith { type, domain, name -> - // Make the JMX hierarchy a bit better organised. - val category = name.substringBefore('.') - val subName = name.substringAfter('.', "") - if (subName == "") - ObjectName("$domain:name=$category") - else - ObjectName("$domain:type=$category,name=$subName") - }. - build(). - start() - } + // Only start the service API requests once the network map registration is complete + thread(name = "WebServer") { + networkMapRegistrationFuture.getOrThrow() + // Begin exporting our own metrics via JMX. + JmxReporter. + forRegistry(services.monitoringService.metrics). + inDomain("net.corda"). + createsObjectNamesWith { type, domain, name -> + // Make the JMX hierarchy a bit better organised. + val category = name.substringBefore('.') + val subName = name.substringAfter('.', "") + if (subName == "") + ObjectName("$domain:name=$category") + else + ObjectName("$domain:type=$category,name=$subName") + }. + build(). + start() } shutdownThread = thread(start = false) { @@ -420,6 +272,7 @@ class Node(override val configuration: FullNodeConfiguration, chain.doFilter(request, response) } } + override fun init(filterConfig: FilterConfig?) {} override fun destroy() {} } diff --git a/node/src/main/kotlin/net/corda/node/services/api/AcceptsFileUpload.kt b/node/src/main/kotlin/net/corda/node/services/api/AcceptsFileUpload.kt index bdf0c54d33..10bcfb7e65 100644 --- a/node/src/main/kotlin/net/corda/node/services/api/AcceptsFileUpload.kt +++ b/node/src/main/kotlin/net/corda/node/services/api/AcceptsFileUpload.kt @@ -1,5 +1,7 @@ package net.corda.node.services.api +import net.corda.core.crypto.SecureHash +import net.corda.core.node.services.FileUploader import java.io.InputStream /** @@ -7,16 +9,12 @@ import java.io.InputStream * * TODO: In future, also accept uploads over the MQ interface too. */ -interface AcceptsFileUpload { +interface AcceptsFileUpload: FileUploader { /** A string that prefixes the URLs, e.g. "attachments" or "interest-rates". Should be OK for URLs. */ val dataTypePrefix: String /** What file extensions are acceptable for the file to be handed to upload() */ val acceptableFileExtensions: List - /** - * Accepts the data in the given input stream, and returns some sort of useful return message that will be sent - * back to the user in the response. - */ - fun upload(data: InputStream): String + override fun accepts(prefix: String) = prefix == dataTypePrefix } diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/CordaRPCClient.kt b/node/src/main/kotlin/net/corda/node/services/messaging/CordaRPCClient.kt index 10514e08f3..7c68bd24b3 100644 --- a/node/src/main/kotlin/net/corda/node/services/messaging/CordaRPCClient.kt +++ b/node/src/main/kotlin/net/corda/node/services/messaging/CordaRPCClient.kt @@ -4,6 +4,8 @@ import com.google.common.net.HostAndPort import net.corda.core.ThreadBox import net.corda.core.logElapsedTime import net.corda.core.messaging.CordaRPCOps +import net.corda.core.minutes +import net.corda.core.seconds import net.corda.core.utilities.loggerFor import net.corda.node.services.config.SSLConfiguration import net.corda.node.services.messaging.ArtemisMessagingComponent.ConnectionDirection.Outbound @@ -11,6 +13,7 @@ import org.apache.activemq.artemis.api.core.ActiveMQException import org.apache.activemq.artemis.api.core.client.ActiveMQClient import org.apache.activemq.artemis.api.core.client.ClientSession import org.apache.activemq.artemis.api.core.client.ClientSessionFactory +import org.apache.activemq.artemis.api.core.client.ServerLocator import rx.Observable import java.io.Closeable import java.time.Duration @@ -24,7 +27,7 @@ import javax.annotation.concurrent.ThreadSafe * @param config If specified, the SSL configuration to use. If not specified, SSL will be disabled and the node will not be authenticated, nor will RPC traffic be encrypted. */ @ThreadSafe -class CordaRPCClient(val host: HostAndPort, override val config: SSLConfiguration?) : Closeable, ArtemisMessagingComponent() { +class CordaRPCClient(val host: HostAndPort, override val config: SSLConfiguration?, val serviceConfigurationOverride: (ServerLocator.() -> Unit)? = null) : Closeable, ArtemisMessagingComponent() { private companion object { val log = loggerFor() } @@ -49,11 +52,15 @@ class CordaRPCClient(val host: HostAndPort, override val config: SSLConfiguratio check(!running) log.logElapsedTime("Startup") { checkStorePasswords() - val serverLocator = ActiveMQClient.createServerLocatorWithoutHA(tcpTransport(Outbound(), host.hostText, host.port)) - serverLocator.threadPoolMaxSize = 1 - // TODO: Configure session reconnection, confirmation window sizes and other Artemis features. - // This will allow reconnection in case of server restart/network outages/IP address changes, etc. - // See http://activemq.apache.org/artemis/docs/1.5.0/client-reconnection.html + val serverLocator = ActiveMQClient.createServerLocatorWithoutHA(tcpTransport(Outbound(), host.hostText, host.port)).apply { + // TODO: Put these in config file or make it user configurable? + threadPoolMaxSize = 1 + confirmationWindowSize = 100000 // a guess + retryInterval = 5.seconds.toMillis() + retryIntervalMultiplier = 1.5 // Exponential backoff + maxRetryInterval = 3.minutes.toMillis() + serviceConfigurationOverride?.invoke(this) + } sessionFactory = serverLocator.createSessionFactory() session = sessionFactory.createSession(username, password, false, true, true, serverLocator.isPreAcknowledge, serverLocator.ackBatchSize) session.start() 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 d7290474b7..3dce4d17b4 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 @@ -15,10 +15,10 @@ import net.corda.node.services.RPCUserService import net.corda.node.services.api.MessagingServiceInternal import net.corda.node.services.config.NodeConfiguration import net.corda.node.services.messaging.ArtemisMessagingComponent.ConnectionDirection.Outbound +import net.corda.node.services.statemachine.StateMachineManager import net.corda.node.utilities.* import org.apache.activemq.artemis.api.core.ActiveMQObjectClosedException -import org.apache.activemq.artemis.api.core.Message.HDR_DUPLICATE_DETECTION_ID -import org.apache.activemq.artemis.api.core.Message.HDR_VALIDATED_USER +import org.apache.activemq.artemis.api.core.Message.* import org.apache.activemq.artemis.api.core.SimpleString import org.apache.activemq.artemis.api.core.client.* import org.bouncycastle.asn1.x500.X500Name @@ -67,6 +67,7 @@ class NodeMessagingClient(override val config: NodeConfiguration, // confusion. const val TOPIC_PROPERTY = "platform-topic" const val SESSION_ID_PROPERTY = "session-id" + val AMQ_DELAY = Integer.valueOf(System.getProperty("amq.delivery.delay.ms", "0")) } private class InnerState { @@ -102,12 +103,12 @@ class NodeMessagingClient(override val config: NodeConfiguration, } private val processedMessages: MutableSet = Collections.synchronizedSet( - object : AbstractJDBCHashSet(Table, loadOnInit = true) { - override fun elementFromRow(row: ResultRow): UUID = row[table.uuid] - override fun addElementToInsert(insert: InsertStatement, entry: UUID, finalizables: MutableList<() -> Unit>) { - insert[table.uuid] = entry - } - }) + object : AbstractJDBCHashSet(Table, loadOnInit = true) { + override fun elementFromRow(row: ResultRow): UUID = row[table.uuid] + override fun addElementToInsert(insert: InsertStatement, entry: UUID, finalizables: MutableList<() -> Unit>) { + insert[table.uuid] = entry + } + }) fun start(rpcOps: RPCOps, userService: RPCUserService) { state.locked { @@ -368,6 +369,11 @@ class NodeMessagingClient(override val config: NodeConfiguration, writeBodyBufferBytes(message.data) // Use the magic deduplication property built into Artemis as our message identity too putStringProperty(HDR_DUPLICATE_DETECTION_ID, SimpleString(message.uniqueMessageId.toString())) + + // For demo purposes - if set then add a delay to messages in order to demonstrate that the flows are doing as intended + if (AMQ_DELAY > 0 && message.topicSession.topic == StateMachineManager.sessionTopic.topic) { + putLongProperty(HDR_SCHEDULED_DELIVERY_TIME, System.currentTimeMillis() + AMQ_DELAY); + } } log.info("Send to: $mqAddress topic: ${message.topicSession.topic} sessionID: ${message.topicSession.sessionID} " + "uuid: ${message.uniqueMessageId}") @@ -376,6 +382,7 @@ class NodeMessagingClient(override val config: NodeConfiguration, } } + private fun getMQAddress(target: MessageRecipients): String { return if (target == myAddress) { // If we are sending to ourselves then route the message directly to our P2P queue. diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/RPCStructures.kt b/node/src/main/kotlin/net/corda/node/services/messaging/RPCStructures.kt index d3f1f98727..8ddb5ee94c 100644 --- a/node/src/main/kotlin/net/corda/node/services/messaging/RPCStructures.kt +++ b/node/src/main/kotlin/net/corda/node/services/messaging/RPCStructures.kt @@ -28,7 +28,6 @@ import net.corda.core.node.services.* import net.corda.core.serialization.* import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.WireTransaction -import net.corda.flows.CashFlowResult import net.corda.node.internal.AbstractNode import net.corda.node.services.User import net.corda.node.services.messaging.ArtemisMessagingComponent.Companion.NODE_USER @@ -36,6 +35,7 @@ import net.corda.node.services.messaging.ArtemisMessagingComponent.NetworkMapAdd import net.i2p.crypto.eddsa.EdDSAPrivateKey import net.i2p.crypto.eddsa.EdDSAPublicKey import org.apache.activemq.artemis.api.core.SimpleString +import org.apache.commons.fileupload.MultipartStream import org.objenesis.strategy.StdInstantiatorStrategy import org.slf4j.Logger import org.slf4j.LoggerFactory @@ -146,6 +146,7 @@ private class RPCKryo(observableSerializer: Serializer>? = null) register(BufferedInputStream::class.java, InputStreamSerializer) register(Class.forName("sun.net.www.protocol.jar.JarURLConnection\$JarURLInputStream"), InputStreamSerializer) + register(MultipartStream.ItemInputStream::class.java, InputStreamSerializer) noReferencesWithin() @@ -191,8 +192,6 @@ private class RPCKryo(observableSerializer: Serializer>? = null) register(Cash.Clauses.ConserveAmount::class.java) register(listOf(Unit).javaClass) // SingletonList register(setOf(Unit).javaClass) // SingletonSet - register(CashFlowResult.Success::class.java) - register(CashFlowResult.Failed::class.java) register(ServiceEntry::class.java) register(NodeInfo::class.java) register(PhysicalLocation::class.java) @@ -209,6 +208,7 @@ private class RPCKryo(observableSerializer: Serializer>? = null) register(SimpleString::class.java) register(ServiceEntry::class.java) // Exceptions. We don't bother sending the stack traces as the client will fill in its own anyway. + register(RuntimeException::class.java) register(IllegalArgumentException::class.java) register(ArrayIndexOutOfBoundsException::class.java) register(IndexOutOfBoundsException::class.java) diff --git a/node/src/main/kotlin/net/corda/node/services/persistence/DataVendingService.kt b/node/src/main/kotlin/net/corda/node/services/persistence/DataVendingService.kt index e9f56ec295..8bbf3cd811 100644 --- a/node/src/main/kotlin/net/corda/node/services/persistence/DataVendingService.kt +++ b/node/src/main/kotlin/net/corda/node/services/persistence/DataVendingService.kt @@ -2,16 +2,17 @@ package net.corda.node.services.persistence import co.paralleluniverse.fibers.Suspendable import net.corda.core.crypto.Party +import net.corda.core.crypto.SecureHash +import net.corda.core.flows.FlowException import net.corda.core.flows.FlowLogic +import net.corda.core.node.CordaPluginRegistry import net.corda.core.node.PluginServiceHub import net.corda.core.node.recordTransactions import net.corda.core.serialization.SingletonSerializeAsToken -import net.corda.core.utilities.loggerFor +import net.corda.core.transactions.SignedTransaction import net.corda.flows.* -import net.corda.core.node.CordaPluginRegistry -import java.io.InputStream -import javax.annotation.concurrent.ThreadSafe import java.util.function.Function +import javax.annotation.concurrent.ThreadSafe object DataVending { @@ -33,55 +34,40 @@ object DataVending { */ @ThreadSafe class Service(services: PluginServiceHub) : SingletonSerializeAsToken() { - - companion object { - val logger = loggerFor() - } - init { services.registerFlowInitiator(FetchTransactionsFlow::class, ::FetchTransactionsHandler) services.registerFlowInitiator(FetchAttachmentsFlow::class, ::FetchAttachmentsHandler) services.registerFlowInitiator(BroadcastTransactionFlow::class, ::NotifyTransactionHandler) } - - private class FetchTransactionsHandler(val otherParty: Party) : FlowLogic() { - @Suspendable - override fun call() { - val request = receive(otherParty).unwrap { - require(it.hashes.isNotEmpty()) - it - } - val txs = request.hashes.map { - val tx = serviceHub.storageService.validatedTransactions.getTransaction(it) - if (tx == null) - logger.info("Got request for unknown tx $it") - tx - } - send(otherParty, txs) + private 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. - private class FetchAttachmentsHandler(val otherParty: Party) : FlowLogic() { + private class FetchAttachmentsHandler(otherParty: Party) : FetchDataHandler(otherParty) { + override fun getData(id: SecureHash): ByteArray? { + return serviceHub.storageService.attachments.openAttachment(id)?.open()?.readBytes() + } + } + + private abstract class FetchDataHandler(val otherParty: Party) : FlowLogic() { @Suspendable + @Throws(FetchDataFlow.HashNotFound::class) override fun call() { val request = receive(otherParty).unwrap { - require(it.hashes.isNotEmpty()) + if (it.hashes.isEmpty()) throw FlowException("Empty hash list") it } - val attachments = request.hashes.map { - val jar: InputStream? = serviceHub.storageService.attachments.openAttachment(it)?.open() - if (jar == null) { - logger.info("Got request for unknown attachment $it") - null - } else { - jar.readBytes() - } + val response = request.hashes.map { + getData(it) ?: throw FetchDataFlow.HashNotFound(it) } - send(otherParty, attachments) + send(otherParty, response) } + + protected abstract fun getData(id: SecureHash): T? } diff --git a/node/src/main/kotlin/net/corda/node/services/persistence/StorageServiceImpl.kt b/node/src/main/kotlin/net/corda/node/services/persistence/StorageServiceImpl.kt index 5e42cc8aec..6e41630fb0 100644 --- a/node/src/main/kotlin/net/corda/node/services/persistence/StorageServiceImpl.kt +++ b/node/src/main/kotlin/net/corda/node/services/persistence/StorageServiceImpl.kt @@ -1,12 +1,15 @@ package net.corda.node.services.persistence -import net.corda.core.node.services.AttachmentStorage -import net.corda.core.node.services.StateMachineRecordedTransactionMappingStorage -import net.corda.core.node.services.TransactionStorage -import net.corda.core.node.services.TxWritableStorageService +import net.corda.core.node.services.* import net.corda.core.serialization.SingletonSerializeAsToken open class StorageServiceImpl(override val attachments: AttachmentStorage, override val validatedTransactions: TransactionStorage, override val stateMachineRecordedTransactionMapping: StateMachineRecordedTransactionMappingStorage) - : SingletonSerializeAsToken(), TxWritableStorageService + : SingletonSerializeAsToken(), TxWritableStorageService { + lateinit override var uploaders: List + + fun initUploaders(uploadersList: List) { + uploaders = uploadersList + } +} 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 4675001e6a..520657c526 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 @@ -30,7 +30,7 @@ import java.util.concurrent.ExecutionException class FlowStateMachineImpl(override val id: StateMachineRunId, val logic: FlowLogic, - scheduler: FiberScheduler) : Fiber("flow", scheduler), FlowStateMachine { + scheduler: FiberScheduler) : Fiber("flow", scheduler), FlowStateMachine { companion object { // Used to work around a small limitation in Quasar. private val QUASAR_UNBLOCKER = run { @@ -49,7 +49,7 @@ class FlowStateMachineImpl(override val id: StateMachineRunId, @Transient override lateinit var serviceHub: ServiceHubInternal @Transient internal lateinit var database: Database @Transient internal lateinit var actionOnSuspend: (FlowIORequest) -> Unit - @Transient internal lateinit var actionOnEnd: () -> Unit + @Transient internal lateinit var actionOnEnd: (Pair?) -> Unit @Transient internal var fromCheckpoint: Boolean = false @Transient private var txTrampoline: Transaction? = null @@ -80,26 +80,35 @@ class FlowStateMachineImpl(override val id: StateMachineRunId, } @Suspendable - override fun run(): R { + override fun run() { createTransaction() val result = try { logic.call() + } catch (e: FlowException) { + // Check if the FlowException was propagated by looking at where the stack trace originates (see suspendAndExpectReceive). + val propagated = e.stackTrace[0].className == javaClass.name + actionOnEnd(Pair(e, propagated)) + _resultFuture?.setException(e) + return } catch (t: Throwable) { - actionOnEnd() + actionOnEnd(null) _resultFuture?.setException(t) throw ExecutionException(t) } + // Only sessions which have a single send and nothing else will block here + openSessions.values + .filter { it.state is FlowSessionState.Initiating } + .forEach { it.waitForConfirmation() } // This is to prevent actionOnEnd being called twice if it throws an exception - actionOnEnd() + actionOnEnd(null) _resultFuture?.set(result) - return result } private fun createTransaction() { // Make sure we have a database transaction createDatabaseTransaction(database) - logger.trace { "Starting database transaction ${TransactionManager.currentOrNull()} on ${Strand.currentStrand()}." } + logger.trace { "Starting database transaction ${TransactionManager.currentOrNull()} on ${Strand.currentStrand()}" } } internal fun commitTransaction() { @@ -121,34 +130,48 @@ class FlowStateMachineImpl(override val id: StateMachineRunId, otherParty: Party, payload: Any, sessionFlow: FlowLogic<*>): UntrustworthyData { - val (session, new) = getSession(otherParty, sessionFlow, payload) - val receivedSessionData = if (new) { + val session = getConfirmedSession(otherParty, sessionFlow) + return if (session == null) { // Only do a receive here as the session init has carried the payload - receiveInternal(session) + receiveInternal(startNewSession(otherParty, sessionFlow, payload, waitForConfirmation = true)) } else { - val sendSessionData = createSessionData(session, payload) - sendAndReceiveInternal(session, sendSessionData) - } - return receivedSessionData.checkPayloadIs(receiveType) + sendAndReceiveInternal(session, createSessionData(session, payload)) + }.checkPayloadIs(receiveType) } @Suspendable override fun receive(receiveType: Class, otherParty: Party, sessionFlow: FlowLogic<*>): UntrustworthyData { - val session = getSession(otherParty, sessionFlow, null).first + val session = getConfirmedSession(otherParty, sessionFlow) ?: startNewSession(otherParty, sessionFlow, null, waitForConfirmation = true) return receiveInternal(session).checkPayloadIs(receiveType) } @Suspendable override fun send(otherParty: Party, payload: Any, sessionFlow: FlowLogic<*>) { - val (session, new) = getSession(otherParty, sessionFlow, payload) - if (!new) { + val session = getConfirmedSession(otherParty, sessionFlow) + if (session == null) { // Don't send the payload again if it was already piggy-backed on a session init + startNewSession(otherParty, sessionFlow, payload, waitForConfirmation = false) + } else { sendInternal(session, createSessionData(session, payload)) } } + /** + * This method will suspend the state machine and wait for incoming session init response from other party. + */ + @Suspendable + private fun FlowSession.waitForConfirmation() { + val (peerParty, sessionInitResponse) = receiveInternal(this) + if (sessionInitResponse is SessionConfirm) { + state = FlowSessionState.Initiated(peerParty, sessionInitResponse.initiatedSessionId) + } else { + sessionInitResponse as SessionReject + throw FlowException("Party ${state.sendToParty} rejected session request: ${sessionInitResponse.errorMessage}") + } + } + private fun createSessionData(session: FlowSession, payload: Any): SessionData { val sessionState = session.state val peerSessionId = when (sessionState) { @@ -174,12 +197,12 @@ class FlowStateMachineImpl(override val id: StateMachineRunId, } @Suspendable - private fun getSession(otherParty: Party, sessionFlow: FlowLogic<*>, firstPayload: Any?): Pair { - val session = openSessions[Pair(sessionFlow, otherParty)] - return if (session != null) { - Pair(session, false) - } else { - Pair(startNewSession(otherParty, sessionFlow, firstPayload), true) + private fun getConfirmedSession(otherParty: Party, sessionFlow: FlowLogic<*>): FlowSession? { + return openSessions[Pair(sessionFlow, otherParty)]?.apply { + if (state is FlowSessionState.Initiating) { + // Session still initiating, try to retrieve the init response. + waitForConfirmation() + } } } @@ -190,24 +213,21 @@ class FlowStateMachineImpl(override val id: StateMachineRunId, * multiple public keys, but we **don't support multiple nodes advertising the same legal identity**. */ @Suspendable - private fun startNewSession(otherParty: Party, sessionFlow: FlowLogic<*>, firstPayload: Any?): FlowSession { + private fun startNewSession(otherParty: Party, sessionFlow: FlowLogic<*>, firstPayload: Any?, waitForConfirmation: Boolean): FlowSession { logger.trace { "Initiating a new session with $otherParty" } - val session = FlowSession(sessionFlow, random63BitValue(), FlowSessionState.Initiating(otherParty)) + val session = FlowSession(sessionFlow, random63BitValue(), null, FlowSessionState.Initiating(otherParty)) openSessions[Pair(sessionFlow, otherParty)] = session val counterpartyFlow = sessionFlow.getCounterpartyMarker(otherParty).name val sessionInit = SessionInit(session.ourSessionId, counterpartyFlow, firstPayload) - val (peerParty, sessionInitResponse) = sendAndReceiveInternal(session, sessionInit) - if (sessionInitResponse is SessionConfirm) { - require(session.state is FlowSessionState.Initiating) - session.state = FlowSessionState.Initiated(peerParty, sessionInitResponse.initiatedSessionId) - return session - } else { - sessionInitResponse as SessionReject - throw FlowException("Party $otherParty rejected session request: ${sessionInitResponse.errorMessage}") + sendInternal(session, sessionInit) + if (waitForConfirmation) { + session.waitForConfirmation() } + return session } @Suspendable + @Suppress("UNCHECKED_CAST", "PLATFORM_CLASS_MAPPED_TO_KOTLIN") private fun suspendAndExpectReceive(receiveRequest: ReceiveRequest): ReceivedSessionMessage { val session = receiveRequest.session fun getReceivedMessage(): ReceivedSessionMessage? = session.receivedMessages.poll() @@ -224,19 +244,23 @@ class FlowStateMachineImpl(override val id: StateMachineRunId, suspend(receiveRequest) getReceivedMessage() ?: throw IllegalStateException("Was expecting a ${receiveRequest.receiveType.simpleName} but instead " + - "got nothing: $receiveRequest") + "got nothing for $receiveRequest") } - if (receivedMessage.message is SessionEnd) { - openSessions.values.remove(session) - throw FlowException("Party ${session.state.sendToParty} has ended their flow but we were expecting to " + - "receive ${receiveRequest.receiveType.simpleName} from them") - } else if (receiveRequest.receiveType.isInstance(receivedMessage.message)) { - @Suppress("UNCHECKED_CAST") + if (receiveRequest.receiveType.isInstance(receivedMessage.message)) { return receivedMessage as ReceivedSessionMessage + } else if (receivedMessage.message is SessionEnd) { + openSessions.values.remove(session) + if (receivedMessage.message.errorResponse != null) { + (receivedMessage.message.errorResponse as java.lang.Throwable).fillInStackTrace() + throw receivedMessage.message.errorResponse + } else { + throw FlowSessionException("${session.state.sendToParty} has ended their flow but we were expecting " + + "to receive ${receiveRequest.receiveType.simpleName} from them") + } } else { throw IllegalStateException("Was expecting a ${receiveRequest.receiveType.simpleName} but instead got " + - "${receivedMessage.message}: $receiveRequest") + "${receivedMessage.message} for $receiveRequest") } } 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 6602e55add..c1811c98b8 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 @@ -29,7 +29,7 @@ data class SessionData(override val recipientSessionId: Long, val payload: Any) } } -data class SessionEnd(override val recipientSessionId: Long) : ExistingSessionMessage +data class SessionEnd(override val recipientSessionId: Long, val errorResponse: FlowException?) : ExistingSessionMessage data class ReceivedSessionMessage(val sender: Party, val message: M) @@ -37,7 +37,9 @@ fun ReceivedSessionMessage.checkPayloadIs(type: Class): Untr if (type.isInstance(message.payload)) { return UntrustworthyData(type.cast(message.payload)) } else { - throw FlowException("We were expecting a ${type.name} from $sender but we instead got a " + + throw FlowSessionException("We were expecting a ${type.name} from $sender but we instead got a " + "${message.payload.javaClass.name} (${message.payload})") } -} \ No newline at end of file +} + +class FlowSessionException(message: String) : RuntimeException(message) 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 fdfa200f1d..ee214162ef 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 @@ -12,6 +12,7 @@ import net.corda.core.ThreadBox import net.corda.core.bufferUntilSubscribed import net.corda.core.crypto.Party import net.corda.core.crypto.commonName +import net.corda.core.flows.FlowException import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowStateMachine import net.corda.core.flows.StateMachineRunId @@ -194,7 +195,7 @@ class StateMachineManager(val serviceHub: ServiceHubInternal, checkpointStorage.forEach { // If a flow is added before start() then don't attempt to restore it if (!stateMachines.containsValue(it)) { - val fiber = deserializeFiber(it.serializedFiber) + val fiber = deserializeFiber(it) initFiber(fiber) stateMachines[fiber] = it } @@ -256,7 +257,7 @@ class StateMachineManager(val serviceHub: ServiceHubInternal, if (peerParty != null) { if (message is SessionConfirm) { logger.debug { "Received session confirmation but associated fiber has already terminated, so sending session end" } - sendSessionMessage(peerParty, SessionEnd(message.initiatedSessionId)) + sendSessionMessage(peerParty, SessionEnd(message.initiatedSessionId, null)) } else { logger.trace { "Ignoring session end message for already closed session: $message" } } @@ -269,30 +270,44 @@ class StateMachineManager(val serviceHub: ServiceHubInternal, private fun onSessionInit(sessionInit: SessionInit, sender: Party) { logger.trace { "Received $sessionInit $sender" } val otherPartySessionId = sessionInit.initiatorSessionId - try { - val markerClass = Class.forName(sessionInit.flowName) - val flowFactory = serviceHub.getFlowFactory(markerClass) - if (flowFactory != null) { - val flow = flowFactory(sender) - val fiber = createFiber(flow) - val session = FlowSession(flow, random63BitValue(), FlowSessionState.Initiated(sender, otherPartySessionId)) - if (sessionInit.firstPayload != null) { - session.receivedMessages += ReceivedSessionMessage(sender, SessionData(session.ourSessionId, sessionInit.firstPayload)) - } - openSessions[session.ourSessionId] = session - fiber.openSessions[Pair(flow, sender)] = session - updateCheckpoint(fiber) - sendSessionMessage(sender, SessionConfirm(otherPartySessionId, session.ourSessionId), fiber) - fiber.logger.debug { "Initiated from $sessionInit on $session" } - startFiber(fiber) - } else { - logger.warn("Unknown flow marker class in $sessionInit") - sendSessionMessage(sender, SessionReject(otherPartySessionId, "Don't know ${markerClass.name}")) - } + + fun sendSessionReject(message: String) = sendSessionMessage(sender, SessionReject(otherPartySessionId, message)) + + val markerClass = try { + Class.forName(sessionInit.flowName) } catch (e: Exception) { logger.warn("Received invalid $sessionInit", e) - sendSessionMessage(sender, SessionReject(otherPartySessionId, "Unable to establish session")) + sendSessionReject("Don't know ${sessionInit.flowName}") + return } + + val flowFactory = serviceHub.getFlowFactory(markerClass) + if (flowFactory == null) { + logger.warn("Unknown flow marker class in $sessionInit") + sendSessionReject("Don't know ${markerClass.name}") + return + } + + val session = try { + val flow = flowFactory(sender) + val fiber = createFiber(flow) + val session = FlowSession(flow, random63BitValue(), sender, FlowSessionState.Initiated(sender, otherPartySessionId)) + if (sessionInit.firstPayload != null) { + session.receivedMessages += ReceivedSessionMessage(sender, SessionData(session.ourSessionId, sessionInit.firstPayload)) + } + openSessions[session.ourSessionId] = session + fiber.openSessions[Pair(flow, sender)] = session + updateCheckpoint(fiber) + session + } catch (e: Exception) { + logger.warn("Couldn't start session for $sessionInit", e) + sendSessionReject("Unable to establish session") + return + } + + sendSessionMessage(sender, SessionConfirm(otherPartySessionId, session.ourSessionId), session.fiber) + session.fiber.logger.debug { "Initiated from $sessionInit on $session" } + startFiber(session.fiber) } private fun serializeFiber(fiber: FlowStateMachineImpl<*>): SerializedBytes> { @@ -302,11 +317,11 @@ class StateMachineManager(val serviceHub: ServiceHubInternal, return fiber.serialize(kryo) } - private fun deserializeFiber(serialisedFiber: SerializedBytes>): FlowStateMachineImpl<*> { + private fun deserializeFiber(checkpoint: Checkpoint): FlowStateMachineImpl<*> { val kryo = quasarKryo() // put the map of token -> tokenized into the kryo context SerializeAsTokenSerializer.setContext(kryo, serializationContext) - return serialisedFiber.deserialize(kryo).apply { fromCheckpoint = true } + return checkpoint.serializedFiber.deserialize(kryo).apply { fromCheckpoint = true } } private fun quasarKryo(): Kryo { @@ -330,14 +345,14 @@ class StateMachineManager(val serviceHub: ServiceHubInternal, processIORequest(ioRequest) decrementLiveFibers() } - fiber.actionOnEnd = { + fiber.actionOnEnd = { errorResponse: Pair? -> try { fiber.logic.progressTracker?.currentStep = ProgressTracker.DONE mutex.locked { stateMachines.remove(fiber)?.let { checkpointStorage.removeCheckpoint(it) } notifyChangeObservers(fiber, AddOrRemove.REMOVE) } - endAllFiberSessions(fiber) + endAllFiberSessions(fiber, errorResponse) } finally { fiber.commitTransaction() decrementLiveFibers() @@ -352,14 +367,13 @@ class StateMachineManager(val serviceHub: ServiceHubInternal, } } - private fun endAllFiberSessions(fiber: FlowStateMachineImpl<*>) { + private fun endAllFiberSessions(fiber: FlowStateMachineImpl<*>, errorResponse: Pair?) { + // TODO Blanking the stack trace prevents the receiving flow from filling in its own stack trace +// @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") +// (errorResponse?.first as java.lang.Throwable?)?.stackTrace = emptyArray() openSessions.values.removeIf { session -> if (session.fiber == fiber) { - val initiatedState = session.state as? FlowSessionState.Initiated - if (initiatedState != null) { - sendSessionMessage(initiatedState.peerParty, SessionEnd(initiatedState.peerSessionId), fiber) - recentlyClosedSessions[session.ourSessionId] = initiatedState.peerParty - } + session.endSession(errorResponse) true } else { false @@ -367,6 +381,25 @@ class StateMachineManager(val serviceHub: ServiceHubInternal, } } + private fun FlowSession.endSession(errorResponse: Pair?) { + val initiatedState = state as? Initiated ?: return + val propagatedException = errorResponse?.let { + val (exception, propagated) = it + if (propagated) { + // This exception was propagated to us. We only propagate it down the invocation chain to the flow that + // initiated us, not to flows we've started sessions with. + if (initiatingParty != null) exception else null + } else { + exception // Our local flow threw the exception so propagate it + } + } + sendSessionMessage( + initiatedState.peerParty, + SessionEnd(initiatedState.peerSessionId, propagatedException), + fiber) + recentlyClosedSessions[ourSessionId] = initiatedState.peerParty + } + private fun startFiber(fiber: FlowStateMachineImpl<*>) { try { resumeFiber(fiber) @@ -483,6 +516,7 @@ class StateMachineManager(val serviceHub: ServiceHubInternal, data class FlowSession( val flow: FlowLogic<*>, val ourSessionId: Long, + val initiatingParty: Party?, var state: FlowSessionState, @Volatile var waitingForResponse: Boolean = false ) { diff --git a/node/src/main/kotlin/net/corda/node/utilities/ConfigUtils.kt b/node/src/main/kotlin/net/corda/node/utilities/ConfigUtils.kt new file mode 100644 index 0000000000..5048cb8981 --- /dev/null +++ b/node/src/main/kotlin/net/corda/node/utilities/ConfigUtils.kt @@ -0,0 +1,9 @@ +package net.corda.node.utilities + +import com.google.common.net.HostAndPort +import com.typesafe.config.Config +import java.nio.file.Path +import java.nio.file.Paths + +fun Config.getHostAndPort(name: String): HostAndPort = HostAndPort.fromString(getString(name)) +fun Config.getPath(name: String): Path = Paths.get(getString(name)) \ No newline at end of file diff --git a/node/src/main/kotlin/net/corda/node/utilities/JsonSupport.kt b/node/src/main/kotlin/net/corda/node/utilities/JsonSupport.kt index 452a49f385..20d06f4e67 100644 --- a/node/src/main/kotlin/net/corda/node/utilities/JsonSupport.kt +++ b/node/src/main/kotlin/net/corda/node/utilities/JsonSupport.kt @@ -11,11 +11,12 @@ import com.fasterxml.jackson.databind.module.SimpleModule import com.fasterxml.jackson.module.kotlin.KotlinModule import net.corda.core.contracts.BusinessCalendar import net.corda.core.crypto.* +import net.corda.core.messaging.CordaRPCOps import net.corda.core.node.NodeInfo -import net.corda.core.node.services.IdentityService import net.corda.core.serialization.deserialize import net.corda.core.serialization.serialize import net.i2p.crypto.eddsa.EdDSAPublicKey +import net.corda.core.node.services.IdentityService import java.math.BigDecimal import java.time.LocalDate import java.time.LocalDateTime @@ -23,9 +24,25 @@ import java.time.LocalDateTime /** * Utilities and serialisers for working with JSON representations of basic types. This adds Jackson support for * the java.time API, some core types, and Kotlin data classes. + * + * TODO: This does not belong in node. It should be moved to the client module or a dedicated webserver module. */ object JsonSupport { - val javaTimeModule : Module by lazy { + interface PartyObjectMapper { + fun partyFromName(partyName: String): Party? + } + + class RpcObjectMapper(val rpc: CordaRPCOps) : PartyObjectMapper, ObjectMapper() { + override fun partyFromName(partyName: String): Party? = rpc.partyFromName(partyName) + } + class IdentityObjectMapper(val identityService: IdentityService) : PartyObjectMapper, ObjectMapper(){ + override fun partyFromName(partyName: String) = identityService.partyFromName(partyName) + } + class NoPartyObjectMapper: PartyObjectMapper, ObjectMapper() { + override fun partyFromName(partyName: String) = throw UnsupportedOperationException() + } + + val javaTimeModule: Module by lazy { SimpleModule("java.time").apply { addSerializer(LocalDate::class.java, ToStringSerializer) addDeserializer(LocalDate::class.java, LocalDateDeserializer) @@ -34,7 +51,7 @@ object JsonSupport { } } - val cordaModule : Module by lazy { + val cordaModule: Module by lazy { SimpleModule("core").apply { addSerializer(Party::class.java, PartySerializer) addDeserializer(Party::class.java, PartyDeserializer) @@ -61,18 +78,24 @@ object JsonSupport { } } - fun createDefaultMapper(identities: IdentityService): ObjectMapper = - ServiceHubObjectMapper(identities).apply { - enable(SerializationFeature.INDENT_OUTPUT) - enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY) - enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS) + /* Mapper requiring RPC support to deserialise parties from names */ + fun createDefaultMapper(rpc: CordaRPCOps): ObjectMapper = configureMapper(RpcObjectMapper(rpc)) - registerModule(javaTimeModule) - registerModule(cordaModule) - registerModule(KotlinModule()) - } + /* For testing or situations where deserialising parties is not required */ + fun createNonRpcMapper(): ObjectMapper = configureMapper(NoPartyObjectMapper()) - class ServiceHubObjectMapper(val identities: IdentityService) : ObjectMapper() + /* For testing with an in memory identity service */ + fun createInMemoryMapper(identityService: IdentityService) = configureMapper(IdentityObjectMapper(identityService)) + + private fun configureMapper(mapper: ObjectMapper): ObjectMapper = mapper.apply { + enable(SerializationFeature.INDENT_OUTPUT) + enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY) + enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS) + + registerModule(javaTimeModule) + registerModule(cordaModule) + registerModule(KotlinModule()) + } object ToStringSerializer : JsonSerializer() { override fun serialize(obj: Any, generator: JsonGenerator, provider: SerializerProvider) { @@ -108,9 +131,10 @@ object JsonSupport { if (parser.currentToken == JsonToken.FIELD_NAME) { parser.nextToken() } - val mapper = parser.codec as ServiceHubObjectMapper + + val mapper = parser.codec as PartyObjectMapper // TODO this needs to use some industry identifier(s) not just these human readable names - return mapper.identities.partyFromName(parser.text) ?: throw JsonParseException(parser, "Could not find a Party with name: ${parser.text}") + return mapper.partyFromName(parser.text) ?: throw JsonParseException(parser, "Could not find a Party with name ${parser.text}") } } diff --git a/node/src/main/kotlin/net/corda/node/webserver/WebServer.kt b/node/src/main/kotlin/net/corda/node/webserver/WebServer.kt new file mode 100644 index 0000000000..cf9b774231 --- /dev/null +++ b/node/src/main/kotlin/net/corda/node/webserver/WebServer.kt @@ -0,0 +1,179 @@ +package net.corda.node.webserver + +import net.corda.core.messaging.CordaRPCOps +import net.corda.core.node.CordaPluginRegistry +import net.corda.core.utilities.loggerFor +import net.corda.node.printBasicNodeInfo +import net.corda.node.services.config.FullNodeConfiguration +import net.corda.node.services.messaging.ArtemisMessagingComponent +import net.corda.node.services.messaging.CordaRPCClient +import net.corda.node.webserver.internal.APIServerImpl +import net.corda.node.webserver.servlets.AttachmentDownloadServlet +import net.corda.node.webserver.servlets.DataUploadServlet +import net.corda.node.webserver.servlets.ObjectMapperConfig +import net.corda.node.webserver.servlets.ResponseFilter +import org.apache.activemq.artemis.api.core.ActiveMQNotConnectedException +import org.eclipse.jetty.server.* +import org.eclipse.jetty.server.handler.HandlerCollection +import org.eclipse.jetty.servlet.DefaultServlet +import org.eclipse.jetty.servlet.ServletContextHandler +import org.eclipse.jetty.servlet.ServletHolder +import org.eclipse.jetty.util.ssl.SslContextFactory +import org.eclipse.jetty.webapp.WebAppContext +import org.glassfish.jersey.server.ResourceConfig +import org.glassfish.jersey.server.ServerProperties +import org.glassfish.jersey.servlet.ServletContainer +import java.lang.reflect.InvocationTargetException +import java.net.InetAddress +import java.util.* + +// TODO: Split into a separate module under client that packages into WAR formats. +class WebServer(val config: FullNodeConfiguration) { + private companion object { + val log = loggerFor() + val retryDelay = 1000L // Milliseconds + } + + val address = config.webAddress + private lateinit var server: Server + + fun start() { + printBasicNodeInfo("Starting as webserver: ${config.webAddress}") + server = initWebServer(retryConnectLocalRpc()) + } + + fun run() { + while (server.isRunning) { + Thread.sleep(100) // TODO: Redesign + } + } + + private fun initWebServer(localRpc: CordaRPCOps): Server { + // Note that the web server handlers will all run concurrently, and not on the node thread. + val handlerCollection = HandlerCollection() + + // TODO: Move back into the node itself. + // Export JMX monitoring statistics and data over REST/JSON. + if (config.exportJMXto.split(',').contains("http")) { + val classpath = System.getProperty("java.class.path").split(System.getProperty("path.separator")) + val warpath = classpath.firstOrNull { it.contains("jolokia-agent-war-2") && it.endsWith(".war") } + if (warpath != null) { + handlerCollection.addHandler(WebAppContext().apply { + // Find the jolokia WAR file on the classpath. + contextPath = "/monitoring/json" + setInitParameter("mimeType", "application/json") + war = warpath + }) + } else { + log.warn("Unable to locate Jolokia WAR on classpath") + } + } + + // API, data upload and download to services (attachments, rates oracles etc) + handlerCollection.addHandler(buildServletContextHandler(localRpc)) + + val server = Server() + + val connector = if (config.useHTTPS) { + val httpsConfiguration = HttpConfiguration() + httpsConfiguration.outputBufferSize = 32768 + httpsConfiguration.addCustomizer(SecureRequestCustomizer()) + val sslContextFactory = SslContextFactory() + sslContextFactory.keyStorePath = config.keyStoreFile.toString() + sslContextFactory.setKeyStorePassword(config.keyStorePassword) + sslContextFactory.setKeyManagerPassword(config.keyStorePassword) + sslContextFactory.setTrustStorePath(config.trustStoreFile.toString()) + sslContextFactory.setTrustStorePassword(config.trustStorePassword) + sslContextFactory.setExcludeProtocols("SSL.*", "TLSv1", "TLSv1.1") + sslContextFactory.setIncludeProtocols("TLSv1.2") + sslContextFactory.setExcludeCipherSuites(".*NULL.*", ".*RC4.*", ".*MD5.*", ".*DES.*", ".*DSS.*") + sslContextFactory.setIncludeCipherSuites(".*AES.*GCM.*") + val sslConnector = ServerConnector(server, SslConnectionFactory(sslContextFactory, "http/1.1"), HttpConnectionFactory(httpsConfiguration)) + sslConnector.port = address.port + sslConnector + } else { + val httpConfiguration = HttpConfiguration() + httpConfiguration.outputBufferSize = 32768 + val httpConnector = ServerConnector(server, HttpConnectionFactory(httpConfiguration)) + log.info("Starting webserver on address $address") + httpConnector.port = address.port + httpConnector + } + server.connectors = arrayOf(connector) + + server.handler = handlerCollection + //runOnStop += Runnable { server.stop() } + server.start() + log.info("Server started") + log.info("Embedded web server is listening on", "http://${InetAddress.getLocalHost().hostAddress}:${connector.port}/") + return server + } + + private fun buildServletContextHandler(localRpc: CordaRPCOps): ServletContextHandler { + return ServletContextHandler().apply { + contextPath = "/" + setAttribute("rpc", localRpc) + addServlet(DataUploadServlet::class.java, "/upload/*") + addServlet(AttachmentDownloadServlet::class.java, "/attachments/*") + + val resourceConfig = ResourceConfig() + resourceConfig.register(ObjectMapperConfig(localRpc)) + resourceConfig.register(ResponseFilter()) + resourceConfig.register(APIServerImpl(localRpc)) + + val webAPIsOnClasspath = pluginRegistries.flatMap { x -> x.webApis } + for (webapi in webAPIsOnClasspath) { + log.info("Add plugin web API from attachment $webapi") + val customAPI = try { + webapi.apply(localRpc) + } catch (ex: InvocationTargetException) { + log.error("Constructor $webapi threw an error: ", ex.targetException) + continue + } + resourceConfig.register(customAPI) + } + + val staticDirMaps = pluginRegistries.map { x -> x.staticServeDirs } + val staticDirs = staticDirMaps.flatMap { it.keys }.zip(staticDirMaps.flatMap { it.values }) + staticDirs.forEach { + val staticDir = ServletHolder(DefaultServlet::class.java) + staticDir.setInitParameter("resourceBase", it.second) + staticDir.setInitParameter("dirAllowed", "true") + staticDir.setInitParameter("pathInfoOnly", "true") + addServlet(staticDir, "/web/${it.first}/*") + } + + // Give the app a slightly better name in JMX rather than a randomly generated one and enable JMX + resourceConfig.addProperties(mapOf(ServerProperties.APPLICATION_NAME to "node.api", + ServerProperties.MONITORING_STATISTICS_MBEANS_ENABLED to "true")) + + val container = ServletContainer(resourceConfig) + val jerseyServlet = ServletHolder(container) + addServlet(jerseyServlet, "/api/*") + jerseyServlet.initOrder = 0 // Initialise at server start + } + } + + private fun retryConnectLocalRpc(): CordaRPCOps { + while (true) { + try { + return connectLocalRpcAsNodeUser() + } catch (e: ActiveMQNotConnectedException) { + log.debug("Could not connect to ${config.artemisAddress} due to exception: ", e) + Thread.sleep(retryDelay) + } + } + } + + private fun connectLocalRpcAsNodeUser(): CordaRPCOps { + log.info("Connecting to node at ${config.artemisAddress} as node user") + val client = CordaRPCClient(config.artemisAddress, config) + client.start(ArtemisMessagingComponent.NODE_USER, ArtemisMessagingComponent.NODE_USER) + return client.proxy() + } + + /** Fetch CordaPluginRegistry classes registered in META-INF/services/net.corda.core.node.CordaPluginRegistry files that exist in the classpath */ + val pluginRegistries: List by lazy { + ServiceLoader.load(CordaPluginRegistry::class.java).toList() + } +} \ No newline at end of file diff --git a/node/src/main/kotlin/net/corda/node/webserver/api/APIServer.kt b/node/src/main/kotlin/net/corda/node/webserver/api/APIServer.kt new file mode 100644 index 0000000000..0447bbb601 --- /dev/null +++ b/node/src/main/kotlin/net/corda/node/webserver/api/APIServer.kt @@ -0,0 +1,43 @@ +package net.corda.node.webserver.api + +import net.corda.core.node.NodeInfo +import java.time.LocalDateTime +import javax.ws.rs.GET +import javax.ws.rs.Path +import javax.ws.rs.Produces +import javax.ws.rs.core.MediaType +import javax.ws.rs.core.Response + +/** + * Top level interface to external interaction with the distributed ledger. + * + * Wherever a list is returned by a fetchXXX method that corresponds with an input list, that output list will have optional elements + * where a null indicates "missing" and the elements returned will be in the order corresponding with the input list. + * + */ +@Path("") +interface APIServer { + /** + * Report current UTC time as understood by the platform. + */ + @GET + @Path("servertime") + @Produces(MediaType.APPLICATION_JSON) + fun serverTime(): LocalDateTime + + /** + * Report whether this node is started up or not. + */ + @GET + @Path("status") + @Produces(MediaType.TEXT_PLAIN) + fun status(): Response + + /** + * Report this node's configuration and identities. + */ + @GET + @Path("info") + @Produces(MediaType.APPLICATION_JSON) + fun info(): NodeInfo +} \ No newline at end of file diff --git a/node/src/main/kotlin/net/corda/node/api/Query.kt b/node/src/main/kotlin/net/corda/node/webserver/api/Query.kt similarity index 92% rename from node/src/main/kotlin/net/corda/node/api/Query.kt rename to node/src/main/kotlin/net/corda/node/webserver/api/Query.kt index 3772684f77..9d5e34fe1b 100644 --- a/node/src/main/kotlin/net/corda/node/api/Query.kt +++ b/node/src/main/kotlin/net/corda/node/webserver/api/Query.kt @@ -1,4 +1,4 @@ -package net.corda.node.api +package net.corda.node.webserver.api /** * Extremely rudimentary query language which should most likely be replaced with a product. diff --git a/node/src/main/kotlin/net/corda/node/webserver/internal/APIServerImpl.kt b/node/src/main/kotlin/net/corda/node/webserver/internal/APIServerImpl.kt new file mode 100644 index 0000000000..02155c51cc --- /dev/null +++ b/node/src/main/kotlin/net/corda/node/webserver/internal/APIServerImpl.kt @@ -0,0 +1,23 @@ +package net.corda.node.webserver.internal + +import net.corda.core.messaging.CordaRPCOps +import net.corda.node.webserver.api.* +import java.time.LocalDateTime +import java.time.ZoneId +import javax.ws.rs.core.Response + +class APIServerImpl(val rpcOps: CordaRPCOps) : APIServer { + + override fun serverTime(): LocalDateTime { + return LocalDateTime.ofInstant(rpcOps.currentNodeTime(), ZoneId.of("UTC")) + } + + /** + * This endpoint is for polling if the webserver is serving. It will always return 200. + */ + override fun status(): Response { + return Response.ok("started").build() + } + + override fun info() = rpcOps.nodeIdentity() +} diff --git a/node/src/main/kotlin/net/corda/node/servlets/AttachmentDownloadServlet.kt b/node/src/main/kotlin/net/corda/node/webserver/servlets/AttachmentDownloadServlet.kt similarity index 98% rename from node/src/main/kotlin/net/corda/node/servlets/AttachmentDownloadServlet.kt rename to node/src/main/kotlin/net/corda/node/webserver/servlets/AttachmentDownloadServlet.kt index 52cd1e10c7..de40ec9bb4 100644 --- a/node/src/main/kotlin/net/corda/node/servlets/AttachmentDownloadServlet.kt +++ b/node/src/main/kotlin/net/corda/node/webserver/servlets/AttachmentDownloadServlet.kt @@ -1,4 +1,4 @@ -package net.corda.node.servlets +package net.corda.node.webserver.servlets import net.corda.core.crypto.SecureHash import net.corda.core.node.services.StorageService diff --git a/node/src/main/kotlin/net/corda/node/servlets/DataUploadServlet.kt b/node/src/main/kotlin/net/corda/node/webserver/servlets/DataUploadServlet.kt similarity index 59% rename from node/src/main/kotlin/net/corda/node/servlets/DataUploadServlet.kt rename to node/src/main/kotlin/net/corda/node/webserver/servlets/DataUploadServlet.kt index 59b9a02edd..76a337128c 100644 --- a/node/src/main/kotlin/net/corda/node/servlets/DataUploadServlet.kt +++ b/node/src/main/kotlin/net/corda/node/webserver/servlets/DataUploadServlet.kt @@ -1,5 +1,6 @@ -package net.corda.node.servlets +package net.corda.node.webserver.servlets +import net.corda.core.messaging.CordaRPCOps import net.corda.core.utilities.loggerFor import net.corda.node.internal.Node import net.corda.node.services.api.AcceptsFileUpload @@ -12,26 +13,19 @@ import javax.servlet.http.HttpServletResponse /** * Accepts binary streams, finds the right [AcceptsFileUpload] implementor and hands the stream off to it. */ -class DataUploadServlet : HttpServlet() { +class DataUploadServlet: HttpServlet() { private val log = loggerFor() override fun doPost(req: HttpServletRequest, resp: HttpServletResponse) { - val node = servletContext.getAttribute("node") as Node - @Suppress("DEPRECATION") // Bogus warning due to superclass static method being deprecated. val isMultipart = ServletFileUpload.isMultipartContent(req) + val rpc = servletContext.getAttribute("rpc") as CordaRPCOps if (!isMultipart) { resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "This end point is for data uploads only.") return } - val acceptor: AcceptsFileUpload? = findAcceptor(node, req) - if (acceptor == null) { - resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Got a file upload request for an unknown data type") - return - } - val upload = ServletFileUpload() val iterator = upload.getItemIterator(req) val messages = ArrayList() @@ -43,18 +37,15 @@ class DataUploadServlet : HttpServlet() { while (iterator.hasNext()) { val item = iterator.next() - if (item.name != null && !acceptor.acceptableFileExtensions.any { item.name.endsWith(it) }) { - resp.sendError(HttpServletResponse.SC_BAD_REQUEST, - "${item.name}: Must be have a filename ending in one of: ${acceptor.acceptableFileExtensions}") - return - } - log.info("Receiving ${item.name}") - item.openStream().use { - val message = acceptor.upload(it) - log.info("${item.name} successfully accepted: $message") - messages += message + try { + val dataType = req.pathInfo.substring(1).substringBefore('/') + messages += rpc.uploadFile(dataType, item.name, item.openStream()) + log.info("${item.name} successfully accepted: ${messages.last()}") + } catch(e: RuntimeException) { + println(e) + resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Got a file upload request for an unknown data type") } } @@ -62,8 +53,4 @@ class DataUploadServlet : HttpServlet() { val writer = resp.writer messages.forEach { writer.println(it) } } - - private fun findAcceptor(node: Node, req: HttpServletRequest): AcceptsFileUpload? { - return node.servicesThatAcceptUploads.firstOrNull { req.pathInfo.substring(1).substringBefore('/') == it.dataTypePrefix } - } } diff --git a/node/src/main/kotlin/net/corda/node/servlets/Config.kt b/node/src/main/kotlin/net/corda/node/webserver/servlets/ObjectMapperConfig.kt similarity index 67% rename from node/src/main/kotlin/net/corda/node/servlets/Config.kt rename to node/src/main/kotlin/net/corda/node/webserver/servlets/ObjectMapperConfig.kt index 69b59cae85..78dbd1b131 100644 --- a/node/src/main/kotlin/net/corda/node/servlets/Config.kt +++ b/node/src/main/kotlin/net/corda/node/webserver/servlets/ObjectMapperConfig.kt @@ -1,6 +1,7 @@ -package net.corda.node.servlets +package net.corda.node.webserver.servlets import com.fasterxml.jackson.databind.ObjectMapper +import net.corda.core.messaging.CordaRPCOps import net.corda.core.node.ServiceHub import net.corda.node.utilities.JsonSupport import javax.ws.rs.ext.ContextResolver @@ -11,7 +12,7 @@ import javax.ws.rs.ext.Provider * and to organise serializers / deserializers for java.time.* classes as necessary. */ @Provider -class Config(val services: ServiceHub) : ContextResolver { - val defaultObjectMapper = JsonSupport.createDefaultMapper(services.identityService) +class ObjectMapperConfig(rpc: CordaRPCOps) : ContextResolver { + val defaultObjectMapper = JsonSupport.createDefaultMapper(rpc) override fun getContext(type: Class<*>) = defaultObjectMapper } diff --git a/node/src/main/kotlin/net/corda/node/servlets/ResponseFilter.kt b/node/src/main/kotlin/net/corda/node/webserver/servlets/ResponseFilter.kt similarity index 96% rename from node/src/main/kotlin/net/corda/node/servlets/ResponseFilter.kt rename to node/src/main/kotlin/net/corda/node/webserver/servlets/ResponseFilter.kt index e39eb97b95..6700b8bb0a 100644 --- a/node/src/main/kotlin/net/corda/node/servlets/ResponseFilter.kt +++ b/node/src/main/kotlin/net/corda/node/webserver/servlets/ResponseFilter.kt @@ -1,4 +1,4 @@ -package net.corda.node.servlets +package net.corda.node.webserver.servlets import javax.ws.rs.container.ContainerRequestContext import javax.ws.rs.container.ContainerResponseContext diff --git a/node/src/test/kotlin/net/corda/node/ArgsParserTest.kt b/node/src/test/kotlin/net/corda/node/ArgsParserTest.kt index 224a0a540b..c143da1680 100644 --- a/node/src/test/kotlin/net/corda/node/ArgsParserTest.kt +++ b/node/src/test/kotlin/net/corda/node/ArgsParserTest.kt @@ -17,7 +17,8 @@ class ArgsParserTest { baseDirectory = workingDirectory, configFile = workingDirectory / "node.conf", help = false, - logToConsole = false)) + logToConsole = false, + isWebserver = false)) } @Test @@ -28,7 +29,8 @@ class ArgsParserTest { baseDirectory = expectedBaseDir, configFile = expectedBaseDir / "node.conf", help = false, - logToConsole = false)) + logToConsole = false, + isWebserver = false)) } @Test @@ -39,7 +41,8 @@ class ArgsParserTest { baseDirectory = baseDirectory, configFile = baseDirectory / "node.conf", help = false, - logToConsole = false)) + logToConsole = false, + isWebserver = false)) } @Test @@ -49,7 +52,8 @@ class ArgsParserTest { baseDirectory = workingDirectory, configFile = workingDirectory / "different.conf", help = false, - logToConsole = false)) + logToConsole = false, + isWebserver = false)) } @Test @@ -60,7 +64,19 @@ class ArgsParserTest { baseDirectory = workingDirectory, configFile = configFile, help = false, - logToConsole = false)) + logToConsole = false, + isWebserver = false)) + } + + @Test + fun `just webserver `() { + val cmdLineOptions = parser.parse("--webserver") + assertThat(cmdLineOptions).isEqualTo(CmdLineOptions( + baseDirectory = workingDirectory, + configFile = workingDirectory / "node.conf", + help = false, + logToConsole = false, + isWebserver = true)) } @Test diff --git a/node/src/test/kotlin/net/corda/node/JsonSupportTest.kt b/node/src/test/kotlin/net/corda/node/JsonSupportTest.kt index bb9f5f66ab..7248f4fb7e 100644 --- a/node/src/test/kotlin/net/corda/node/JsonSupportTest.kt +++ b/node/src/test/kotlin/net/corda/node/JsonSupportTest.kt @@ -15,7 +15,7 @@ import kotlin.test.assertEquals class JsonSupportTest { companion object { - val mapper = JsonSupport.createDefaultMapper(MockIdentityService(mutableListOf())) + val mapper = JsonSupport.createNonRpcMapper() } @Property diff --git a/node/src/test/kotlin/net/corda/node/messaging/AttachmentTests.kt b/node/src/test/kotlin/net/corda/node/messaging/AttachmentTests.kt index 94c4856486..8ace2bbc3f 100644 --- a/node/src/test/kotlin/net/corda/node/messaging/AttachmentTests.kt +++ b/node/src/test/kotlin/net/corda/node/messaging/AttachmentTests.kt @@ -14,11 +14,14 @@ import net.corda.node.services.network.NetworkMapService import net.corda.node.services.persistence.NodeAttachmentService import net.corda.node.services.transactions.SimpleNotaryService import net.corda.testing.node.MockNetwork +import net.i2p.crypto.eddsa.KeyPairGenerator import org.junit.Before import org.junit.Test import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream +import java.math.BigInteger import java.security.KeyPair +import java.security.KeyPairGeneratorSpi import java.util.jar.JarOutputStream import java.util.zip.ZipEntry import kotlin.test.assertEquals @@ -84,8 +87,10 @@ class AttachmentTests { // Make a node that doesn't do sanity checking at load time. val n0 = network.createNode(null, -1, object : MockNetwork.Factory { override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?, - advertisedServices: Set, id: Int, keyPair: KeyPair?): MockNetwork.MockNode { - return object : MockNetwork.MockNode(config, network, networkMapAddr, advertisedServices, id, keyPair) { + advertisedServices: Set, id: Int, + overrideServices: Map?, + entropyRoot: BigInteger): MockNetwork.MockNode { + return object : MockNetwork.MockNode(config, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot) { override fun start(): MockNetwork.MockNode { super.start() (storage.attachments as NodeAttachmentService).checkAttachmentsOnLoad = false 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 06370a7449..b469f33c79 100644 --- a/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt +++ b/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt @@ -20,7 +20,6 @@ import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.TransactionBuilder import net.corda.core.transactions.WireTransaction import net.corda.core.utilities.DUMMY_NOTARY -import net.corda.core.utilities.DUMMY_NOTARY_KEY import net.corda.core.utilities.LogHelper import net.corda.core.utilities.TEST_TX_TIME import net.corda.flows.TwoPartyTradeFlow.Buyer @@ -43,6 +42,7 @@ import org.junit.Test import rx.Observable import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream +import java.math.BigInteger import java.security.KeyPair import java.util.* import java.util.concurrent.Future @@ -60,9 +60,6 @@ import kotlin.test.assertTrue */ class TwoPartyTradeFlowTests { lateinit var net: MockNetwork - lateinit var notaryNode: MockNetwork.MockNode - lateinit var aliceNode: MockNetwork.MockNode - lateinit var bobNode: MockNetwork.MockNode @Before fun before() { @@ -84,9 +81,9 @@ class TwoPartyTradeFlowTests { net = MockNetwork(false, true) ledger { - notaryNode = net.createNotaryNode(null, DUMMY_NOTARY.name, DUMMY_NOTARY_KEY) - aliceNode = net.createPartyNode(notaryNode.info.address, ALICE.name, ALICE_KEY) - bobNode = net.createPartyNode(notaryNode.info.address, BOB.name, BOB_KEY) + 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 aliceKey = aliceNode.services.legalIdentityKey val notaryKey = notaryNode.services.notaryIdentityKey @@ -99,9 +96,10 @@ class TwoPartyTradeFlowTests { val alicesFakePaper = fillUpForSeller(false, aliceNode.info.legalIdentity.owningKey, 1200.DOLLARS `issued by` DUMMY_CASH_ISSUER, null, notaryNode.info.notaryIdentity).second - insertFakeTransactions(alicesFakePaper, aliceNode, aliceKey, notaryKey) + insertFakeTransactions(alicesFakePaper, aliceNode, notaryNode, aliceKey, notaryKey) - val (bobStateMachine, aliceResult) = runBuyerAndSeller("alice's paper".outputStateAndRef()) + val (bobStateMachine, aliceResult) = runBuyerAndSeller(notaryNode, aliceNode, bobNode, + "alice's paper".outputStateAndRef()) // TODO: Verify that the result was inserted into the transaction database. // assertEquals(bobResult.get(), aliceNode.storage.validatedTransactions[aliceResult.get().id]) @@ -124,9 +122,9 @@ class TwoPartyTradeFlowTests { @Test fun `shutdown and restore`() { ledger { - notaryNode = net.createNotaryNode(null, DUMMY_NOTARY.name, DUMMY_NOTARY_KEY) - aliceNode = net.createPartyNode(notaryNode.info.address, ALICE.name, ALICE_KEY) - bobNode = net.createPartyNode(notaryNode.info.address, BOB.name, BOB_KEY) + val notaryNode = net.createNotaryNode(null, DUMMY_NOTARY.name) + val aliceNode = net.createPartyNode(notaryNode.info.address, ALICE.name) + var bobNode = net.createPartyNode(notaryNode.info.address, BOB.name) aliceNode.disableDBCloseOnStop() bobNode.disableDBCloseOnStop() val aliceKey = aliceNode.services.legalIdentityKey @@ -142,8 +140,8 @@ class TwoPartyTradeFlowTests { } val alicesFakePaper = fillUpForSeller(false, aliceNode.info.legalIdentity.owningKey, 1200.DOLLARS `issued by` DUMMY_CASH_ISSUER, null, notaryNode.info.notaryIdentity).second - insertFakeTransactions(alicesFakePaper, aliceNode, aliceKey, notaryKey) - val aliceFuture = runBuyerAndSeller("alice's paper".outputStateAndRef()).sellerResult + insertFakeTransactions(alicesFakePaper, aliceNode, notaryNode, aliceKey, notaryKey) + val aliceFuture = runBuyerAndSeller(notaryNode, aliceNode, bobNode, "alice's paper".outputStateAndRef()).sellerResult // Everything is on this thread so we can now step through the flow one step at a time. // Seller Alice already sent a message to Buyer Bob. Pump once: @@ -179,10 +177,11 @@ class TwoPartyTradeFlowTests { // that Bob was waiting on before the reboot occurred. bobNode = net.createNode(networkMapAddr, bobAddr.id, object : MockNetwork.Factory { override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?, - advertisedServices: Set, id: Int, keyPair: KeyPair?): MockNetwork.MockNode { - return MockNetwork.MockNode(config, network, networkMapAddr, advertisedServices, bobAddr.id, BOB_KEY) + advertisedServices: Set, id: Int, overrideServices: Map?, + entropyRoot: BigInteger): MockNetwork.MockNode { + return MockNetwork.MockNode(config, network, networkMapAddr, advertisedServices, bobAddr.id, overrideServices, entropyRoot) } - }, true, BOB.name, BOB_KEY) + }, true, BOB.name) // Find the future representing the result of this state machine again. val bobFuture = bobNode.smm.findStateMachines(Buyer::class.java).single().second @@ -213,12 +212,16 @@ class TwoPartyTradeFlowTests { // Creates a mock node with an overridden storage service that uses a RecordingMap, that lets us test the order // of gets and puts. - private fun makeNodeWithTracking(networkMapAddr: SingleMessageRecipient?, name: String, keyPair: KeyPair): MockNetwork.MockNode { + private fun makeNodeWithTracking(networkMapAddr: SingleMessageRecipient?, name: String, overrideServices: Map? = null): MockNetwork.MockNode { // Create a node in the mock network ... return net.createNode(networkMapAddr, -1, object : MockNetwork.Factory { - override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?, - advertisedServices: Set, id: Int, keyPair: KeyPair?): MockNetwork.MockNode { - return object : MockNetwork.MockNode(config, network, networkMapAddr, advertisedServices, id, keyPair) { + override fun create(config: NodeConfiguration, + network: MockNetwork, + networkMapAddr: SingleMessageRecipient?, + advertisedServices: Set, id: Int, + overrideServices: Map?, + entropyRoot: BigInteger): MockNetwork.MockNode { + return object : MockNetwork.MockNode(config, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot) { // That constructs the storage service object in a customised way ... override fun constructStorageService( attachments: NodeAttachmentService, @@ -229,14 +232,14 @@ class TwoPartyTradeFlowTests { } } } - }, true, name, keyPair) + }, true, name, overrideServices) } @Test fun `check dependencies of sale asset are resolved`() { - notaryNode = net.createNotaryNode(null, DUMMY_NOTARY.name, DUMMY_NOTARY_KEY) - aliceNode = makeNodeWithTracking(notaryNode.info.address, ALICE.name, ALICE_KEY) - bobNode = makeNodeWithTracking(notaryNode.info.address, BOB.name, BOB_KEY) + val notaryNode = net.createNotaryNode(null, DUMMY_NOTARY.name) + val aliceNode = makeNodeWithTracking(notaryNode.info.address, ALICE.name) + val bobNode = makeNodeWithTracking(notaryNode.info.address, BOB.name) val aliceKey = aliceNode.services.legalIdentityKey ledger(aliceNode.services) { @@ -250,15 +253,18 @@ class TwoPartyTradeFlowTests { } val attachmentID = attachment(ByteArrayInputStream(stream.toByteArray())) - val bobsFakeCash = fillUpForBuyer(false, bobNode.keyManagement.freshKey().public.composite, notaryNode.info.notaryIdentity).second - val bobsSignedTxns = insertFakeTransactions(bobsFakeCash, bobNode) + val extraKey = bobNode.keyManagement.freshKey() + val bobsFakeCash = fillUpForBuyer(false, extraKey.public.composite, + DUMMY_CASH_ISSUER.party, + notaryNode.info.notaryIdentity).second + val bobsSignedTxns = insertFakeTransactions(bobsFakeCash, bobNode, notaryNode, bobNode.services.legalIdentityKey, extraKey) val alicesFakePaper = fillUpForSeller(false, aliceNode.info.legalIdentity.owningKey, 1200.DOLLARS `issued by` DUMMY_CASH_ISSUER, attachmentID, notaryNode.info.notaryIdentity).second - val alicesSignedTxns = insertFakeTransactions(alicesFakePaper, aliceNode, aliceKey) + val alicesSignedTxns = insertFakeTransactions(alicesFakePaper, aliceNode, notaryNode, aliceKey) net.runNetwork() // Clear network map registration messages - runBuyerAndSeller("alice's paper".outputStateAndRef()) + runBuyerAndSeller(notaryNode, aliceNode, bobNode, "alice's paper".outputStateAndRef()) net.runNetwork() @@ -326,9 +332,9 @@ class TwoPartyTradeFlowTests { @Test fun `track() works`() { - notaryNode = net.createNotaryNode(null, DUMMY_NOTARY.name, DUMMY_NOTARY_KEY) - aliceNode = makeNodeWithTracking(notaryNode.info.address, ALICE.name, ALICE_KEY) - bobNode = makeNodeWithTracking(notaryNode.info.address, BOB.name, BOB_KEY) + val notaryNode = net.createNotaryNode(null, DUMMY_NOTARY.name) + val aliceNode = makeNodeWithTracking(notaryNode.info.address, ALICE.name) + val bobNode = makeNodeWithTracking(notaryNode.info.address, BOB.name) val aliceKey = aliceNode.services.legalIdentityKey ledger(aliceNode.services) { @@ -342,11 +348,13 @@ class TwoPartyTradeFlowTests { } val attachmentID = attachment(ByteArrayInputStream(stream.toByteArray())) - val bobsFakeCash = fillUpForBuyer(false, bobNode.keyManagement.freshKey().public.composite, notaryNode.info.notaryIdentity).second - insertFakeTransactions(bobsFakeCash, bobNode) + val bobsFakeCash = fillUpForBuyer(false, bobNode.keyManagement.freshKey().public.composite, + DUMMY_CASH_ISSUER.party, + notaryNode.info.notaryIdentity).second + insertFakeTransactions(bobsFakeCash, bobNode, notaryNode) val alicesFakePaper = fillUpForSeller(false, aliceNode.info.legalIdentity.owningKey, 1200.DOLLARS `issued by` DUMMY_CASH_ISSUER, attachmentID, notaryNode.info.notaryIdentity).second - insertFakeTransactions(alicesFakePaper, aliceNode, aliceKey) + insertFakeTransactions(alicesFakePaper, aliceNode, notaryNode, aliceKey) net.runNetwork() // Clear network map registration messages @@ -356,7 +364,8 @@ class TwoPartyTradeFlowTests { val aliceTxMappings = databaseTransaction(aliceNode.database) { aliceMappingsStorage.track().second } - val aliceSmId = runBuyerAndSeller("alice's paper".outputStateAndRef()).sellerId + val aliceSmId = runBuyerAndSeller(notaryNode, aliceNode, bobNode, + "alice's paper".outputStateAndRef()).sellerId net.runNetwork() @@ -412,12 +421,15 @@ class TwoPartyTradeFlowTests { val sellerId: StateMachineRunId ) - private fun runBuyerAndSeller(assetToSell: StateAndRef): RunResult { - val buyerFuture = bobNode.initiateSingleShotFlow(Seller::class) { otherParty -> + private fun runBuyerAndSeller(notaryNode: MockNetwork.MockNode, + sellerNode: MockNetwork.MockNode, + buyerNode: MockNetwork.MockNode, + assetToSell: StateAndRef): RunResult { + val buyerFuture = buyerNode.initiateSingleShotFlow(Seller::class) { otherParty -> Buyer(otherParty, notaryNode.info.notaryIdentity, 1000.DOLLARS, CommercialPaper.State::class.java) }.map { it.stateMachine } - val seller = Seller(bobNode.info.legalIdentity, notaryNode.info, assetToSell, 1000.DOLLARS, ALICE_KEY) - val sellerResultFuture = aliceNode.services.startFlow(seller).resultFuture + val seller = Seller(buyerNode.info.legalIdentity, notaryNode.info, assetToSell, 1000.DOLLARS, sellerNode.services.legalIdentityKey) + val sellerResultFuture = sellerNode.services.startFlow(seller).resultFuture return RunResult(buyerFuture, sellerResultFuture, seller.stateMachine.id) } @@ -426,23 +438,24 @@ class TwoPartyTradeFlowTests { aliceError: Boolean, expectedMessageSubstring: String ) { - notaryNode = net.createNotaryNode(null, DUMMY_NOTARY.name, DUMMY_NOTARY_KEY) - aliceNode = net.createPartyNode(notaryNode.info.address, ALICE.name, ALICE_KEY) - bobNode = net.createPartyNode(notaryNode.info.address, BOB.name, BOB_KEY) + 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 aliceKey = aliceNode.services.legalIdentityKey val bobKey = bobNode.services.legalIdentityKey val issuer = MEGA_CORP.ref(1, 2, 3) - val bobsBadCash = fillUpForBuyer(bobError, bobKey.public.composite, notaryNode.info.notaryIdentity).second + val bobsBadCash = fillUpForBuyer(bobError, bobKey.public.composite, DUMMY_CASH_ISSUER.party, + notaryNode.info.notaryIdentity).second val alicesFakePaper = fillUpForSeller(aliceError, aliceNode.info.legalIdentity.owningKey, 1200.DOLLARS `issued by` issuer, null, notaryNode.info.notaryIdentity).second - insertFakeTransactions(bobsBadCash, bobNode, bobKey) - insertFakeTransactions(alicesFakePaper, aliceNode, aliceKey) + insertFakeTransactions(bobsBadCash, bobNode, notaryNode, bobKey) + insertFakeTransactions(alicesFakePaper, aliceNode, notaryNode, aliceKey) net.runNetwork() // Clear network map registration messages - val (bobStateMachine, aliceResult) = runBuyerAndSeller("alice's paper".outputStateAndRef()) + val (bobStateMachine, aliceResult) = runBuyerAndSeller(notaryNode, aliceNode, bobNode, "alice's paper".outputStateAndRef()) net.runNetwork() @@ -461,9 +474,10 @@ class TwoPartyTradeFlowTests { private fun insertFakeTransactions( wtxToSign: List, node: AbstractNode, + notaryNode: MockNetwork.MockNode, vararg extraKeys: KeyPair): Map { + val signed: List = signAll(wtxToSign, extraKeys.toList() + notaryNode.services.notaryIdentityKey + DUMMY_CASH_ISSUER_KEY) return databaseTransaction(node.database) { - val signed: List = signAll(wtxToSign, extraKeys.toList() + DUMMY_CASH_ISSUER_KEY) node.services.recordTransactions(signed) val validatedTransactions = node.services.storageService.validatedTransactions if (validatedTransactions is RecordingTransactionStorage) { @@ -475,20 +489,21 @@ class TwoPartyTradeFlowTests { private fun LedgerDSL.fillUpForBuyer( withError: Boolean, - owner: CompositeKey = BOB_PUBKEY, + owner: CompositeKey, + issuer: Party, notary: Party): Pair> { - val issuer = DUMMY_CASH_ISSUER + val interimOwnerKey = MEGA_CORP_PUBKEY // Bob (Buyer) has some cash he got from the Bank of Elbonia, Alice (Seller) has some commercial paper she // wants to sell to Bob. val eb1 = transaction(transactionBuilder = TransactionBuilder(notary = notary)) { // Issued money to itself. - output("elbonian money 1", notary = notary) { 800.DOLLARS.CASH `issued by` issuer `owned by` MEGA_CORP_PUBKEY } - output("elbonian money 2", notary = notary) { 1000.DOLLARS.CASH `issued by` issuer `owned by` MEGA_CORP_PUBKEY } + output("elbonian money 1", notary = notary) { 800.DOLLARS.CASH `issued by` issuer `owned by` interimOwnerKey } + output("elbonian money 2", notary = notary) { 1000.DOLLARS.CASH `issued by` issuer `owned by` interimOwnerKey } if (!withError) { - command(DUMMY_CASH_ISSUER_KEY.public.composite) { Cash.Commands.Issue() } + command(issuer.owningKey) { Cash.Commands.Issue() } } else { // Put a broken command on so at least a signature is created - command(DUMMY_CASH_ISSUER_KEY.public.composite) { Cash.Commands.Move() } + command(issuer.owningKey) { Cash.Commands.Move() } } timestamp(TEST_TX_TIME) if (withError) { @@ -502,15 +517,15 @@ class TwoPartyTradeFlowTests { val bc1 = transaction(transactionBuilder = TransactionBuilder(notary = notary)) { input("elbonian money 1") output("bob cash 1", notary = notary) { 800.DOLLARS.CASH `issued by` issuer `owned by` owner } - command(MEGA_CORP_PUBKEY) { Cash.Commands.Move() } + command(interimOwnerKey) { Cash.Commands.Move() } this.verifies() } val bc2 = transaction(transactionBuilder = TransactionBuilder(notary = notary)) { input("elbonian money 2") output("bob cash 2", notary = notary) { 300.DOLLARS.CASH `issued by` issuer `owned by` owner } - output(notary = notary) { 700.DOLLARS.CASH `issued by` issuer `owned by` MEGA_CORP_PUBKEY } // Change output. - command(MEGA_CORP_PUBKEY) { Cash.Commands.Move() } + output(notary = notary) { 700.DOLLARS.CASH `issued by` issuer `owned by` interimOwnerKey } // Change output. + command(interimOwnerKey) { Cash.Commands.Move() } this.verifies() } diff --git a/node/src/test/kotlin/net/corda/node/services/InMemoryNetworkMapCacheTest.kt b/node/src/test/kotlin/net/corda/node/services/InMemoryNetworkMapCacheTest.kt index 86e0cc0ba1..bee9b114f2 100644 --- a/node/src/test/kotlin/net/corda/node/services/InMemoryNetworkMapCacheTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/InMemoryNetworkMapCacheTest.kt @@ -1,7 +1,5 @@ package net.corda.node.services -import net.corda.core.crypto.composite -import net.corda.core.crypto.generateKeyPair import net.corda.core.getOrThrow import net.corda.core.node.services.ServiceInfo import net.corda.node.services.network.NetworkMapService @@ -9,6 +7,7 @@ import net.corda.node.utilities.databaseTransaction import net.corda.testing.expect import net.corda.testing.node.MockNetwork import org.junit.Test +import java.math.BigInteger import kotlin.test.assertEquals class InMemoryNetworkMapCacheTest { @@ -24,19 +23,23 @@ class InMemoryNetworkMapCacheTest { @Test fun `key collision`() { - val keyPair = generateKeyPair() - val nodeA = network.createNode(null, -1, MockNetwork.DefaultFactory, true, "Node A", keyPair, ServiceInfo(NetworkMapService.type)) - val nodeB = network.createNode(null, -1, MockNetwork.DefaultFactory, true, "Node B", keyPair, ServiceInfo(NetworkMapService.type)) + val entropy = BigInteger.valueOf(24012017L) + val nodeA = network.createNode(null, -1, MockNetwork.DefaultFactory, true, "Node A", null, entropy, ServiceInfo(NetworkMapService.type)) + val nodeB = network.createNode(null, -1, MockNetwork.DefaultFactory, true, "Node B", null, entropy, ServiceInfo(NetworkMapService.type)) + assertEquals(nodeA.info.legalIdentity, nodeB.info.legalIdentity) // Node A currently knows only about itself, so this returns node A - assertEquals(nodeA.netMapCache.getNodeByLegalIdentityKey(keyPair.public.composite), nodeA.info) + assertEquals(nodeA.netMapCache.getNodeByLegalIdentityKey(nodeA.info.legalIdentity.owningKey), nodeA.info) databaseTransaction(nodeA.database) { nodeA.netMapCache.addNode(nodeB.info) } // Now both nodes match, so it throws an error expect { - nodeA.netMapCache.getNodeByLegalIdentityKey(keyPair.public.composite) + nodeA.netMapCache.getNodeByLegalIdentityKey(nodeA.info.legalIdentity.owningKey) + } + expect { + nodeA.netMapCache.getNodeByLegalIdentityKey(nodeB.info.legalIdentity.owningKey) } } } 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 d6e67f452c..3aef650af2 100644 --- a/node/src/test/kotlin/net/corda/node/services/NotaryChangeTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/NotaryChangeTests.kt @@ -11,18 +11,16 @@ import net.corda.core.utilities.DUMMY_NOTARY import net.corda.core.utilities.DUMMY_NOTARY_KEY import net.corda.flows.NotaryChangeFlow.Instigator import net.corda.flows.StateReplacementException -import net.corda.flows.StateReplacementRefused import net.corda.node.internal.AbstractNode import net.corda.node.services.network.NetworkMapService import net.corda.node.services.transactions.SimpleNotaryService import net.corda.testing.node.MockNetwork -import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.Before import org.junit.Test import java.time.Instant import java.util.* import kotlin.test.assertEquals -import kotlin.test.assertFailsWith import kotlin.test.assertTrue class NotaryChangeTests { @@ -37,7 +35,6 @@ class NotaryChangeTests { net = MockNetwork() oldNotaryNode = net.createNode( legalName = DUMMY_NOTARY.name, - keyPair = DUMMY_NOTARY_KEY, advertisedServices = *arrayOf(ServiceInfo(NetworkMapService.type), ServiceInfo(SimpleNotaryService.type))) clientNodeA = net.createNode(networkMapAddress = oldNotaryNode.info.address) clientNodeB = net.createNode(networkMapAddress = oldNotaryNode.info.address) @@ -84,8 +81,9 @@ class NotaryChangeTests { net.runNetwork() - val ex = assertFailsWith(StateReplacementException::class) { future.resultFuture.getOrThrow() } - assertThat(ex.error).isInstanceOf(StateReplacementRefused::class.java) + assertThatExceptionOfType(StateReplacementException::class.java).isThrownBy { + future.resultFuture.getOrThrow() + } } @Test diff --git a/node/src/test/kotlin/net/corda/node/services/NotaryServiceTests.kt b/node/src/test/kotlin/net/corda/node/services/NotaryServiceTests.kt index 077e56fa74..619a71e0c1 100644 --- a/node/src/test/kotlin/net/corda/node/services/NotaryServiceTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/NotaryServiceTests.kt @@ -23,6 +23,7 @@ import net.corda.testing.node.MockNetwork import org.assertj.core.api.Assertions.assertThat import org.junit.Before import org.junit.Test +import java.security.KeyPair import java.time.Instant import java.util.* import kotlin.test.assertEquals @@ -32,14 +33,15 @@ class NotaryServiceTests { lateinit var net: MockNetwork lateinit var notaryNode: MockNetwork.MockNode lateinit var clientNode: MockNetwork.MockNode + lateinit var clientKeyPair: KeyPair @Before fun setup() { net = MockNetwork() notaryNode = net.createNode( legalName = DUMMY_NOTARY.name, - keyPair = DUMMY_NOTARY_KEY, advertisedServices = *arrayOf(ServiceInfo(NetworkMapService.type), ServiceInfo(SimpleNotaryService.type))) - clientNode = net.createNode(networkMapAddress = notaryNode.info.address, keyPair = MINI_CORP_KEY) + clientNode = net.createNode(networkMapAddress = notaryNode.info.address) + clientKeyPair = clientNode.keyManagement.toKeyPair(clientNode.info.legalIdentity.owningKey.keys.single()) net.runNetwork() // Clear network map registration messages } @@ -48,7 +50,7 @@ class NotaryServiceTests { val inputState = issueState(clientNode) val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState) tx.setTime(Instant.now(), 30.seconds) - tx.signWith(clientNode.keyPair!!) + tx.signWith(clientKeyPair) tx.toSignedTransaction(false) } @@ -61,7 +63,7 @@ class NotaryServiceTests { val stx = run { val inputState = issueState(clientNode) val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState) - tx.signWith(clientNode.keyPair!!) + tx.signWith(clientKeyPair) tx.toSignedTransaction(false) } @@ -75,7 +77,7 @@ class NotaryServiceTests { val inputState = issueState(clientNode) val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState) tx.setTime(Instant.now().plusSeconds(3600), 30.seconds) - tx.signWith(clientNode.keyPair!!) + tx.signWith(clientKeyPair) tx.toSignedTransaction(false) } @@ -89,7 +91,7 @@ class NotaryServiceTests { val stx = run { val inputState = issueState(clientNode) val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState) - tx.signWith(clientNode.keyPair!!) + tx.signWith(clientKeyPair) tx.toSignedTransaction(false) } @@ -107,13 +109,13 @@ class NotaryServiceTests { val inputState = issueState(clientNode) val stx = run { val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState) - tx.signWith(clientNode.keyPair!!) + tx.signWith(clientKeyPair) tx.toSignedTransaction(false) } val stx2 = run { val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState) tx.addInputState(issueState(clientNode)) - tx.signWith(clientNode.keyPair!!) + tx.signWith(clientKeyPair) tx.toSignedTransaction(false) } diff --git a/node/src/test/kotlin/net/corda/node/services/PersistentNetworkMapServiceTest.kt b/node/src/test/kotlin/net/corda/node/services/PersistentNetworkMapServiceTest.kt index 0f06eab263..aa3f73a90e 100644 --- a/node/src/test/kotlin/net/corda/node/services/PersistentNetworkMapServiceTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/PersistentNetworkMapServiceTest.kt @@ -14,7 +14,9 @@ import net.corda.testing.node.MockNetwork import org.junit.After import org.junit.Before import org.junit.Test +import java.math.BigInteger import java.security.KeyPair +import java.security.KeyPairGeneratorSpi /** * This class mirrors [InMemoryNetworkMapServiceTest] but switches in a [PersistentNetworkMapService] and @@ -55,8 +57,10 @@ class PersistentNetworkMapServiceTest : AbstractNetworkMapServiceTest() { private object NodeFactory : MockNetwork.Factory { override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?, - advertisedServices: Set, id: Int, keyPair: KeyPair?): MockNetwork.MockNode { - return object : MockNetwork.MockNode(config, network, networkMapAddr, advertisedServices, id, keyPair) { + advertisedServices: Set, id: Int, + overrideServices: Map?, + entropyRoot: BigInteger): MockNetwork.MockNode { + return object : MockNetwork.MockNode(config, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot) { override fun makeNetworkMapService() { inNodeNetworkMapService = SwizzleNetworkMapService(services) diff --git a/node/src/test/kotlin/net/corda/node/services/ScheduledFlowTests.kt b/node/src/test/kotlin/net/corda/node/services/ScheduledFlowTests.kt index dd1f47b1ee..b3545fccff 100644 --- a/node/src/test/kotlin/net/corda/node/services/ScheduledFlowTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/ScheduledFlowTests.kt @@ -98,7 +98,6 @@ class ScheduledFlowTests { net = MockNetwork(threadPerNode = true) notaryNode = net.createNode( legalName = DUMMY_NOTARY.name, - keyPair = DUMMY_NOTARY_KEY, advertisedServices = *arrayOf(ServiceInfo(NetworkMapService.type), ServiceInfo(ValidatingNotaryService.type))) nodeA = net.createNode(notaryNode.info.address, start = false) nodeB = net.createNode(notaryNode.info.address, start = false) diff --git a/node/src/test/kotlin/net/corda/node/services/ValidatingNotaryServiceTests.kt b/node/src/test/kotlin/net/corda/node/services/ValidatingNotaryServiceTests.kt index ee2c1f5c3b..2228443f9f 100644 --- a/node/src/test/kotlin/net/corda/node/services/ValidatingNotaryServiceTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/ValidatingNotaryServiceTests.kt @@ -34,10 +34,9 @@ class ValidatingNotaryServiceTests { net = MockNetwork() notaryNode = net.createNode( legalName = DUMMY_NOTARY.name, - keyPair = DUMMY_NOTARY_KEY, advertisedServices = *arrayOf(ServiceInfo(NetworkMapService.type), ServiceInfo(ValidatingNotaryService.type)) ) - clientNode = net.createNode(networkMapAddress = notaryNode.info.address, keyPair = MINI_CORP_KEY) + clientNode = net.createNode(networkMapAddress = notaryNode.info.address) net.runNetwork() // Clear network map registration messages } @@ -45,7 +44,8 @@ class ValidatingNotaryServiceTests { val stx = run { val inputState = issueInvalidState(clientNode, notaryNode.info.notaryIdentity) val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState) - tx.signWith(clientNode.keyPair!!) + val keyPair = clientNode.services.keyManagementService.toKeyPair(clientNode.info.legalIdentity.owningKey.keys.single()) + tx.signWith(keyPair) tx.toSignedTransaction(false) } @@ -62,7 +62,8 @@ class ValidatingNotaryServiceTests { val command = Command(DummyContract.Commands.Move(), expectedMissingKey) val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState, command) - tx.signWith(clientNode.keyPair!!) + val keyPair = clientNode.services.keyManagementService.toKeyPair(clientNode.info.legalIdentity.owningKey.keys.single()) + tx.signWith(keyPair) tx.toSignedTransaction(false) } diff --git a/node/src/test/kotlin/net/corda/node/services/statemachine/StateMachineManagerTests.kt b/node/src/test/kotlin/net/corda/node/services/statemachine/StateMachineManagerTests.kt index b37ccc5232..ea6a94aef0 100644 --- a/node/src/test/kotlin/net/corda/node/services/statemachine/StateMachineManagerTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/statemachine/StateMachineManagerTests.kt @@ -13,6 +13,8 @@ import net.corda.core.flows.FlowLogic import net.corda.core.getOrThrow import net.corda.core.map import net.corda.core.messaging.MessageRecipients +import net.corda.core.node.services.PartyInfo +import net.corda.core.node.services.ServiceInfo import net.corda.core.random63BitValue import net.corda.core.rootCause import net.corda.core.serialization.OpaqueBytes @@ -21,6 +23,7 @@ import net.corda.flows.CashCommand import net.corda.flows.CashFlow import net.corda.flows.NotaryFlow import net.corda.node.services.persistence.checkpoints +import net.corda.node.services.transactions.ValidatingNotaryService import net.corda.node.utilities.databaseTransaction import net.corda.testing.expect import net.corda.testing.expectEvents @@ -31,7 +34,8 @@ 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.AssertionsForClassTypes.assertThatThrownBy +import org.assertj.core.api.Assertions.assertThatThrownBy +import org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType import org.junit.After import org.junit.Before import org.junit.Test @@ -55,10 +59,12 @@ class StateMachineManagerTests { node1 = nodes.first node2 = nodes.second val notaryKeyPair = generateKeyPair() + val notaryService = ServiceInfo(ValidatingNotaryService.type, "notary-service-2000") + val overrideServices = mapOf(Pair(notaryService, notaryKeyPair)) // Note that these notaries don't operate correctly as they don't share their state. They are only used for testing // service addressing. - notary1 = net.createNotaryNode(networkMapAddr = node1.services.myInfo.address, keyPair = notaryKeyPair, serviceName = "notary-service-2000") - notary2 = net.createNotaryNode(networkMapAddr = node1.services.myInfo.address, keyPair = notaryKeyPair, serviceName = "notary-service-2000") + notary1 = net.createNotaryNode(networkMapAddr = node1.services.myInfo.address, overrideServices = overrideServices, serviceName = "notary-service-2000") + notary2 = net.createNotaryNode(networkMapAddr = node1.services.myInfo.address, overrideServices = overrideServices, serviceName = "notary-service-2000") net.messagingNetwork.receivedMessages.toSessionTransfers().forEach { sessionTransfers += it } net.runNetwork() @@ -244,14 +250,14 @@ class StateMachineManagerTests { assertSessionTransfers(node2, node1 sent sessionInit(SendFlow::class, payload) to node2, node2 sent sessionConfirm to node1, - node1 sent sessionEnd to node2 + node1 sent sessionEnd() to node2 //There's no session end from the other flows as they're manually suspended ) assertSessionTransfers(node3, node1 sent sessionInit(SendFlow::class, payload) to node3, node3 sent sessionConfirm to node1, - node1 sent sessionEnd to node3 + node1 sent sessionEnd() to node3 //There's no session end from the other flows as they're manually suspended ) @@ -278,14 +284,14 @@ class StateMachineManagerTests { node1 sent sessionInit(ReceiveFlow::class) to node2, node2 sent sessionConfirm to node1, node2 sent sessionData(node2Payload) to node1, - node2 sent sessionEnd to node1 + node2 sent sessionEnd() to node1 ) assertSessionTransfers(node3, node1 sent sessionInit(ReceiveFlow::class) to node3, node3 sent sessionConfirm to node1, node3 sent sessionData(node3Payload) to node1, - node3 sent sessionEnd to node1 + node3 sent sessionEnd() to node1 ) } @@ -301,7 +307,7 @@ class StateMachineManagerTests { node2 sent sessionData(20L) to node1, node1 sent sessionData(11L) to node2, node2 sent sessionData(21L) to node1, - node1 sent sessionEnd to node2 + node1 sent sessionEnd() to node2 ) } @@ -321,6 +327,8 @@ class StateMachineManagerTests { net.runNetwork() } val endpoint = net.messagingNetwork.endpoint(notary1.net.myAddress as InMemoryMessagingNetwork.PeerHandle)!! + val party1Info = notary1.services.networkMapCache.getPartyInfo(notary1.info.notaryIdentity)!! + assert(party1Info is PartyInfo.Service) val notary1Address: MessageRecipients = endpoint.getAddressOfParty(notary1.services.networkMapCache.getPartyInfo(notary1.info.notaryIdentity)!!) assert(notary1Address is InMemoryMessagingNetwork.ServiceHandle) assertEquals(notary1Address, endpoint.getAddressOfParty(notary2.services.networkMapCache.getPartyInfo(notary2.info.notaryIdentity)!!)) @@ -361,18 +369,119 @@ class StateMachineManagerTests { } @Test - fun `exception thrown on other side`() { - val erroringFiber = node2.initiateSingleShotFlow(ReceiveFlow::class) { ExceptionFlow }.map { it.stateMachine as FlowStateMachineImpl } + fun `FlowException thrown on other side`() { + val erroringFlowFuture = node2.initiateSingleShotFlow(ReceiveFlow::class) { + ExceptionFlow { MyFlowException("Nothing useful") } + } val receivingFiber = node1.services.startFlow(ReceiveFlow(node2.info.legalIdentity)) as FlowStateMachineImpl net.runNetwork() - assertThatThrownBy { receivingFiber.resultFuture.getOrThrow() }.isInstanceOf(FlowException::class.java) + assertThatExceptionOfType(MyFlowException::class.java) + .isThrownBy { receivingFiber.resultFuture.getOrThrow() } + .withMessage("Nothing useful") + .withStackTraceContaining("ReceiveFlow") // Make sure the stack trace is that of the receiving flow + databaseTransaction(node2.database) { + assertThat(node2.checkpointStorage.checkpoints()).isEmpty() + } + val errorFlow = erroringFlowFuture.getOrThrow() assertThat(receivingFiber.isTerminated).isTrue() - assertThat(erroringFiber.getOrThrow().isTerminated).isTrue() + assertThat((errorFlow.stateMachine as FlowStateMachineImpl).isTerminated).isTrue() assertSessionTransfers( node1 sent sessionInit(ReceiveFlow::class) to node2, node2 sent sessionConfirm to node1, - node2 sent sessionEnd to node1 + node2 sent sessionEnd(errorFlow.exceptionThrown) to node1 ) + // TODO see StateMachineManager.endAllFiberSessions +// // Make sure the original stack trace isn't sent down the wire +// assertThat((sessionTransfers.last().message as SessionEnd).errorResponse!!.stackTrace).isEmpty() + } + + @Test + fun `FlowException propagated in invocation chain`() { + val node3 = net.createNode(node1.info.address) + net.runNetwork() + + node3.initiateSingleShotFlow(ReceiveFlow::class) { ExceptionFlow { MyFlowException("Chain") } } + node2.initiateSingleShotFlow(ReceiveFlow::class) { ReceiveFlow(node3.info.legalIdentity) } + val receivingFiber = node1.services.startFlow(ReceiveFlow(node2.info.legalIdentity)) + net.runNetwork() + assertThatExceptionOfType(MyFlowException::class.java) + .isThrownBy { receivingFiber.resultFuture.getOrThrow() } + .withMessage("Chain") + } + + private class SendAndReceiveFlow(val otherParty: Party, val payload: Any) : FlowLogic() { + @Suspendable + override fun call() { + sendAndReceive(otherParty, payload) + } + } + + @Test + fun `FlowException thrown and there is a 3rd unrelated party flow`() { + val node3 = net.createNode(node1.info.address) + net.runNetwork() + + // 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") } + .map { it.stateMachine } + node3.initiateSingleShotFlow(ReceiveFlow::class) { ExceptionFlow { MyFlowException("Nothing useful") } } + + val node1Fiber = node1.services.startFlow(ReceiveFlow(node2.info.legalIdentity, node3.info.legalIdentity)) as FlowStateMachineImpl + net.runNetwork() + + // Node 1 will terminate with the error it received from node 3 but it won't propagate that to node 2 (as it's + // not relevant to it) but it will end its session with it + assertThatExceptionOfType(MyFlowException::class.java).isThrownBy { + node1Fiber.resultFuture.getOrThrow() + } + val node2ResultFuture = node2Fiber.getOrThrow().resultFuture + assertThatExceptionOfType(FlowSessionException::class.java).isThrownBy { + node2ResultFuture.getOrThrow() + } + + assertSessionTransfers(node2, + node1 sent sessionInit(ReceiveFlow::class) to node2, + node2 sent sessionConfirm to node1, + node2 sent sessionData("Hello") to node1, + node1 sent sessionEnd() to node2 // Unexpected session-end + ) + } + + private class ConditionalExceptionFlow(val otherParty: Party, val sendPayload: Any) : FlowLogic() { + @Suspendable + override fun call() { + val throwException = receive(otherParty).unwrap { it } + if (throwException) { + throw MyFlowException("Throwing exception as requested") + } + send(otherParty, sendPayload) + } + } + + @Test + fun `retry subFlow due to receiving FlowException`() { + class AskForExceptionFlow(val otherParty: Party, val throwException: Boolean) : FlowLogic() { + @Suspendable + override fun call(): String = sendAndReceive(otherParty, throwException).unwrap { it } + } + + class RetryOnExceptionFlow(val otherParty: Party) : FlowLogic() { + @Suspendable + override fun call(): String { + return try { + subFlow(AskForExceptionFlow(otherParty, throwException = true)) + } catch (e: MyFlowException) { + subFlow(AskForExceptionFlow(otherParty, throwException = false)) + } + } + } + + node2.services.registerFlowInitiator(AskForExceptionFlow::class) { ConditionalExceptionFlow(it, "Hello") } + val resultFuture = node1.services.startFlow(RetryOnExceptionFlow(node2.info.legalIdentity)).resultFuture + net.runNetwork() + assertThat(resultFuture.getOrThrow()).isEqualTo("Hello") } private inline fun > MockNode.restartAndGetRestoredFlow( @@ -396,15 +505,16 @@ class StateMachineManagerTests { private fun sessionData(payload: Any) = SessionData(0, payload) - private val sessionEnd = SessionEnd(0) + private fun sessionEnd(error: FlowException? = null) = SessionEnd(0, error) private fun assertSessionTransfers(vararg expected: SessionTransfer) { assertThat(sessionTransfers).containsExactly(*expected) } - private fun assertSessionTransfers(node: MockNode, vararg expected: SessionTransfer) { + private fun assertSessionTransfers(node: MockNode, vararg expected: SessionTransfer): List { val actualForNode = sessionTransfers.filter { it.from == node.id || it.to == node.net.myAddress } assertThat(actualForNode).containsExactly(*expected) + return actualForNode } private data class SessionTransfer(val from: Int, val message: SessionMessage, val to: MessageRecipients) { @@ -433,7 +543,6 @@ class StateMachineManagerTests { private infix fun MockNode.sent(message: SessionMessage): Pair = Pair(id, message) private infix fun Pair.to(node: MockNode): SessionTransfer = SessionTransfer(first, second, node.net.myAddress) - private class NoOpFlow(val nonTerminating: Boolean = false) : FlowLogic() { @Transient var flowStarted = false @@ -491,7 +600,16 @@ class StateMachineManagerTests { } } - private object ExceptionFlow : FlowLogic() { - override fun call(): Nothing = throw Exception() + private class ExceptionFlow(val exception: () -> E) : FlowLogic() { + lateinit var exceptionThrown: E + override fun call(): Nothing { + exceptionThrown = exception() + throw exceptionThrown + } + } + + private class MyFlowException(message: String) : FlowException(message) { + override fun equals(other: Any?): Boolean = other is MyFlowException && other.message == this.message + override fun hashCode(): Int = message?.hashCode() ?: 31 } } diff --git a/publish.properties b/publish.properties index c9aaf86b6a..f3bffdda51 100644 --- a/publish.properties +++ b/publish.properties @@ -1 +1 @@ -gradlePluginsVersion=0.7 +gradlePluginsVersion=0.7.1 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 75bc11fc27..2f84383c2f 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 @@ -118,4 +118,4 @@ private fun sslConfigFor(nodename: String, certsPath: String?): SSLConfiguration override val trustStorePassword: String = "trustpass" override val certificatesDirectory: Path = if (certsPath != null) Paths.get(certsPath) else Paths.get("build") / "nodes" / nodename / "certificates" } -} \ No newline at end of file +} 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 50e36588d4..f7f4fc1725 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 @@ -7,6 +7,7 @@ import net.corda.core.getOrThrow import net.corda.core.node.services.ServiceInfo import net.corda.node.driver.driver import net.corda.node.services.transactions.SimpleNotaryService +import net.corda.node.utilities.getHostAndPort import org.junit.Test class BankOfCordaHttpAPITest { @@ -17,8 +18,8 @@ class BankOfCordaHttpAPITest { startNode("BankOfCorda", setOf(ServiceInfo(SimpleNotaryService.type))), startNode("BigCorporation") ).getOrThrow() - val nodeBankOfCordaApiAddr = nodeBankOfCorda.configuration.webAddress + val nodeBankOfCordaApiAddr = startWebserver(nodeBankOfCorda).getOrThrow() assert(BankOfCordaClientApi(nodeBankOfCordaApiAddr).requestWebIssue(IssueRequestParams(1000, "USD", "BigCorporation", "1", "BankOfCorda"))) }, isDebug = true) } -} \ No newline at end of file +} diff --git a/samples/bank-of-corda-demo/src/integration-test/kotlin/net/corda/bank/BankOfCordaRPCClientTest.kt b/samples/bank-of-corda-demo/src/integration-test/kotlin/net/corda/bank/BankOfCordaRPCClientTest.kt index f66d53717c..5337fface2 100644 --- a/samples/bank-of-corda-demo/src/integration-test/kotlin/net/corda/bank/BankOfCordaRPCClientTest.kt +++ b/samples/bank-of-corda-demo/src/integration-test/kotlin/net/corda/bank/BankOfCordaRPCClientTest.kt @@ -24,8 +24,8 @@ class BankOfCordaRPCClientTest { driver(dsl = { val user = User("user1", "test", permissions = setOf(startFlowPermission())) val (nodeBankOfCorda, nodeBigCorporation) = Futures.allAsList( - startNode("BankOfCorda", setOf(ServiceInfo(SimpleNotaryService.type)), listOf(user)), - startNode("BigCorporation", rpcUsers = listOf(user)) + startNode("BankOfCorda", setOf(ServiceInfo(SimpleNotaryService.type)), listOf(user)), + startNode("BigCorporation", rpcUsers = listOf(user)) ).getOrThrow() // Bank of Corda RPC Client @@ -86,4 +86,4 @@ class BankOfCordaRPCClientTest { } }, isDebug = true) } -} \ No newline at end of file +} diff --git a/samples/bank-of-corda-demo/src/main/kotlin/net/corda/bank/BankOfCordaDriver.kt b/samples/bank-of-corda-demo/src/main/kotlin/net/corda/bank/BankOfCordaDriver.kt index 52f2757ecc..cc98f123a0 100644 --- a/samples/bank-of-corda-demo/src/main/kotlin/net/corda/bank/BankOfCordaDriver.kt +++ b/samples/bank-of-corda-demo/src/main/kotlin/net/corda/bank/BankOfCordaDriver.kt @@ -50,8 +50,9 @@ private class BankOfCordaDriver { driver(dsl = { val user = User("user1", "test", permissions = setOf(startFlowPermission(), startFlowPermission())) startNode("Notary", setOf(ServiceInfo(SimpleNotaryService.type))) - startNode("BankOfCorda", rpcUsers = listOf(user), advertisedServices = setOf(ServiceInfo(ServiceType.corda.getSubType("issuer.USD")))) + val bankOfCorda = startNode("BankOfCorda", rpcUsers = listOf(user), advertisedServices = setOf(ServiceInfo(ServiceType.corda.getSubType("issuer.USD")))) startNode("BigCorporation", rpcUsers = listOf(user)) + startWebserver(bankOfCorda.get()) waitForAllNodesToFinish() }, isDebug = true) } @@ -75,7 +76,8 @@ private class BankOfCordaDriver { } } catch (e: Exception) { - printHelp(parser) + println("Exception occurred: $e \n ${e.printStackTrace()}") + exitProcess(1) } } } 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 e505818d81..9376378a51 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 @@ -35,14 +35,20 @@ class IRSDemoTest : IntegrationTestCategory { startNode("Bank B") ).getOrThrow() + val (controllerAddr, nodeAAddr, nodeBAddr) = Futures.allAsList( + startWebserver(controller), + startWebserver(nodeA), + startWebserver(nodeB) + ).getOrThrow() + val nextFixingDates = getFixingDateObservable(nodeA.configuration) - runUploadRates(controller.configuration.webAddress) - runTrade(nodeA.configuration.webAddress) + runUploadRates(controllerAddr) + runTrade(nodeAAddr) // Wait until the initial trade and all scheduled fixings up to the current date have finished nextFixingDates.first { it == null || it > currentDate } - runDateChange(nodeB.configuration.webAddress) + runDateChange(nodeBAddr) nextFixingDates.first { it == null || it > futureDate } } } @@ -78,4 +84,4 @@ class IRSDemoTest : IntegrationTestCategory { val url = URL("http://$host/upload/interest-rates") assert(uploadFile(url, fileContents)) } -} \ No newline at end of file +} 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 4e2589e7fb..baed312051 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 @@ -1,5 +1,7 @@ package net.corda.irs +import com.google.common.util.concurrent.Futures +import net.corda.core.getOrThrow import net.corda.core.node.services.ServiceInfo import net.corda.irs.api.NodeInterestRates import net.corda.node.driver.driver @@ -11,9 +13,16 @@ import net.corda.node.services.transactions.SimpleNotaryService */ fun main(args: Array) { driver(dsl = { - startNode("Notary", setOf(ServiceInfo(SimpleNotaryService.type), ServiceInfo(NodeInterestRates.type))).get() - startNode("Bank A") - startNode("Bank B") + val (controller, nodeA, nodeB) = Futures.allAsList( + startNode("Notary", setOf(ServiceInfo(SimpleNotaryService.type), ServiceInfo(NodeInterestRates.type))), + startNode("Bank A"), + startNode("Bank B") + ).getOrThrow() + + startWebserver(controller) + startWebserver(nodeA) + startWebserver(nodeB) + waitForAllNodesToFinish() }, useTestClock = true, isDebug = true) } 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 bc80ac16ae..c34dbb0ac7 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 @@ -47,9 +47,8 @@ object FixingFlow { // validate the party that initiated is the one on the deal and that the recipient corresponds with it. // TODO: this is in no way secure and will be replaced by general session initiation logic in the future - val myName = serviceHub.myInfo.legalIdentity.name // Also check we are one of the parties - deal.parties.filter { it.name == myName }.single() + require(deal.parties.count { it.owningKey == serviceHub.myInfo.legalIdentity.owningKey } == 1) return handshake } @@ -60,8 +59,7 @@ object FixingFlow { val fixOf = deal.nextFixingOf()!! // TODO Do we need/want to substitute in new public keys for the Parties? - val myName = serviceHub.myInfo.legalIdentity.name - val myOldParty = deal.parties.single { it.name == myName } + val myOldParty = deal.parties.single { it.owningKey == serviceHub.myInfo.legalIdentity.owningKey } val newDeal = deal @@ -109,8 +107,8 @@ object FixingFlow { } override val myKeyPair: KeyPair get() { - val myName = serviceHub.myInfo.legalIdentity.name - val myKeys = dealToFix.state.data.parties.filter { it.name == myName }.single().owningKey.keys + val myCompositeKey = serviceHub.myInfo.legalIdentity.owningKey + val myKeys = dealToFix.state.data.parties.filter { it.owningKey == myCompositeKey }.single().owningKey.keys return serviceHub.keyManagementService.toKeyPair(myKeys) } @@ -144,13 +142,12 @@ object FixingFlow { override fun call(): Unit { progressTracker.nextStep() val dealToFix = serviceHub.loadState(ref) - // TODO: this is not the eventual mechanism for identifying the parties val fixableDeal = (dealToFix.data as FixableDealState) - val sortedParties = fixableDeal.parties.sortedBy { it.name } - if (sortedParties[0].name == serviceHub.myInfo.legalIdentity.name) { + val parties = fixableDeal.parties.filter { it.owningKey != serviceHub.myInfo.legalIdentity.owningKey } + if (parties.isNotEmpty()) { val fixing = FixingSession(ref, fixableDeal.oracleType) // Start the Floater which will then kick-off the Fixer - subFlow(Floater(sortedParties[1], fixing)) + subFlow(Floater(parties.first(), fixing)) } } } diff --git a/samples/irs-demo/src/main/kotlin/net/corda/simulation/IRSSimulation.kt b/samples/irs-demo/src/main/kotlin/net/corda/simulation/IRSSimulation.kt index 4b67d341eb..2e9c984aa9 100644 --- a/samples/irs-demo/src/main/kotlin/net/corda/simulation/IRSSimulation.kt +++ b/samples/irs-demo/src/main/kotlin/net/corda/simulation/IRSSimulation.kt @@ -22,6 +22,8 @@ import net.corda.node.utilities.databaseTransaction import net.corda.testing.initiateSingleShotFlow import net.corda.testing.node.InMemoryMessagingNetwork import net.corda.testing.node.MockIdentityService +import net.i2p.crypto.eddsa.KeyPairGenerator +import java.security.SecureRandom import java.time.LocalDate import java.util.* @@ -30,7 +32,7 @@ import java.util.* * A simulation in which banks execute interest rate swaps with each other, including the fixing events. */ class IRSSimulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, latencyInjector: InMemoryMessagingNetwork.LatencyCalculator?) : Simulation(networkSendManuallyPumped, runAsync, latencyInjector) { - val om = net.corda.node.utilities.JsonSupport.createDefaultMapper(MockIdentityService(network.identities)) + val om = net.corda.node.utilities.JsonSupport.createInMemoryMapper(MockIdentityService(network.identities)) init { currentDateAndTime = LocalDate.of(2016, 3, 8).atStartOfDay() @@ -126,7 +128,7 @@ class IRSSimulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, laten showProgressFor(listOf(node1, node2)) showConsensusFor(listOf(node1, node2, regulators[0])) - val instigator = Instigator(node2.info.legalIdentity, AutoOffer(notary.info.notaryIdentity, irs), node1.keyPair!!) + val instigator = Instigator(node2.info.legalIdentity, AutoOffer(notary.info.notaryIdentity, irs), node1.services.legalIdentityKey) val instigatorTx: ListenableFuture = node1.services.startFlow(instigator).resultFuture return Futures.allAsList(instigatorTx, acceptorTx).flatMap { instigatorTx } diff --git a/samples/irs-demo/src/main/kotlin/net/corda/simulation/Simulation.kt b/samples/irs-demo/src/main/kotlin/net/corda/simulation/Simulation.kt index ab5575a761..bfb5dd8dab 100644 --- a/samples/irs-demo/src/main/kotlin/net/corda/simulation/Simulation.kt +++ b/samples/irs-demo/src/main/kotlin/net/corda/simulation/Simulation.kt @@ -2,7 +2,6 @@ package net.corda.simulation import com.google.common.util.concurrent.Futures import com.google.common.util.concurrent.ListenableFuture -import net.corda.core.crypto.generateKeyPair import net.corda.core.flatMap import net.corda.core.flows.FlowLogic import net.corda.core.messaging.SingleMessageRecipient @@ -25,6 +24,7 @@ import net.corda.testing.node.TestClock import net.corda.testing.node.setTo import rx.Observable import rx.subjects.PublishSubject +import java.math.BigInteger import java.security.KeyPair import java.time.LocalDate import java.time.LocalDateTime @@ -50,8 +50,9 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean, // This puts together a mock network of SimulatedNodes. open class SimulatedNode(config: NodeConfiguration, mockNet: MockNetwork, networkMapAddress: SingleMessageRecipient?, - advertisedServices: Set, id: Int, keyPair: KeyPair?) - : MockNetwork.MockNode(config, mockNet, networkMapAddress, advertisedServices, id, keyPair) { + advertisedServices: Set, id: Int, overrideServices: Map?, + entropyRoot: BigInteger) + : MockNetwork.MockNode(config, mockNet, networkMapAddress, advertisedServices, id, overrideServices, entropyRoot) { override fun findMyLocation(): PhysicalLocation? = CityDatabase[configuration.nearestCity] } @@ -59,7 +60,8 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean, var counter = 0 override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?, - advertisedServices: Set, id: Int, keyPair: KeyPair?): MockNetwork.MockNode { + advertisedServices: Set, id: Int, overrideServices: Map?, + entropyRoot: BigInteger): MockNetwork.MockNode { val letter = 'A' + counter val city = bankLocations[counter++ % bankLocations.size] @@ -69,12 +71,12 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean, myLegalName = "Bank $letter", nearestCity = city, networkMapService = null) - return SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, keyPair) + return SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot) } fun createAll(): List { return bankLocations.map { - network.createNode(networkMap.info.address, start = false, nodeFactory = this, keyPair = generateKeyPair()) as SimulatedNode + network.createNode(networkMap.info.address, start = false, nodeFactory = this) as SimulatedNode } } } @@ -82,41 +84,44 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean, val bankFactory = BankFactory() object NetworkMapNodeFactory : MockNetwork.Factory { - override fun create(config: NodeConfiguration, network: MockNetwork, - networkMapAddr: SingleMessageRecipient?, advertisedServices: Set, id: Int, keyPair: KeyPair?): MockNetwork.MockNode { + override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?, + advertisedServices: Set, id: Int, overrideServices: Map?, + entropyRoot: BigInteger): MockNetwork.MockNode { require(advertisedServices.containsType(NetworkMapService.type)) val cfg = TestNodeConfiguration( baseDirectory = config.baseDirectory, myLegalName = "Network coordination center", nearestCity = "Amsterdam", networkMapService = null) - return object : SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, keyPair) {} + return object : SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot) {} } } object NotaryNodeFactory : MockNetwork.Factory { override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?, - advertisedServices: Set, id: Int, keyPair: KeyPair?): MockNetwork.MockNode { + advertisedServices: Set, id: Int, overrideServices: Map?, + entropyRoot: BigInteger): MockNetwork.MockNode { require(advertisedServices.containsType(SimpleNotaryService.type)) val cfg = TestNodeConfiguration( baseDirectory = config.baseDirectory, myLegalName = "Notary Service", nearestCity = "Zurich", networkMapService = null) - return SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, keyPair) + return SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot) } } object RatesOracleFactory : MockNetwork.Factory { override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?, - advertisedServices: Set, id: Int, keyPair: KeyPair?): MockNetwork.MockNode { + advertisedServices: Set, id: Int, overrideServices: Map?, + entropyRoot: BigInteger): MockNetwork.MockNode { require(advertisedServices.containsType(NodeInterestRates.type)) val cfg = TestNodeConfiguration( baseDirectory = config.baseDirectory, myLegalName = "Rates Service Provider", nearestCity = "Madrid", networkMapService = null) - return object : SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, keyPair) { + return object : SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot) { override fun start(): MockNetwork.MockNode { super.start() javaClass.classLoader.getResourceAsStream("example.rates.txt").use { @@ -132,13 +137,14 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean, object RegulatorFactory : MockNetwork.Factory { override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?, - advertisedServices: Set, id: Int, keyPair: KeyPair?): MockNetwork.MockNode { + advertisedServices: Set, id: Int, overrideServices: Map?, + entropyRoot: BigInteger): MockNetwork.MockNode { val cfg = TestNodeConfiguration( baseDirectory = config.baseDirectory, myLegalName = "Regulator A", nearestCity = "Paris", networkMapService = null) - return object : SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, keyPair) { + return object : SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot) { // TODO: Regulatory nodes don't actually exist properly, this is a last minute demo request. // So we just fire a message at a node that doesn't know how to handle it, and it'll ignore it. // But that's fine for visualisation purposes. diff --git a/samples/network-visualiser/src/main/kotlin/net/corda/netmap/VisualiserView.kt b/samples/network-visualiser/src/main/kotlin/net/corda/netmap/VisualiserView.kt index 9c90c46040..e5b874d112 100644 --- a/samples/network-visualiser/src/main/kotlin/net/corda/netmap/VisualiserView.kt +++ b/samples/network-visualiser/src/main/kotlin/net/corda/netmap/VisualiserView.kt @@ -225,14 +225,14 @@ internal class VisualiserView() { styleChoice.value = displayStyle val dropShadow = Pane().apply { styleClass += "drop-shadow-pane-horizontal"; minHeight = 8.0 } - val logoImage = ImageView(javaClass.getResource("R3 logo.png").toExternalForm()) + val logoImage = ImageView(javaClass.getResource("Corda logo.png").toExternalForm()) logoImage.fitHeight = 65.0 logoImage.isPreserveRatio = true - val logoLabel = HBox(logoImage, VBox( - Label("D I S T R I B U T E D L E D G E R G R O U P").apply { styleClass += "dlg-label" }, + val logoLabel = HBox(logoImage, Label("Network Simulator").apply { styleClass += "logo-label" } - )) + ) logoLabel.spacing = 10.0 + logoLabel.alignment = Pos.CENTER_LEFT HBox.setHgrow(logoLabel, Priority.ALWAYS) logoLabel.setPrefSize(Region.USE_COMPUTED_SIZE, Region.USE_PREF_SIZE) dateLabel = Label("").apply { styleClass += "date-label" } diff --git a/samples/network-visualiser/src/main/resources/net/corda/netmap/Corda logo.png b/samples/network-visualiser/src/main/resources/net/corda/netmap/Corda logo.png new file mode 100644 index 0000000000..16b101e3a9 Binary files /dev/null and b/samples/network-visualiser/src/main/resources/net/corda/netmap/Corda logo.png differ diff --git a/samples/network-visualiser/src/main/resources/net/corda/netmap/R3 logo.png b/samples/network-visualiser/src/main/resources/net/corda/netmap/R3 logo.png deleted file mode 100644 index 34d2996a35..0000000000 Binary files a/samples/network-visualiser/src/main/resources/net/corda/netmap/R3 logo.png and /dev/null differ diff --git a/samples/network-visualiser/src/main/resources/net/corda/netmap/styles.css b/samples/network-visualiser/src/main/resources/net/corda/netmap/styles.css index b7454d6787..dc2c30210e 100644 --- a/samples/network-visualiser/src/main/resources/net/corda/netmap/styles.css +++ b/samples/network-visualiser/src/main/resources/net/corda/netmap/styles.css @@ -170,7 +170,6 @@ .logo-label { -fx-font-size: 40; - -fx-text-fill: slategray; } .date-label { diff --git a/samples/raft-notary-demo/src/main/kotlin/net/corda/notarydemo/NotaryDemo.kt b/samples/raft-notary-demo/src/main/kotlin/net/corda/notarydemo/NotaryDemo.kt index f2511e7840..be4f1f03b4 100644 --- a/samples/raft-notary-demo/src/main/kotlin/net/corda/notarydemo/NotaryDemo.kt +++ b/samples/raft-notary-demo/src/main/kotlin/net/corda/notarydemo/NotaryDemo.kt @@ -24,7 +24,6 @@ fun main(args: Array) { /** Interface for using the notary demo API from a client. */ private class NotaryDemoClientApi(val rpc: CordaRPCOps) { - private val notary by lazy { rpc.networkMapUpdates().first.first { it.advertisedServices.any { it.info.type.isNotary() } }.notaryIdentity } @@ -37,17 +36,21 @@ private class NotaryDemoClientApi(val rpc: CordaRPCOps) { private val TRANSACTION_COUNT = 10 } - /** Makes a call to the demo api to start transaction notarisation. */ + /** Makes calls to the node rpc to start transaction notarisation. */ fun startNotarisation() { - val response = notarise(TRANSACTION_COUNT) - println(response) + notarise(TRANSACTION_COUNT) } - fun notarise(count: Int): String { + fun notarise(count: Int) { val transactions = buildTransactions(count) val signers = notariseTransactions(transactions) + val transactionSigners = transactions.zip(signers).map { + val (tx, signer) = it + "Tx [${tx.tx.id.prefixChars()}..] signed by $signer" + }.joinToString("\n") - return buildResponse(transactions, signers) + println("Notary: \"${notary.name}\", with composite key: ${notary.owningKey}\n" + + "Notarised ${transactions.size} transactions:\n" + transactionSigners) } /** @@ -72,20 +75,7 @@ private class NotaryDemoClientApi(val rpc: CordaRPCOps) { val signatureFutures = transactions.map { rpc.startFlow(NotaryFlow::Client, it).returnValue.toBlocking().toFuture() } - val signers = signatureFutures.map { it.get().by.toStringShort() } - return signers - } - - /** Builds a response for the caller containing the list of transaction ids and corresponding signer keys. */ - private fun buildResponse(transactions: List, signers: List): String { - val transactionSigners = transactions.zip(signers).map { - val (tx, signer) = it - "Tx [${tx.tx.id.prefixChars()}..] signed by $signer" - }.joinToString("\n") - - val response = "Notary: \"${notary.name}\", with composite key: ${notary.owningKey}\n" + - "Notarised ${transactions.size} transactions:\n" + transactionSigners - return response + return signatureFutures.map { it.get().by.toStringShort() } } } 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 b8a9acf55f..2deef657f4 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 @@ -1,9 +1,9 @@ package net.corda.vega +import com.google.common.util.concurrent.Futures import com.opengamma.strata.product.common.BuySell import net.corda.core.getOrThrow import net.corda.core.node.services.ServiceInfo -import net.corda.node.driver.NodeHandle import net.corda.node.driver.driver import net.corda.node.services.transactions.SimpleNotaryService import net.corda.testing.IntegrationTestCategory @@ -12,14 +12,11 @@ import net.corda.vega.api.PortfolioApi import net.corda.vega.api.PortfolioApiUtils import net.corda.vega.api.SwapDataModel import net.corda.vega.api.SwapDataView -import net.corda.vega.portfolio.Portfolio import org.junit.Test import java.math.BigDecimal import java.time.LocalDate -import java.util.* -import java.util.concurrent.Future -class SimmValuationTest: IntegrationTestCategory { +class SimmValuationTest : IntegrationTestCategory { private companion object { // SIMM demo can only currently handle one valuation date due to a lack of market data or a market data source. val valuationDate = LocalDate.parse("2016-06-06") @@ -31,23 +28,20 @@ class SimmValuationTest: IntegrationTestCategory { @Test fun `runs SIMM valuation demo`() { driver(isDebug = true) { startNode("Controller", setOf(ServiceInfo(SimpleNotaryService.type))).getOrThrow() - val nodeA = getSimmNodeApi(startNode(nodeALegalName)) - val nodeB = getSimmNodeApi(startNode(nodeBLegalName)) - val nodeBParty = getPartyWithName(nodeA, nodeBLegalName) - val nodeAParty = getPartyWithName(nodeB, nodeALegalName) + val (nodeA, nodeB) = Futures.allAsList(startNode(nodeALegalName), startNode(nodeBLegalName)).getOrThrow() + val (nodeAApi, nodeBApi) = Futures.allAsList(startWebserver(nodeA), startWebserver(nodeB)) + .getOrThrow() + .map { HttpApi.fromHostAndPort(it, "api/simmvaluationdemo") } + val nodeBParty = getPartyWithName(nodeAApi, nodeBLegalName) + val nodeAParty = getPartyWithName(nodeBApi, nodeALegalName) - assert(createTradeBetween(nodeA, nodeBParty, testTradeId)) - assert(tradeExists(nodeB, nodeAParty, testTradeId)) - assert(runValuationsBetween(nodeA, nodeBParty)) - assert(valuationExists(nodeB, nodeAParty)) + assert(createTradeBetween(nodeAApi, nodeBParty, testTradeId)) + assert(tradeExists(nodeBApi, nodeAParty, testTradeId)) + assert(runValuationsBetween(nodeAApi, nodeBParty)) + assert(valuationExists(nodeBApi, nodeAParty)) } } - private fun getSimmNodeApi(futureNode: Future): HttpApi { - val nodeAddr = futureNode.getOrThrow().configuration.webAddress - return HttpApi.fromHostAndPort(nodeAddr, "api/simmvaluationdemo") - } - private fun getPartyWithName(partyApi: HttpApi, countryparty: String): PortfolioApi.ApiParty = getAvailablePartiesFor(partyApi).counterparties.single { it.text == countryparty } diff --git a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/Main.kt b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/Main.kt index a66be19642..9655903d5e 100644 --- a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/Main.kt +++ b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/Main.kt @@ -1,5 +1,7 @@ package net.corda.vega +import com.google.common.util.concurrent.Futures +import net.corda.core.getOrThrow import net.corda.core.node.services.ServiceInfo import net.corda.node.driver.driver import net.corda.node.services.transactions.SimpleNotaryService @@ -12,9 +14,16 @@ import net.corda.node.services.transactions.SimpleNotaryService fun main(args: Array) { driver(dsl = { startNode("Controller", setOf(ServiceInfo(SimpleNotaryService.type))) - startNode("Bank A") - startNode("Bank B") - startNode("Bank C") + val (nodeA, nodeB, nodeC) = Futures.allAsList( + startNode("Bank A"), + startNode("Bank B"), + startNode("Bank C") + ).getOrThrow() + + startWebserver(nodeA) + startWebserver(nodeB) + startWebserver(nodeC) + waitForAllNodesToFinish() }, isDebug = true) } 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 1da82f1f5d..40ba74a159 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 @@ -18,6 +18,8 @@ import net.corda.core.messaging.Ack import net.corda.core.node.PluginServiceHub import net.corda.core.node.services.dealsWith import net.corda.core.transactions.SignedTransaction +import net.corda.flows.AbstractStateReplacementFlow.Proposal +import net.corda.flows.StateReplacementException import net.corda.flows.TwoPartyDealFlow import net.corda.vega.analytics.* import net.corda.vega.contracts.* @@ -299,9 +301,12 @@ object SimmFlow { private fun updatePortfolio(portfolio: Portfolio) { logger.info("Handshake finished, awaiting Simm update") send(replyToParty, Ack) // Hack to state that this party is ready - subFlow(StateRevisionFlow.Receiver(replyToParty, { - it.portfolio == portfolio.refs - }), shareParentSessions = true) + subFlow(object : StateRevisionFlow.Receiver(replyToParty) { + override fun verifyProposal(proposal: Proposal) { + super.verifyProposal(proposal) + if (proposal.modification.portfolio != portfolio.refs) throw StateReplacementException() + } + }, shareParentSessions = true) } @Suspendable @@ -309,11 +314,12 @@ object SimmFlow { val portfolio = stateRef.state.data.portfolio.toStateAndRef(serviceHub).toPortfolio() val valuer = stateRef.state.data.valuer val valuation = agreeValuation(portfolio, offer.valuationDate, valuer) - - subFlow(StateRevisionFlow.Receiver(replyToParty) { - it.valuation == valuation + subFlow(object : StateRevisionFlow.Receiver(replyToParty) { + override fun verifyProposal(proposal: Proposal) { + super.verifyProposal(proposal) + if (proposal.modification.valuation != valuation) throw StateReplacementException() + } }, shareParentSessions = true) } - } } 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 ddf24d7967..2da3cce5a3 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 @@ -1,13 +1,12 @@ package net.corda.vega.flows import net.corda.core.contracts.StateAndRef -import net.corda.core.contracts.StateRef import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party import net.corda.core.seconds import net.corda.core.transactions.SignedTransaction -import net.corda.core.utilities.UntrustworthyData import net.corda.flows.AbstractStateReplacementFlow +import net.corda.flows.StateReplacementException import net.corda.vega.contracts.RevisionedState /** @@ -15,18 +14,11 @@ import net.corda.vega.contracts.RevisionedState * on the update between two parties */ object StateRevisionFlow { - data class Proposal(override val stateRef: StateRef, - override val modification: T, - override val stx: SignedTransaction) : AbstractStateReplacementFlow.Proposal - - class Requester(curStateRef: StateAndRef>, val updatedData: T) - : AbstractStateReplacementFlow.Instigator, T>(curStateRef, updatedData) { - override fun assembleProposal(stateRef: StateRef, modification: T, stx: SignedTransaction): AbstractStateReplacementFlow.Proposal - = Proposal(stateRef, modification, stx) - + class Requester(curStateRef: StateAndRef>, + updatedData: T) : AbstractStateReplacementFlow.Instigator, T>(curStateRef, updatedData) { override fun assembleTx(): Pair> { val state = originalState.state.data - val tx = state.generateRevision(originalState.state.notary, originalState, updatedData) + val tx = state.generateRevision(originalState.state.notary, originalState, modification) tx.setTime(serviceHub.clock.instant(), 30.seconds) tx.signWith(serviceHub.legalIdentityKey) @@ -35,16 +27,12 @@ object StateRevisionFlow { } } - class Receiver(otherParty: Party, private val validate: (T) -> Boolean) - : AbstractStateReplacementFlow.Acceptor(otherParty) { - override fun verifyProposal(maybeProposal: UntrustworthyData>) - : AbstractStateReplacementFlow.Proposal { - return maybeProposal.unwrap { - val proposedTx = it.stx.tx - val state = it.stateRef - require(proposedTx.inputs.contains(state)) { "The proposed state $state is not in the proposed transaction inputs" } - require(validate(it.modification)) - it + open class Receiver(otherParty: Party) : AbstractStateReplacementFlow.Acceptor(otherParty) { + override fun verifyProposal(proposal: AbstractStateReplacementFlow.Proposal) { + val proposedTx = proposal.stx.tx + val state = proposal.stateRef + if (state !in proposedTx.inputs) { + throw StateReplacementException("The proposed state $state is not in the proposed transaction inputs") } } } 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 b956df1bac..f28cb2ab75 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 @@ -19,10 +19,10 @@ class TraderDemoTest { val demoUser = listOf(User("demo", "demo", permissions)) val user = User("user1", "test", permissions = setOf(startFlowPermission())) val (nodeA, nodeB) = Futures.allAsList( - startNode("Bank A", rpcUsers = demoUser), - startNode("Bank B", rpcUsers = demoUser), - startNode("BankOfCorda", rpcUsers = listOf(user)), - startNode("Notary", setOf(ServiceInfo(SimpleNotaryService.type))) + startNode("Bank A", rpcUsers = demoUser), + startNode("Bank B", rpcUsers = demoUser), + startNode("BankOfCorda", rpcUsers = listOf(user)), + startNode("Notary", setOf(ServiceInfo(SimpleNotaryService.type))) ).getOrThrow() val (nodeARpc, nodeBRpc) = listOf(nodeA, nodeB) .map { it.rpcClientToNode().start(demoUser[0].username, demoUser[0].password).proxy() } 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 6708d2702d..527a9c77da 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt +++ b/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt @@ -4,6 +4,7 @@ package net.corda.testing import com.google.common.net.HostAndPort import com.google.common.util.concurrent.ListenableFuture +import com.typesafe.config.Config import net.corda.core.contracts.StateRef import net.corda.core.crypto.* import net.corda.core.flows.FlowLogic @@ -155,3 +156,5 @@ data class TestNodeConfiguration( override val emailAddress: String = "", override val exportJMXto: String = "", override val devMode: Boolean = true) : NodeConfiguration + +fun Config.getHostAndPort(name: String) = HostAndPort.fromString(getString(name)) 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 ea5da50ab9..89d05e3626 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,10 +6,12 @@ import com.google.common.util.concurrent.Futures import com.google.common.util.concurrent.ListenableFuture import net.corda.core.* import net.corda.core.crypto.Party +import net.corda.core.crypto.entropyToKeyPair import net.corda.core.messaging.RPCOps import net.corda.core.messaging.SingleMessageRecipient import net.corda.core.node.CordaPluginRegistry 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.loggerFor @@ -28,6 +30,7 @@ import net.corda.node.utilities.AffinityExecutor.ServiceAffinityExecutor import net.corda.testing.TestNodeConfiguration import org.apache.activemq.artemis.utils.ReusableLatch import org.slf4j.Logger +import java.math.BigInteger import java.nio.file.FileSystem import java.security.KeyPair import java.util.* @@ -72,14 +75,22 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false, /** Allows customisation of how nodes are created. */ interface Factory { + /** + * @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 create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?, - advertisedServices: Set, id: Int, keyPair: KeyPair?): MockNode + advertisedServices: Set, id: Int, overrideServices: Map?, + entropyRoot: BigInteger): MockNode } object DefaultFactory : Factory { override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?, - advertisedServices: Set, id: Int, keyPair: KeyPair?): MockNode { - return MockNode(config, network, networkMapAddr, advertisedServices, id, keyPair) + advertisedServices: Set, id: Int, overrideServices: Map?, + entropyRoot: BigInteger): MockNode { + return MockNode(config, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot) } } @@ -108,12 +119,20 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false, } } + /** + * @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. + */ open class MockNode(config: NodeConfiguration, val mockNet: MockNetwork, override val networkMapAddress: SingleMessageRecipient?, advertisedServices: Set, val id: Int, - val keyPair: KeyPair?) : AbstractNode(config, advertisedServices, TestClock(), mockNet.busyLatch) { + val overrideServices: Map?, + val entropyRoot: BigInteger = BigInteger.valueOf(random63BitValue())) : AbstractNode(config, advertisedServices, TestClock(), mockNet.busyLatch) { + var counter = entropyRoot override val log: Logger = loggerFor() override val serverThread: AffinityExecutor = if (mockNet.threadPerNode) @@ -134,7 +153,9 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false, override fun makeVaultService(): VaultService = NodeVaultService(services) - override fun makeKeyManagementService(): KeyManagementService = E2ETestKeyManagementService(partyKeys) + override fun makeKeyManagementService(): KeyManagementService { + return E2ETestKeyManagementService(partyKeys + (overrideServices?.values ?: emptySet())) + } override fun startMessagingService(rpcOps: RPCOps) { // Nothing to do @@ -144,7 +165,28 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false, inNodeNetworkMapService = InMemoryNetworkMapService(services) } - override fun generateKeyPair(): KeyPair = keyPair ?: super.generateKeyPair() + override fun makeServiceEntries(): List { + val defaultEntries = super.makeServiceEntries() + return if (overrideServices == null) { + defaultEntries + } else { + defaultEntries.map { + val override = overrideServices[it.info] + if (override != null) { + // TODO: Store the key + ServiceEntry(it.info, Party(it.identity.name, override.public)) + } else { + it + } + } + } + } + + // This is not thread safe, but node construction is done on a single thread, so that should always be fine + override fun generateKeyPair(): KeyPair { + counter = counter.add(BigInteger.ONE) + return entropyToKeyPair(counter) + } // It's OK to not have a network map service in the mock network. override fun noNetworkMapConfigured(): ListenableFuture = Futures.immediateFuture(Unit) @@ -189,9 +231,28 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false, override fun acceptableLiveFiberCountOnStop(): Int = acceptableLiveFiberCountOnStop } - /** Returns a node, optionally created by the passed factory method. */ + /** + * 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: String? = null, keyPair: KeyPair? = null, + start: Boolean = true, legalName: String? = null, overrideServices: Map? = null, + vararg advertisedServices: ServiceInfo): MockNode + = createNode(networkMapAddress, forcedID, nodeFactory, start, legalName, overrideServices, BigInteger.valueOf(random63BitValue()), *advertisedServices) + + /** + * 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: String? = null, overrideServices: Map? = null, + entropyRoot: BigInteger = BigInteger.valueOf(random63BitValue()), vararg advertisedServices: ServiceInfo): MockNode { val newNode = forcedID == -1 val id = if (newNode) nextNodeId++ else forcedID @@ -205,7 +266,7 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false, myLegalName = legalName ?: "Mock Company $id", networkMapService = null, dataSourceProperties = makeTestDataSourceProperties("node_${id}_net_$networkId")) - val node = nodeFactory.create(config, this, networkMapAddress, advertisedServices.toSet(), id, keyPair) + val node = nodeFactory.create(config, this, networkMapAddress, advertisedServices.toSet(), id, overrideServices, entropyRoot) if (start) { node.setup().start() if (threadPerNode && networkMapAddress != null) @@ -242,8 +303,13 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false, */ fun createTwoNodes(nodeFactory: Factory = defaultFactory, notaryKeyPair: KeyPair? = null): Pair { require(nodes.isEmpty()) + val notaryServiceInfo = ServiceInfo(SimpleNotaryService.type) + val notaryOverride = if (notaryKeyPair != null) + mapOf(Pair(notaryServiceInfo, notaryKeyPair)) + else + null return Pair( - createNode(null, -1, nodeFactory, true, null, notaryKeyPair, ServiceInfo(NetworkMapService.type), ServiceInfo(SimpleNotaryService.type)), + createNode(null, -1, nodeFactory, true, null, notaryOverride, BigInteger.valueOf(random63BitValue()), ServiceInfo(NetworkMapService.type), notaryServiceInfo), createNode(nodes[0].info.address, -1, nodeFactory, true, null) ) } @@ -260,9 +326,14 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false, */ fun createSomeNodes(numPartyNodes: Int = 2, nodeFactory: Factory = defaultFactory, notaryKeyPair: KeyPair? = DUMMY_NOTARY_KEY): BasketOfNodes { require(nodes.isEmpty()) + val notaryServiceInfo = ServiceInfo(SimpleNotaryService.type) + val notaryOverride = if (notaryKeyPair != null) + mapOf(Pair(notaryServiceInfo, notaryKeyPair)) + else + null val mapNode = createNode(null, nodeFactory = nodeFactory, advertisedServices = ServiceInfo(NetworkMapService.type)) - val notaryNode = createNode(mapNode.info.address, nodeFactory = nodeFactory, keyPair = notaryKeyPair, - advertisedServices = ServiceInfo(SimpleNotaryService.type)) + val notaryNode = createNode(mapNode.info.address, nodeFactory = nodeFactory, overrideServices = notaryOverride, + advertisedServices = notaryServiceInfo) val nodes = ArrayList() repeat(numPartyNodes) { nodes += createPartyNode(mapNode.info.address) @@ -270,12 +341,18 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false, return BasketOfNodes(nodes, notaryNode, mapNode) } - fun createNotaryNode(networkMapAddr: SingleMessageRecipient? = null, legalName: String? = null, keyPair: KeyPair? = null, serviceName: String? = null): MockNode { - return createNode(networkMapAddr, -1, defaultFactory, true, legalName, keyPair, ServiceInfo(NetworkMapService.type), ServiceInfo(ValidatingNotaryService.type, serviceName)) + fun createNotaryNode(networkMapAddr: SingleMessageRecipient? = null, + legalName: String? = null, + overrideServices: Map? = null, + serviceName: String? = null): MockNode { + return createNode(networkMapAddr, -1, defaultFactory, true, legalName, overrideServices, BigInteger.valueOf(random63BitValue()), + ServiceInfo(NetworkMapService.type), ServiceInfo(ValidatingNotaryService.type, serviceName)) } - fun createPartyNode(networkMapAddr: SingleMessageRecipient, legalName: String? = null, keyPair: KeyPair? = null): MockNode { - return createNode(networkMapAddr, -1, defaultFactory, true, legalName, keyPair) + fun createPartyNode(networkMapAddr: SingleMessageRecipient, + legalName: String? = null, + overrideServices: Map? = null): MockNode { + return createNode(networkMapAddr, -1, defaultFactory, true, legalName, overrideServices) } @Suppress("unused") // This is used from the network visualiser tool. 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 a99247b6ad..97607e55a4 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 @@ -155,6 +155,7 @@ open class MockTransactionStorage : TransactionStorage { @ThreadSafe class MockStorageService(override val attachments: AttachmentStorage = MockAttachmentStorage(), override val validatedTransactions: TransactionStorage = MockTransactionStorage(), + override val uploaders: List = listOf(), override val stateMachineRecordedTransactionMapping: StateMachineRecordedTransactionMappingStorage = MockStateMachineRecordedTransactionMappingStorage()) : SingletonSerializeAsToken(), TxWritableStorageService 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 177c393aa2..17661dfa81 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 @@ -16,9 +16,12 @@ import net.corda.core.contracts.Issued import net.corda.core.contracts.PartyAndReference import net.corda.core.contracts.withoutIssuer import net.corda.core.crypto.Party +import net.corda.core.flows.FlowException +import net.corda.core.getOrThrow import net.corda.core.messaging.startFlow import net.corda.core.node.NodeInfo import net.corda.core.serialization.OpaqueBytes +import net.corda.core.toFuture import net.corda.core.transactions.SignedTransaction import net.corda.explorer.model.CashTransaction import net.corda.explorer.model.IssuerModel @@ -28,7 +31,6 @@ import net.corda.explorer.views.byteFormatter import net.corda.explorer.views.stringConverter import net.corda.flows.CashCommand import net.corda.flows.CashFlow -import net.corda.flows.CashFlowResult import net.corda.flows.IssuerFlow.IssuanceRequester import org.controlsfx.dialog.ExceptionDialog import tornadofx.Fragment @@ -87,33 +89,37 @@ class NewTransaction : Fragment() { } dialog.show() runAsync { - if (it is CashCommand.IssueCash) { + val handle = if (it is CashCommand.IssueCash) { myIdentity.value?.let { myIdentity -> rpcProxy.value!!.startFlow(::IssuanceRequester, it.amount, it.recipient, it.issueRef, - myIdentity.legalIdentity).returnValue.toBlocking().first() + myIdentity.legalIdentity) } + } else { + rpcProxy.value!!.startFlow(::CashFlow, it) } - else { - rpcProxy.value!!.startFlow(::CashFlow, it).returnValue.toBlocking().first() + val response = try { + handle?.returnValue?.toFuture()?.getOrThrow() + } catch (e: FlowException) { + e } + it to response }.ui { - dialog.contentText = when (it) { - is SignedTransaction -> { - dialog.alertType = Alert.AlertType.INFORMATION - "Cash Issued \nTransaction ID : ${it.id} \nMessage" - } - is CashFlowResult.Success -> { - dialog.alertType = Alert.AlertType.INFORMATION - "Transaction Started \nTransaction ID : ${it.transaction?.id} \nMessage : ${it.message}" - } - else -> { - dialog.alertType = Alert.AlertType.ERROR - it.toString() + val (command, response) = it + val (alertType, contentText) = if (response is FlowException) { + Alert.AlertType.ERROR to response.message + } else { + val type = when (command) { + is CashCommand.IssueCash -> "Cash Issued" + is CashCommand.ExitCash -> "Cash Exited" + is CashCommand.PayCash -> "Cash Paid" } + Alert.AlertType.INFORMATION to "$type \nTransaction ID : ${(response as SignedTransaction).id}" } + dialog.alertType = alertType + dialog.contentText = contentText dialog.dialogPane.isDisable = false dialog.dialogPane.scene.window.sizeToScene() }.setOnFailed { diff --git a/tools/loadtest/src/main/kotlin/net/corda/loadtest/tests/CrossCashTest.kt b/tools/loadtest/src/main/kotlin/net/corda/loadtest/tests/CrossCashTest.kt index e50256132e..42ed3b0182 100644 --- a/tools/loadtest/src/main/kotlin/net/corda/loadtest/tests/CrossCashTest.kt +++ b/tools/loadtest/src/main/kotlin/net/corda/loadtest/tests/CrossCashTest.kt @@ -7,11 +7,13 @@ import net.corda.core.contracts.Issued import net.corda.core.contracts.PartyAndReference import net.corda.core.contracts.USD import net.corda.core.crypto.Party +import net.corda.core.getOrThrow import net.corda.core.messaging.startFlow import net.corda.core.serialization.OpaqueBytes +import net.corda.core.toFuture import net.corda.flows.CashCommand +import net.corda.flows.CashException import net.corda.flows.CashFlow -import net.corda.flows.CashFlowResult import net.corda.loadtest.LoadTest import net.corda.loadtest.NodeHandle import org.slf4j.LoggerFactory @@ -205,14 +207,11 @@ val crossCashTest = LoadTest( }, execute = { command -> - val result = command.node.connection.proxy.startFlow(::CashFlow, command.command).returnValue.toBlocking().first() - when (result) { - is CashFlowResult.Success -> { - log.info(result.message) - } - is CashFlowResult.Failed -> { - log.error(result.message) - } + try { + val result = command.node.connection.proxy.startFlow(::CashFlow, command.command).returnValue.toFuture().getOrThrow() + log.info("Success: $result") + } catch (e: CashException) { + log.error("Failure", e) } }, diff --git a/tools/loadtest/src/main/kotlin/net/corda/loadtest/tests/SelfIssueTest.kt b/tools/loadtest/src/main/kotlin/net/corda/loadtest/tests/SelfIssueTest.kt index d8201bab0d..2abc1a1270 100644 --- a/tools/loadtest/src/main/kotlin/net/corda/loadtest/tests/SelfIssueTest.kt +++ b/tools/loadtest/src/main/kotlin/net/corda/loadtest/tests/SelfIssueTest.kt @@ -7,10 +7,12 @@ import net.corda.client.mock.replicatePoisson import net.corda.contracts.asset.Cash import net.corda.core.contracts.USD import net.corda.core.crypto.Party +import net.corda.core.getOrThrow import net.corda.core.messaging.startFlow +import net.corda.core.toFuture import net.corda.flows.CashCommand +import net.corda.flows.CashException import net.corda.flows.CashFlow -import net.corda.flows.CashFlowResult import net.corda.loadtest.LoadTest import net.corda.loadtest.NodeHandle import org.slf4j.LoggerFactory @@ -60,14 +62,11 @@ val selfIssueTest = LoadTest( }, execute = { command -> - val result = command.node.connection.proxy.startFlow(::CashFlow, command.command).returnValue.toBlocking().first() - when (result) { - is CashFlowResult.Success -> { - log.info(result.message) - } - is CashFlowResult.Failed -> { - log.error(result.message) - } + try { + val result = command.node.connection.proxy.startFlow(::CashFlow, command.command).returnValue.toFuture().getOrThrow() + log.info("Success: $result") + } catch (e: CashException) { + log.error("Failure", e) } },