From 1b72feff7ab9ed8be98da86f1622dac8915a2900 Mon Sep 17 00:00:00 2001 From: Mike Hearn Date: Fri, 24 Jun 2016 14:57:24 +0200 Subject: [PATCH 001/114] Testing: Fix the wallet filler code. --- .../main/kotlin/com/r3corda/contracts/testing/WalletFiller.kt | 3 ++- .../kotlin/com/r3corda/node/services/WalletWithCashTest.kt | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/contracts/src/main/kotlin/com/r3corda/contracts/testing/WalletFiller.kt b/contracts/src/main/kotlin/com/r3corda/contracts/testing/WalletFiller.kt index b1ba2a87e2..ec7bec2404 100644 --- a/contracts/src/main/kotlin/com/r3corda/contracts/testing/WalletFiller.kt +++ b/contracts/src/main/kotlin/com/r3corda/contracts/testing/WalletFiller.kt @@ -71,11 +71,12 @@ private fun calculateRandomlySizedAmounts(howMuch: Amount, min: Int, m if (i < numStates - 1) { // Adjust the amount a bit up or down, to give more realistic amounts (not all identical). amounts[i] = baseSize + (baseSize / 2 * (rng.nextDouble() - 0.5)).toLong() - filledSoFar += baseSize + filledSoFar += amounts[i] } else { // Handle inexact rounding. amounts[i] = howMuch.quantity - filledSoFar } } + check(amounts.sum() == howMuch.quantity) return amounts } \ No newline at end of file diff --git a/node/src/test/kotlin/com/r3corda/node/services/WalletWithCashTest.kt b/node/src/test/kotlin/com/r3corda/node/services/WalletWithCashTest.kt index 100a072288..949d0761df 100644 --- a/node/src/test/kotlin/com/r3corda/node/services/WalletWithCashTest.kt +++ b/node/src/test/kotlin/com/r3corda/node/services/WalletWithCashTest.kt @@ -56,7 +56,7 @@ class WalletWithCashTest { assertEquals(29.01.DOLLARS `issued by` myPartyRef, state.amount) assertEquals(ALICE_PUBKEY, state.owner) - assertEquals(33.34.DOLLARS `issued by` myPartyRef, (w.states[2].state.data as Cash.State).amount) + assertEquals(35.38.DOLLARS `issued by` myPartyRef, (w.states[2].state.data as Cash.State).amount) assertEquals(35.61.DOLLARS `issued by` myPartyRef, (w.states[1].state.data as Cash.State).amount) } From 848b998d26beb17e2d4580f8a47d6cec17150c3f Mon Sep 17 00:00:00 2001 From: Mike Hearn Date: Mon, 27 Jun 2016 14:55:55 +0200 Subject: [PATCH 002/114] Suppress compiler warnings in experimental. They are still expected to be fixed in the other modules. --- experimental/build.gradle | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/experimental/build.gradle b/experimental/build.gradle index 8723bc20ce..c7f8ff8c45 100644 --- a/experimental/build.gradle +++ b/experimental/build.gradle @@ -10,6 +10,13 @@ repositories { mavenCentral() } +compileKotlin { + kotlinOptions.suppressWarnings = true +} +compileTestKotlin { + kotlinOptions.suppressWarnings = true +} + dependencies { compile project(':core') compile project(':contracts') From cb90a8c09b45cf7a8432d7009d3913fcc8a80c50 Mon Sep 17 00:00:00 2001 From: Mike Hearn Date: Mon, 27 Jun 2016 15:22:00 +0200 Subject: [PATCH 003/114] Add a policy about compiler warnings. --- docs/source/codestyle.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/source/codestyle.rst b/docs/source/codestyle.rst index ed05f4411e..aeebb4f04d 100644 --- a/docs/source/codestyle.rst +++ b/docs/source/codestyle.rst @@ -213,3 +213,10 @@ Notably: collection wrappers, if that is appropriate. * If the code following "get()" is succinct, prefer a one-liner formatting of the public property as above, otherwise put the "get()" on the line below, indented. + +6. Compiler warnings +#################### + +We do not allow compiler warnings, except in the experimental module where the usual standards do not apply and warnings +are suppressed. If a warning exists it should be either fixed or suppressed using @SuppressWarnings and if suppressed +there must be an accompanying explanation in the code for why the warning is a false positive. \ No newline at end of file From 9994d129f2022bbd61b168be329fb32a70105d69 Mon Sep 17 00:00:00 2001 From: Ross Nicoll Date: Fri, 24 Jun 2016 15:34:40 +0100 Subject: [PATCH 004/114] General cleanup based on first round of feedback * Rename AggregateCommands to IssuanceCommands * Reorder comparisons to be consistent * Rename verifyDefaultCommand to verifySetLifecycleCommand * Rename currency to issued/product * Add note about needing to rethink timestamping * Rename issuer to obligor, and owner to beneficiary * Move lifecycle inversion code into SetLifecycle command * Correct comments regarding cash states * Rework description of contractHash parameter * Fixes 'netting equal balances due between parties', and add further netting tests * Separate calculations involving issued products and the underlying product * Use signed transactions in obligation tests * Add verification tests for changing lifecycle --- .../kotlin/com/r3corda/contracts/cash/Cash.kt | 13 +- .../r3corda/contracts/cash/FungibleAsset.kt | 2 +- .../contracts/cash/FungibleAssetState.kt | 4 +- .../com/r3corda/contracts/Obligation.kt | 366 +++++++++--------- .../testing/ExperimentalTestUtils.kt | 16 +- .../com/r3corda/contracts/ObligationTests.kt | 220 +++++++---- 6 files changed, 341 insertions(+), 280 deletions(-) diff --git a/contracts/src/main/kotlin/com/r3corda/contracts/cash/Cash.kt b/contracts/src/main/kotlin/com/r3corda/contracts/cash/Cash.kt index 2d15cebd7e..606f430014 100644 --- a/contracts/src/main/kotlin/com/r3corda/contracts/cash/Cash.kt +++ b/contracts/src/main/kotlin/com/r3corda/contracts/cash/Cash.kt @@ -54,6 +54,9 @@ class Cash : FungibleAsset() { ) : FungibleAsset.State { constructor(deposit: PartyAndReference, amount: Amount, owner: PublicKey) : this(Amount(amount.quantity, Issued(deposit, amount.token)), owner) + + override val productAmount: Amount + get() = Amount(amount.quantity, amount.token.product) override val deposit: PartyAndReference get() = amount.token.issuer override val contract = CASH_PROGRAM_ID @@ -62,8 +65,8 @@ class Cash : FungibleAsset() { override val participants: List get() = listOf(owner) - override fun move(amount: Amount>, owner: PublicKey): FungibleAsset.State - = copy(amount = amount, owner = owner) + override fun move(newAmount: Amount, newOwner: PublicKey): FungibleAsset.State + = copy(amount = amount.copy(newAmount.quantity, amount.token), owner = newOwner) override fun toString() = "${Emoji.bagOfCash}Cash($amount at $deposit owned by ${owner.toStringShort()})" @@ -75,9 +78,9 @@ class Cash : FungibleAsset() { /** * A command stating that money has been moved, optionally to fulfil another contract. * - * @param contractHash the hash of the contract this cash is settling, to ensure one cash contract cannot be - * used to settle multiple contracts. May be null, if this is not relevant to any other contract in the - * same transaction + * @param contractHash the contract this move is for the attention of. Only that contract's verify function + * should take the moved states into account when considering whether it is valid. Typically this will be + * null. */ data class Move(override val contractHash: SecureHash? = null) : FungibleAsset.Commands.Move, Commands diff --git a/contracts/src/main/kotlin/com/r3corda/contracts/cash/FungibleAsset.kt b/contracts/src/main/kotlin/com/r3corda/contracts/cash/FungibleAsset.kt index 56061adab2..869ddea6d5 100644 --- a/contracts/src/main/kotlin/com/r3corda/contracts/cash/FungibleAsset.kt +++ b/contracts/src/main/kotlin/com/r3corda/contracts/cash/FungibleAsset.kt @@ -34,7 +34,7 @@ abstract class FungibleAsset : Contract { interface State : FungibleAssetState> { /** Where the underlying currency backing this ledger entry can be found (propagated) */ val deposit: PartyAndReference - override val amount: Amount> + val amount: Amount> /** There must be a MoveCommand signed by this key to claim the amount */ override val owner: PublicKey } diff --git a/contracts/src/main/kotlin/com/r3corda/contracts/cash/FungibleAssetState.kt b/contracts/src/main/kotlin/com/r3corda/contracts/cash/FungibleAssetState.kt index 17fa51adb2..b2641d5d99 100644 --- a/contracts/src/main/kotlin/com/r3corda/contracts/cash/FungibleAssetState.kt +++ b/contracts/src/main/kotlin/com/r3corda/contracts/cash/FungibleAssetState.kt @@ -10,6 +10,6 @@ import java.security.PublicKey */ interface FungibleAssetState : OwnableState { val issuanceDef: I - val amount: Amount> - fun move(amount: Amount>, owner: PublicKey): FungibleAssetState + val productAmount: Amount + fun move(amount: Amount, owner: PublicKey): FungibleAssetState } \ No newline at end of file diff --git a/experimental/src/main/kotlin/com/r3corda/contracts/Obligation.kt b/experimental/src/main/kotlin/com/r3corda/contracts/Obligation.kt index 3635785735..cb1504a428 100644 --- a/experimental/src/main/kotlin/com/r3corda/contracts/Obligation.kt +++ b/experimental/src/main/kotlin/com/r3corda/contracts/Obligation.kt @@ -18,7 +18,7 @@ import java.util.* val OBLIGATION_PROGRAM_ID = Obligation() /** - * A cash settlement contract commits the issuer to delivering a specified amount of cash (represented as the [Cash] + * A cash settlement contract commits the obligor to delivering a specified amount of cash (represented as the [Cash] * contract) at a specified future point in time. Similarly to cash, settlement transactions may split and merge * contracts across multiple input and output states. * @@ -51,7 +51,7 @@ class Obligation

: Contract { NORMAL, /** * Indicates the contract has not been settled by its due date. Once in the defaulted state, - * it can only be reverted to [NORMAL] state by the owner. + * it can only be reverted to [NORMAL] state by the beneficiary. */ DEFAULTED } @@ -61,7 +61,7 @@ class Obligation

: Contract { * underlying issued thing. */ interface NetState

{ - val issued: Issued

+ val template: StateTemplate

} /** @@ -71,11 +71,8 @@ class Obligation

: Contract { */ data class BilateralNetState

( val partyKeys: Set, - val issuanceDef: StateTemplate

- ) : NetState

{ - override val issued: Issued

- get() = issuanceDef.issued - } + override val template: StateTemplate

+ ) : NetState

/** * Subset of state, containing the elements which must match for two or more obligation transactions to be candidates @@ -86,11 +83,8 @@ class Obligation

: Contract { * Used in cases where all parties (or their proxies) are signing, such as central clearing. */ data class MultilateralNetState

( - val issuanceDef: StateTemplate

- ) : NetState

{ - override val issued: Issued

- get() = issuanceDef.issued - } + override val template: StateTemplate

+ ) : NetState

/** * Subset of state, containing the elements specified when issuing a new settlement contract. @@ -101,14 +95,14 @@ class Obligation

: Contract { /** The hash of the cash contract we're willing to accept in payment for this debt. */ val acceptableContracts: NonEmptySet, /** The parties whose cash we are willing to accept in payment for this debt. */ - val acceptableIssuanceDefinitions: NonEmptySet>, + val acceptableIssuedProducts: NonEmptySet>, /** When the contract must be settled by. */ val dueBefore: Instant, val timeTolerance: Duration = Duration.ofSeconds(30) ) { - val issued: Issued

- get() = acceptableIssuanceDefinitions.toSet().single() + val product: P + get() = acceptableIssuedProducts.map { it.product }.toSet().single() } /** @@ -119,57 +113,58 @@ class Obligation

: Contract { * @param P the product the obligation is for payment of. */ data class IssuanceDefinition

( - val issuer: Party, + val obligor: Party, val template: StateTemplate

- ) { - val currency: P - get() = template.issued.product - val issued: Issued

- get() = template.issued - } + ) /** - * A state representing the obligation of one party (issuer) to deliver a specified number of - * units of an underlying asset (described as issuanceDef.acceptableCashIssuance) to the owner + * A state representing the obligation of one party (obligor) to deliver a specified number of + * units of an underlying asset (described as issuanceDef.acceptableCashIssuance) to the beneficiary * no later than the specified time. * * @param P the product the obligation is for payment of. */ data class State

( var lifecycle: Lifecycle = Lifecycle.NORMAL, - /** Where the debt originates from (issuer) */ - val issuer: Party, + /** Where the debt originates from (obligor) */ + val obligor: Party, val template: StateTemplate

, val quantity: Long, /** The public key of the entity the contract pays to */ - override val owner: PublicKey + val beneficiary: PublicKey ) : FungibleAssetState>, BilateralNettableState> { - override val amount: Amount> - get() = Amount(quantity, template.issued) + val amount: Amount

+ get() = Amount(quantity, template.product) + val aggregateState: IssuanceDefinition

+ get() = issuanceDef + override val productAmount: Amount

+ get() = amount override val contract = OBLIGATION_PROGRAM_ID val acceptableContracts: NonEmptySet get() = template.acceptableContracts val acceptableIssuanceDefinitions: NonEmptySet<*> - get() = template.acceptableIssuanceDefinitions + get() = template.acceptableIssuedProducts val dueBefore: Instant get() = template.dueBefore override val issuanceDef: IssuanceDefinition

- get() = IssuanceDefinition(issuer, template) + get() = IssuanceDefinition(obligor, template) override val participants: List - get() = listOf(issuer.owningKey, owner) + get() = listOf(obligor.owningKey, beneficiary) + override val owner: PublicKey + get() = beneficiary - override fun move(amount: Amount>, owner: PublicKey): Obligation.State

- = copy(quantity = amount.quantity, owner = owner) + override fun move(amount: Amount

, beneficiary: PublicKey): Obligation.State

+ = copy(quantity = amount.quantity, beneficiary = beneficiary) override fun toString() = when (lifecycle) { - Lifecycle.NORMAL -> "${Emoji.bagOfCash}Debt($amount due $dueBefore to ${owner.toStringShort()})" - Lifecycle.DEFAULTED -> "${Emoji.bagOfCash}Debt($amount unpaid by $dueBefore to ${owner.toStringShort()})" + Lifecycle.NORMAL -> "${Emoji.bagOfCash}Debt($amount due $dueBefore to ${beneficiary.toStringShort()})" + Lifecycle.DEFAULTED -> "${Emoji.bagOfCash}Debt($amount unpaid by $dueBefore to ${beneficiary.toStringShort()})" } override val bilateralNetState: BilateralNetState

get() { check(lifecycle == Lifecycle.NORMAL) - return BilateralNetState(setOf(issuer.owningKey, owner), template) + return BilateralNetState(setOf(obligor.owningKey, beneficiary), template) } val multilateralNetState: MultilateralNetState

get() { @@ -182,20 +177,20 @@ class Obligation

: Contract { val netB = other.bilateralNetState require(netA == netB) { "net substates of the two state objects must be identical" } - if (issuer.owningKey == other.issuer.owningKey) { - // Both sides are from the same issuer to owner + if (obligor.owningKey == other.obligor.owningKey) { + // Both sides are from the same obligor to beneficiary return copy(quantity = quantity + other.quantity) } else { - // Issuer and owner are backwards + // Issuer and beneficiary are backwards return copy(quantity = quantity - other.quantity) } } - override fun withNewOwner(newOwner: PublicKey) = Pair(Commands.Move(issuanceDef), copy(owner = newOwner)) + override fun withNewOwner(newOwner: PublicKey) = Pair(Commands.Move(issuanceDef), copy(beneficiary = newOwner)) } - /** Interface for commands that apply to aggregated states */ - interface AggregateCommands

: CommandData { + /** Interface for commands that apply to states grouped by issuance definition */ + interface IssuanceCommands

: CommandData { val aggregateState: IssuanceDefinition

} @@ -203,49 +198,54 @@ class Obligation

: Contract { interface Commands : CommandData { /** * Net two or more cash settlement states together in a close-out netting style. Limited to bilateral netting - * as only the owner (not the issuer) needs to sign. + * as only the beneficiary (not the obligor) needs to sign. */ data class Net(val type: NetType) : Commands /** * A command stating that a debt has been moved, optionally to fulfil another contract. * - * @param contractHash the hash of contract's code, which indicates to that contract that the - * obligation states moved in this transaction are for their sole attention. - * This is a single value to ensure the same state(s) cannot be used to settle multiple contracts. - * May be null, if this is not relevant to any other contract in the same transaction. + * @param contractHash the contract this move is for the attention of. Only that contract's verify function + * should take the moved states into account when considering whether it is valid. Typically this will be + * null. */ data class Move

(override val aggregateState: IssuanceDefinition

, - override val contractHash: SecureHash? = null) : Commands, AggregateCommands

, MoveCommand + override val contractHash: SecureHash? = null) : Commands, IssuanceCommands

, MoveCommand /** - * Allows new cash states to be issued into existence: the nonce ("number used once") ensures the transaction - * has a unique ID even when there are no inputs. + * Allows new obligation states to be issued into existence: the nonce ("number used once") ensures the + * transaction has a unique ID even when there are no inputs. */ data class Issue

(override val aggregateState: IssuanceDefinition

, - val nonce: Long = random63BitValue()) : Commands, AggregateCommands

+ val nonce: Long = random63BitValue()) : Commands, IssuanceCommands

/** - * A command stating that the issuer is settling some or all of the amount owed by paying in a suitable cash - * contract. If this reduces the balance to zero, the contract moves to the settled state. + * A command stating that the obligor is settling some or all of the amount owed by transferring a suitable + * state object to the beneficiary. If this reduces the balance to zero, the state object is destroyed. * @see [Cash.Commands.Move] */ data class Settle

(override val aggregateState: IssuanceDefinition

, - val amount: Amount>) : Commands, AggregateCommands

+ val amount: Amount

) : Commands, IssuanceCommands

/** - * A command stating that the owner is moving the contract into the defaulted state as it has not been settled + * A command stating that the beneficiary is moving the contract into the defaulted state as it has not been settled * by the due date, or resetting a defaulted contract back to the issued state. */ data class SetLifecycle

(override val aggregateState: IssuanceDefinition

, - val lifecycle: Lifecycle) : Commands, AggregateCommands

+ val lifecycle: Lifecycle) : Commands, IssuanceCommands

{ + val inverse: Lifecycle + get() = when (lifecycle) { + Lifecycle.NORMAL -> Lifecycle.DEFAULTED + Lifecycle.DEFAULTED -> Lifecycle.NORMAL + } + } /** - * A command stating that the debt is being released by the owner. Normally would indicate - * either settlement outside of the ledger, or that the issuer is unable to pay. + * A command stating that the debt is being released by the beneficiary. Normally would indicate + * either settlement outside of the ledger, or that the obligor is unable to pay. */ data class Exit

(override val aggregateState: IssuanceDefinition

, - val amount: Amount>) : Commands, AggregateCommands

+ val amount: Amount

) : Commands, IssuanceCommands

} /** This is the function EVERYONE runs */ @@ -264,40 +264,40 @@ class Obligation

: Contract { verifyNetCommand(inputs, outputs, netCommand, key) } } else { - val commandGroups = tx.groupCommands, IssuanceDefinition

> { it.value.aggregateState } + val commandGroups = tx.groupCommands, IssuanceDefinition

> { it.value.aggregateState } // Each group is a set of input/output states with distinct issuance definitions. These types // of settlement are not fungible and must be kept separated for bookkeeping purposes. - val groups = tx.groupStates() { it: State

-> it.issuanceDef } + val groups = tx.groupStates() { it: State

-> it.aggregateState } for ((inputs, outputs, key) in groups) { // Either inputs or outputs could be empty. - val issuer = key.issuer + val obligor = key.obligor val commands = commandGroups[key] ?: emptyList() requireThat { "there are no zero sized outputs" by outputs.none { it.amount.quantity == 0L } } - verifyCommandGroup(tx, commands, inputs, outputs, issuer, key) + verifyCommandGroup(tx, commands, inputs, outputs, obligor, key) } } } private fun verifyCommandGroup(tx: TransactionForContract, - commands: List>>, + commands: List>>, inputs: List>, outputs: List>, - issuer: Party, + obligor: Party, key: IssuanceDefinition

) { // We've already pre-grouped by currency amongst other fields, and verified above that every state specifies - // at least one acceptable cash issuance definition, so we can just use the first issuance definition to + // at least one acceptable issuance definition, so we can just use the first issuance definition to // determine currency - val currency = key.template.acceptableIssuanceDefinitions.first() + val issued = key.template.acceptableIssuedProducts.first() // Issue, default, net and settle commands are all single commands (there's only ever one of them, and // they exclude all other commands). val issueCommand = commands.select>().firstOrNull() - val defaultCommand = commands.select>().firstOrNull() + val setLifecycleCommand = commands.select>().firstOrNull() val settleCommand = commands.select>().firstOrNull() if (commands.size != 1) { @@ -308,8 +308,8 @@ class Obligation

: Contract { // Issue, default and net commands are special, and do not follow normal input/output summing rules, so // deal with them first - if (defaultCommand != null) { - verifyDefaultCommand(inputs, outputs, tx, defaultCommand) + if (setLifecycleCommand != null) { + verifySetLifecycleCommand(inputs, outputs, tx, setLifecycleCommand) } else { // Only the default command processes inputs/outputs that are not in the normal state // TODO: Need to be able to exit defaulted amounts @@ -318,15 +318,15 @@ class Obligation

: Contract { "all outputs are in the normal state " by outputs.all { it.lifecycle == Lifecycle.NORMAL } } if (issueCommand != null) { - verifyIssueCommand(inputs, outputs, tx, issueCommand, currency, issuer) + verifyIssueCommand(inputs, outputs, tx, issueCommand, issued, obligor) } else if (settleCommand != null) { // Perhaps through an abundance of caution, settlement is enforced as its own command. // This could perhaps be merged into verifyBalanceChange() later, however doing so introduces a lot // of scope for making it more opaque what's going on in a transaction and whether it's as expected // by all parties. - verifySettleCommand(inputs, outputs, tx, settleCommand, currency, issuer, key) + verifySettleCommand(inputs, outputs, tx, settleCommand, issued, obligor, key) } else { - verifyBalanceChange(inputs, outputs, commands, currency, issuer) + verifyBalanceChange(inputs, outputs, commands, issued.product, obligor) } } } @@ -339,32 +339,32 @@ class Obligation

: Contract { */ private fun verifyBalanceChange(inputs: List>, outputs: List>, - commands: List>>, - currency: Issued

, - issuer: Party) { + commands: List>>, + product: P, + obligor: Party) { // Sum up how much settlement owed there is in the inputs, and the difference in outputs. The difference should // be matched by exit commands representing the extracted amount. val inputAmount = inputs.sumObligationsOrNull

() ?: throw IllegalArgumentException("there is at least one obligation input for this group") - val outputAmount = outputs.sumObligationsOrZero(currency) + val outputAmount = outputs.sumObligationsOrZero(product) val exitCommands = commands.select>() val requiredExitSignatures = HashSet() - val amountExitingLedger: Amount> = if (exitCommands.isNotEmpty()) { + val amountExitingLedger: Amount

= if (exitCommands.isNotEmpty()) { require(exitCommands.size == 1) { "There can only be one exit command" } val exitCommand = exitCommands.single() - // If we want to remove debt from the ledger, that must be signed for by the owner. For now we require exit - // commands to be signed by all input owners, unlocking the full input amount, rather than trying to detangle + // If we want to remove debt from the ledger, that must be signed for by the beneficiary. For now we require exit + // commands to be signed by all input beneficiarys, unlocking the full input amount, rather than trying to detangle // exactly who exited what. - requiredExitSignatures.addAll(inputs.map { it.owner }) + requiredExitSignatures.addAll(inputs.map { it.beneficiary }) exitCommand.value.amount } else { - Amount(0, currency) + Amount(0, product) } requireThat { "there are no zero sized inputs" by inputs.none { it.amount.quantity == 0L } - "at issuer ${issuer.name} the amounts balance" by + "at obligor ${obligor.name} the amounts balance" by (inputAmount == outputAmount + amountExitingLedger) } @@ -375,39 +375,36 @@ class Obligation

: Contract { * A default command mutates inputs and produces identical outputs, except that the lifecycle changes. */ @VisibleForTesting - protected fun verifyDefaultCommand(inputs: List>, - outputs: List>, - tx: TransactionForContract, - setLifecycleCommand: AuthenticatedObject>) { + protected fun verifySetLifecycleCommand(inputs: List>, + outputs: List>, + tx: TransactionForContract, + setLifecycleCommand: AuthenticatedObject>) { // Default must not change anything except lifecycle, so number of inputs and outputs must match // exactly. require(inputs.size == outputs.size) { "Number of inputs and outputs must match" } // If we have an default command, perform special processing: issued contracts can only be defaulted - // after the due date, and default/reset can only be done by the owner - val expectedOutputState: Lifecycle = setLifecycleCommand.value.lifecycle - val expectedInputState: Lifecycle - - expectedInputState = when (expectedOutputState) { - Lifecycle.DEFAULTED -> Lifecycle.NORMAL - Lifecycle.NORMAL -> Lifecycle.DEFAULTED - } + // after the due date, and default/reset can only be done by the beneficiary + val expectedInputLifecycle: Lifecycle = setLifecycleCommand.value.inverse + val expectedOutputLifecycle: Lifecycle = setLifecycleCommand.value.lifecycle // Check that we're past the deadline for ALL involved inputs, and that the output states correspond 1:1 for ((stateIdx, input) in inputs.withIndex()) { val actualOutput = outputs[stateIdx] val deadline = input.dueBefore + // TODO: Determining correct timestamp authority needs rework now that timestamping service is part of + // notary. val timestamp: TimestampCommand? = tx.commands.getTimestampByName("Mock Company 0", "Notary Service", "Bank A") - val expectedOutput: State

= input.copy(lifecycle = expectedOutputState) + val expectedOutput: State

= input.copy(lifecycle = expectedOutputLifecycle) requireThat { "there is a timestamp from the authority" by (timestamp != null) - "the due date has passed" by (timestamp?.after?.isBefore(deadline) ?: false) - "input state lifecycle is correct" by (input.lifecycle == expectedInputState) + "the due date has passed" by (timestamp!!.after?.isAfter(deadline) ?: false) + "input state lifecycle is correct" by (input.lifecycle == expectedInputLifecycle) "output state corresponds exactly to input state, with lifecycle changed" by (expectedOutput == actualOutput) } } - val owningPubKeys = inputs.map { it.owner }.toSet() + val owningPubKeys = inputs.map { it.beneficiary }.toSet() val keysThatSigned = setLifecycleCommand.signers.toSet() requireThat { "the owning keys are the same as the signing keys" by keysThatSigned.containsAll(owningPubKeys) @@ -419,16 +416,16 @@ class Obligation

: Contract { outputs: List>, tx: TransactionForContract, issueCommand: AuthenticatedObject>, - currency: Issued

, - issuer: Party) { + issued: Issued

, + obligor: Party) { // If we have an issue command, perform special processing: the group is must have no inputs, - // and that signatures are present for all issuers. + // and that signatures are present for all obligors. - val inputAmount = inputs.sumObligationsOrZero(currency) - val outputAmount = outputs.sumObligations

() + val inputAmount: Amount

= inputs.sumObligationsOrZero(issued.product) + val outputAmount: Amount

= outputs.sumObligations

() requireThat { "the issue command has a nonce" by (issueCommand.value.nonce != 0L) - "output deposits are owned by a command signer" by (issuer in issueCommand.signingParties) + "output deposits are owned by a command signer" by (obligor in issueCommand.signingParties) "output values sum to more than the inputs" by (outputAmount > inputAmount) "valid settlement issuance definition is not this issuance definition" by inputs.none { it.issuanceDef in it.acceptableIssuanceDefinitions } } @@ -448,24 +445,25 @@ class Obligation

: Contract { "all outputs are in the normal state " by outputs.all { it.lifecycle == Lifecycle.NORMAL } } - val token = netState.issued - // Create two maps of balances from issuers to owners, one for input states, the other for output states. - val inputBalances = extractAmountsDue(token, inputs) - val outputBalances = extractAmountsDue(token, outputs) + val template = netState.template + val product = template.product + // Create two maps of balances from obligors to beneficiaries, one for input states, the other for output states. + val inputBalances = extractAmountsDue(product, inputs) + val outputBalances = extractAmountsDue(product, outputs) // Sum the columns of the matrices. This will yield the net amount payable to/from each party to/from all other participants. // The two summaries must match, reflecting that the amounts owed match on both input and output. requireThat { - "all input states use the expected token" by (inputs.all { it.issuanceDef.issued == token }) - "all output states use the expected token" by (outputs.all { it.issuanceDef.issued == token }) + "all input states use the same template" by (inputs.all { it.template == template }) + "all output states use the same template" by (outputs.all { it.template == template }) "amounts owed on input and output must match" by (sumAmountsDue(inputBalances) == sumAmountsDue(outputBalances)) } // TODO: Handle proxies nominated by parties, i.e. a central clearing service - val involvedParties = inputs.map { it.owner }.union(inputs.map { it.issuer.owningKey }).toSet() + val involvedParties = inputs.map { it.beneficiary }.union(inputs.map { it.obligor.owningKey }).toSet() when (command.value.type) { // For close-out netting, allow any involved party to sign - NetType.CLOSE_OUT -> require(involvedParties.intersect(command.signers).isNotEmpty()) { "any involved party has signed" } + NetType.CLOSE_OUT -> require(command.signers.intersect(involvedParties).isNotEmpty()) { "any involved party has signed" } // Require signatures from all parties (this constraint can be changed for other contracts, and is used as a // placeholder while exact requirements are established), or fail the transaction. NetType.PAYMENT -> require(command.signers.containsAll(involvedParties)) { "all involved parties have signed" } @@ -479,19 +477,19 @@ class Obligation

: Contract { outputs: List>, tx: TransactionForContract, command: AuthenticatedObject>, - currency: Issued

, - issuer: Party, + issued: Issued

, + obligor: Party, key: IssuanceDefinition

) { val template = key.template - val inputAmount = inputs.sumObligationsOrNull

() ?: throw IllegalArgumentException("there is at least one obligation input for this group") - val outputAmount = outputs.sumObligationsOrZero(currency) + val inputAmount: Amount

= inputs.sumObligationsOrNull

() ?: throw IllegalArgumentException("there is at least one obligation input for this group") + val outputAmount: Amount

= outputs.sumObligationsOrZero(issued.product) - // Sum up all cash contracts that are moving and fulfil our requirements + // Sum up all cash state objects that are moving and fulfil our requirements // The cash contract verification handles ensuring there's inputs enough to cover the output states, we only // care about counting how much cash is output in this transaction. We then calculate the difference in // settlement amounts between the transaction inputs and outputs, and the two must match. No elimination is - // done of amounts paid in by each owner, as it's presumed the owners have enough sense to do that themselves. + // done of amounts paid in by each beneficiary, as it's presumed the beneficiarys have enough sense to do that themselves. // Therefore if someone actually signed the following transaction: // // Inputs: @@ -500,11 +498,11 @@ class Obligation

: Contract { // Outputs: // £1m cash owned by B // Commands: - // Settle (signed by B) + // Settle (signed by A) // Move (signed by B) // // That would pass this check. Ensuring they do not is best addressed in the transaction generation stage. - val cashStates = tx.outStates.filterIsInstance>() + val cashStates = tx.outputs.filterIsInstance>() val acceptableCashStates = cashStates // TODO: This filter is nonsense, because it just checks there is a cash contract loaded, we need to // verify the cash contract is the cash contract we expect. @@ -512,8 +510,8 @@ class Obligation

: Contract { // attachments.mustHaveOneOf(key.acceptableCashContract) .filter { it.contract.legalContractReference in template.acceptableContracts } // Restrict the states to those of the correct issuance definition (this normally - // covers currency and issuer, but is opaque to us) - .filter { it.issuanceDef in template.acceptableIssuanceDefinitions } + // covers currency and obligor, but is opaque to us) + .filter { it.issuanceDef in template.acceptableIssuedProducts } // Catch that there's nothing useful here, so we can dump out a useful error requireThat { "there are cash state outputs" by (cashStates.size > 0) @@ -525,12 +523,12 @@ class Obligation

: Contract { // this one. val moveCommands = tx.commands.select() var totalPenniesSettled = 0L - val requiredSigners = inputs.map { it.issuer.owningKey }.toSet() + val requiredSigners = inputs.map { it.obligor.owningKey }.toSet() - for ((owner, obligations) in inputs.groupBy { it.owner }) { - val settled = amountReceivedByOwner[owner]?.sumCashOrNull() + for ((beneficiary, obligations) in inputs.groupBy { it.beneficiary }) { + val settled = amountReceivedByOwner[beneficiary]?.sumCashOrNull() if (settled != null) { - val debt = obligations.sumObligationsOrZero(currency) + val debt = obligations.sumObligationsOrZero(issued) require(settled.quantity <= debt.quantity) { "Payment of $settled must not exceed debt $debt" } totalPenniesSettled += settled.quantity } @@ -542,19 +540,19 @@ class Obligation

: Contract { "all move commands relate to this contract" by (moveCommands.map { it.value.contractHash } .all { it == null || it == legalContractReference }) "contract does not try to consume itself" by (moveCommands.map { it.value }.filterIsInstance>() - .none { it.aggregateState.issued in template.acceptableIssuanceDefinitions }) - "amounts paid must match recipients to settle" by inputs.map { it.owner }.containsAll(amountReceivedByOwner.keys) - "signatures are present from all issuers" by command.signers.containsAll(requiredSigners) + .none { it.aggregateState == key }) + "amounts paid must match recipients to settle" by inputs.map { it.beneficiary }.containsAll(amountReceivedByOwner.keys) + "signatures are present from all obligors" by command.signers.containsAll(requiredSigners) "there are no zero sized inputs" by inputs.none { it.amount.quantity == 0L } - "at issuer ${issuer.name} the obligations after settlement balance" by - (inputAmount == outputAmount + Amount(totalPenniesSettled, currency)) + "at obligor ${obligor.name} the obligations after settlement balance" by + (inputAmount == outputAmount + Amount(totalPenniesSettled, issued.product)) } } /** * Generate a transaction performing close-out netting of two or more states. * - * @param signer the party who will sign the transaction. Must be one of the issuer or owner. + * @param signer the party who will sign the transaction. Must be one of the obligor or beneficiary. * @param states two or more states, which must be compatible for bilateral netting (same issuance definitions, * and same parties involved). */ @@ -570,7 +568,9 @@ class Obligation

: Contract { "signer is in the state parties" by (signer in netState!!.partyKeys) } - tx.addOutputState(states.reduce { stateA, stateB -> stateA.net(stateB) }) + val out = states.reduce { stateA, stateB -> stateA.net(stateB) } + if (out.quantity > 0L) + tx.addOutputState(out) tx.addCommand(Commands.Net(NetType.PAYMENT), signer) } @@ -578,20 +578,20 @@ class Obligation

: Contract { * Puts together an issuance transaction for the specified amount that starts out being owned by the given pubkey. */ fun generateIssue(tx: TransactionBuilder, - issuer: Party, + obligor: Party, issuanceDef: StateTemplate

, pennies: Long, - owner: PublicKey, + beneficiary: PublicKey, notary: Party) { check(tx.inputStates().isEmpty()) check(tx.outputStates().map { it.data }.sumObligationsOrNull

() == null) - val aggregateState = IssuanceDefinition(issuer, issuanceDef) - tx.addOutputState(State(Lifecycle.NORMAL, issuer, issuanceDef, pennies, owner), notary) - tx.addCommand(Commands.Issue(aggregateState), issuer.owningKey) + val aggregateState = IssuanceDefinition(obligor, issuanceDef) + tx.addOutputState(State(Lifecycle.NORMAL, obligor, issuanceDef, pennies, beneficiary), notary) + tx.addCommand(Commands.Issue(aggregateState), obligor.owningKey) } fun generatePaymentNetting(tx: TransactionBuilder, - currency: Issued

, + issued: Issued

, notary: Party, vararg states: State

) { requireThat { @@ -599,20 +599,20 @@ class Obligation

: Contract { } val groups = states.groupBy { it.multilateralNetState } val partyLookup = HashMap() - val signers = states.map { it.owner }.union(states.map { it.issuer.owningKey }).toSet() + val signers = states.map { it.beneficiary }.union(states.map { it.obligor.owningKey }).toSet() // Create a lookup table of the party that each public key represents. - states.map { it.issuer }.forEach { partyLookup.put(it.owningKey, it) } + states.map { it.obligor }.forEach { partyLookup.put(it.owningKey, it) } for ((netState, groupStates) in groups) { // Extract the net balances - val netBalances = netAmountsDue(extractAmountsDue(currency, states.asIterable())) + val netBalances = netAmountsDue(extractAmountsDue(issued.product, states.asIterable())) netBalances // Convert the balances into obligation state objects .map { entry -> State(Lifecycle.NORMAL, partyLookup[entry.key.first]!!, - netState.issuanceDef, entry.value.quantity, entry.key.second) + netState.template, entry.value.quantity, entry.key.second) } // Add the new states to the TX .forEach { tx.addOutputState(it, notary) } @@ -647,7 +647,7 @@ class Obligation

: Contract { val outState = stateAndRef.state.data.copy(lifecycle = lifecycle) tx.addInputState(stateAndRef) tx.addOutputState(outState, notary) - partiesUsed.add(stateAndRef.state.data.owner) + partiesUsed.add(stateAndRef.state.data.beneficiary) } tx.addCommand(Commands.SetLifecycle(aggregateState, lifecycle), partiesUsed.distinct()) } @@ -659,23 +659,22 @@ class Obligation

: Contract { * only a single settlement command can be present in a transaction, to avoid potential problems with allocating * cash to different obligation issuances. * @param cashStatesAndRefs a list of cash state objects, which MUST all be in the same currency. It is strongly - * encouraged that these all have the same owner. + * encouraged that these all have the same beneficiary. */ fun generateSettle(tx: TransactionBuilder, statesAndRefs: Iterable>>, cashStatesAndRefs: Iterable>>, notary: Party) { val states = statesAndRefs.map { it.state } - val notary = states.first().notary - val obligationIssuer = states.first().data.issuer - val obligationOwner = states.first().data.owner + val obligationIssuer = states.first().data.obligor + val obligationOwner = states.first().data.beneficiary requireThat { "all cash states use the same notary" by (cashStatesAndRefs.all { it.state.notary == notary }) "all obligation states are in the normal state" by (statesAndRefs.all { it.state.data.lifecycle == Lifecycle.NORMAL }) "all obligation states use the same notary" by (statesAndRefs.all { it.state.notary == notary }) - "all obligation states have the same issuer" by (statesAndRefs.all { it.state.data.issuer == obligationIssuer }) - "all obligation states have the same owner" by (statesAndRefs.all { it.state.data.owner == obligationOwner }) + "all obligation states have the same obligor" by (statesAndRefs.all { it.state.data.obligor == obligationIssuer }) + "all obligation states have the same beneficiary" by (statesAndRefs.all { it.state.data.beneficiary == obligationOwner }) } // TODO: A much better (but more complex) solution would be to have two iterators, one for obligations, @@ -684,24 +683,24 @@ class Obligation

: Contract { val issuanceDef = getIssuanceDefinitionOrThrow(statesAndRefs.map { it.state.data }) val template = issuanceDef.template - val obligationTotal: Amount> = states.map { it.data }.sumObligations

() - var obligationRemaining: Amount> = obligationTotal + val obligationTotal: Amount

= states.map { it.data }.sumObligations

() + var obligationRemaining: Amount

= obligationTotal val cashSigners = HashSet() statesAndRefs.forEach { tx.addInputState(it) } - // Move the cash to the new owner + // Move the cash to the new beneficiary cashStatesAndRefs.forEach { if (obligationRemaining.quantity > 0L) { val cashState = it.state tx.addInputState(it) - if (obligationRemaining >= cashState.data.amount) { - tx.addOutputState(cashState.data.move(cashState.data.amount, obligationOwner), notary) - obligationRemaining -= cashState.data.amount + if (obligationRemaining >= cashState.data.productAmount) { + tx.addOutputState(cashState.data.move(cashState.data.productAmount, obligationOwner), notary) + obligationRemaining -= cashState.data.productAmount } else { - // Split the state in two, sending the change back to the previous owner + // Split the state in two, sending the change back to the previous beneficiary tx.addOutputState(cashState.data.move(obligationRemaining, obligationOwner), notary) - tx.addOutputState(cashState.data.move(cashState.data.amount - obligationRemaining, cashState.data.owner), notary) + tx.addOutputState(cashState.data.move(cashState.data.productAmount - obligationRemaining, cashState.data.owner), notary) obligationRemaining -= Amount(0L, obligationRemaining.token) } cashSigners.add(cashState.data.owner) @@ -731,17 +730,17 @@ class Obligation

: Contract { /** - * Convert a list of settlement states into total from each issuer to a owner. + * Convert a list of settlement states into total from each obligor to a beneficiary. * - * @return a map of issuer/owner pairs to the balance due. + * @return a map of obligor/beneficiary pairs to the balance due. */ -fun

extractAmountsDue(currency: Issued

, states: Iterable>): Map, Amount>> { - val balances = HashMap, Amount>>() +fun

extractAmountsDue(product: P, states: Iterable>): Map, Amount

> { + val balances = HashMap, Amount

>() states.forEach { state -> - val key = Pair(state.issuer.owningKey, state.owner) - val balance = balances[key] ?: Amount(0L, currency) - balances[key] = balance + state.amount + val key = Pair(state.obligor.owningKey, state.beneficiary) + val balance = balances[key] ?: Amount(0L, product) + balances[key] = balance + state.productAmount } return balances @@ -750,12 +749,12 @@ fun

extractAmountsDue(currency: Issued

, states: Iterable netAmountsDue(balances: Map, Amount>>): Map, Amount>> { - val nettedBalances = HashMap, Amount>>() +fun

netAmountsDue(balances: Map, Amount

>): Map, Amount

> { + val nettedBalances = HashMap, Amount

>() balances.forEach { balance -> - val (issuer, owner) = balance.key - val oppositeKey = Pair(owner, issuer) + val (obligor, beneficiary) = balance.key + val oppositeKey = Pair(beneficiary, obligor) val opposite = (balances[oppositeKey] ?: Amount(0L, balance.value.token)) // Drop zero balances if (balance.value > opposite) { @@ -770,9 +769,9 @@ fun

netAmountsDue(balances: Map, Amount /** * Calculate the total balance movement for each party in the transaction, based off a summary of balances between - * each issuer and owner. + * each obligor and beneficiary. * - * @param balances payments due, indexed by issuer and owner. Zero balances are stripped from the map before being + * @param balances payments due, indexed by obligor and beneficiary. Zero balances are stripped from the map before being * returned. */ fun

sumAmountsDue(balances: Map, Amount

>): Map { @@ -785,11 +784,11 @@ fun

sumAmountsDue(balances: Map, Amount

>): Map } for ((key, amount) in balances) { - val (issuer, owner) = key - // Subtract it from the issuer - sum[issuer] = sum[issuer]!! - amount.quantity - // Add it to the owner - sum[owner] = sum[owner]!! + amount.quantity + val (obligor, beneficiary) = key + // Subtract it from the obligor + sum[obligor] = sum[obligor]!! - amount.quantity + // Add it to the beneficiary + sum[beneficiary] = sum[beneficiary]!! + amount.quantity } // Strip zero balances @@ -807,13 +806,14 @@ fun

sumAmountsDue(balances: Map, Amount

>): Map /** Sums the cash states in the list, throwing an exception if there are none. * All cash states in the list are presumed to be nettable. */ -fun

Iterable.sumObligations() = filterIsInstance>().map { it.amount }.sumOrThrow() +fun

Iterable.sumObligations(): Amount

+ = filterIsInstance>().map { it.amount }.sumOrThrow() /** Sums the cash settlement states in the list, returning null if there are none. */ -fun

Iterable.sumObligationsOrNull() +fun

Iterable.sumObligationsOrNull(): Amount

? = filterIsInstance>().filter { it.lifecycle == Obligation.Lifecycle.NORMAL }.map { it.amount }.sumOrNull() /** Sums the cash settlement states in the list, returning zero of the given currency if there are none. */ -fun

Iterable.sumObligationsOrZero(currency: Issued

) - = filterIsInstance>().filter { it.lifecycle == Obligation.Lifecycle.NORMAL }.map { it.amount }.sumOrZero(currency) +fun

Iterable.sumObligationsOrZero(product: P): Amount

+ = filterIsInstance>().filter { it.lifecycle == Obligation.Lifecycle.NORMAL }.map { it.amount }.sumOrZero(product) diff --git a/experimental/src/main/kotlin/com/r3corda/contracts/testing/ExperimentalTestUtils.kt b/experimental/src/main/kotlin/com/r3corda/contracts/testing/ExperimentalTestUtils.kt index d88cb52867..112e5f03d6 100644 --- a/experimental/src/main/kotlin/com/r3corda/contracts/testing/ExperimentalTestUtils.kt +++ b/experimental/src/main/kotlin/com/r3corda/contracts/testing/ExperimentalTestUtils.kt @@ -7,6 +7,7 @@ import com.r3corda.core.contracts.Issued import com.r3corda.core.crypto.NullPublicKey import com.r3corda.core.crypto.Party import com.r3corda.core.testing.MINI_CORP +import com.r3corda.core.testing.TEST_TX_TIME import com.r3corda.core.utilities.nonEmptySetOf import java.security.PublicKey import java.time.Instant @@ -14,20 +15,23 @@ import java.util.* object JavaExperimental { @JvmStatic fun at(state: Obligation.State, dueBefore: Instant) = state.copy(template = state.template.copy(dueBefore = dueBefore)) - @JvmStatic fun between(state: Obligation.State, parties: Pair) = state.copy(issuer = parties.first, owner = parties.second) - @JvmStatic fun ownedBy(state: Obligation.State, owner: PublicKey) = state.copy(owner = owner) - @JvmStatic fun issuedBy(state: Obligation.State, party: Party) = state.copy(issuer = party) + @JvmStatic fun at(issuanceDef: Obligation.IssuanceDefinition, dueBefore: Instant) = issuanceDef.copy(template = issuanceDef.template.copy(dueBefore = dueBefore)) + @JvmStatic fun between(state: Obligation.State, parties: Pair) = state.copy(obligor = parties.first, beneficiary = parties.second) + @JvmStatic fun ownedBy(state: Obligation.State, owner: PublicKey) = state.copy(beneficiary = owner) + @JvmStatic fun issuedBy(state: Obligation.State, party: Party) = state.copy(obligor = party) + // Allows you to write 100.DOLLARS.OBLIGATION @JvmStatic fun OBLIGATION_DEF(issued: Issued) - = Obligation.StateTemplate(nonEmptySetOf(Cash().legalContractReference), nonEmptySetOf(issued), Instant.parse("2020-01-01T17:00:00Z")) + = Obligation.StateTemplate(nonEmptySetOf(Cash().legalContractReference), nonEmptySetOf(issued), TEST_TX_TIME) @JvmStatic fun OBLIGATION(amount: Amount>) = Obligation.State(Obligation.Lifecycle.NORMAL, MINI_CORP, - OBLIGATION_DEF(amount.token), amount.quantity, NullPublicKey) + OBLIGATION_DEF(amount.token), amount.quantity, NullPublicKey) } infix fun Obligation.State.`at`(dueBefore: Instant) = JavaExperimental.at(this, dueBefore) +infix fun Obligation.IssuanceDefinition.`at`(dueBefore: Instant) = JavaExperimental.at(this, dueBefore) infix fun Obligation.State.`between`(parties: Pair) = JavaExperimental.between(this, parties) infix fun Obligation.State.`owned by`(owner: PublicKey) = JavaExperimental.ownedBy(this, owner) infix fun Obligation.State.`issued by`(party: Party) = JavaExperimental.issuedBy(this, party) -// Allows you to write 100.DOLLARS.OBLIGATION +/** Allows you to write 100.DOLLARS.CASH */ val Issued.OBLIGATION_DEF: Obligation.StateTemplate get() = JavaExperimental.OBLIGATION_DEF(this) val Amount>.OBLIGATION: Obligation.State get() = JavaExperimental.OBLIGATION(this) diff --git a/experimental/src/test/kotlin/com/r3corda/contracts/ObligationTests.kt b/experimental/src/test/kotlin/com/r3corda/contracts/ObligationTests.kt index 84be8b37df..6f264bc5df 100644 --- a/experimental/src/test/kotlin/com/r3corda/contracts/ObligationTests.kt +++ b/experimental/src/test/kotlin/com/r3corda/contracts/ObligationTests.kt @@ -5,11 +5,11 @@ import com.r3corda.contracts.Obligation.Lifecycle import com.r3corda.contracts.testing.* import com.r3corda.core.contracts.* import com.r3corda.core.crypto.SecureHash -import com.r3corda.core.seconds import com.r3corda.core.testing.* import com.r3corda.core.utilities.nonEmptySetOf import org.junit.Test import java.security.PublicKey +import java.time.Duration import java.time.Instant import java.util.* import kotlin.test.* @@ -25,15 +25,15 @@ class ObligationTests { val sixPm = Instant.parse("2016-01-01T18:00:00.00Z") val notary = MEGA_CORP val megaCorpDollarSettlement = Obligation.StateTemplate(trustedCashContract, megaIssuedDollars, fivePm) - val megaCorpPoundSettlement = megaCorpDollarSettlement.copy(acceptableIssuanceDefinitions = megaIssuedPounds) + val megaCorpPoundSettlement = megaCorpDollarSettlement.copy(acceptableIssuedProducts = megaIssuedPounds) val inState = Obligation.State( lifecycle = Lifecycle.NORMAL, - issuer = MEGA_CORP, + obligor = MEGA_CORP, template = megaCorpDollarSettlement, quantity = 1000.DOLLARS.quantity, - owner = DUMMY_PUBKEY_1 + beneficiary = DUMMY_PUBKEY_1 ) - val outState = inState.copy(owner = DUMMY_PUBKEY_2) + val outState = inState.copy(beneficiary = DUMMY_PUBKEY_2) private fun obligationTestRoots(group: TransactionGroupDSL>) = group.Roots() .transaction(oneMillionDollars.OBLIGATION `between` Pair(ALICE, BOB_PUBKEY) `with notary` DUMMY_NOTARY label "Alice's $1,000,000 obligation to Bob") @@ -97,9 +97,9 @@ class ObligationTests { transaction { output { Obligation.State( - issuer = MINI_CORP, + obligor = MINI_CORP, quantity = 1000.DOLLARS.quantity, - owner = DUMMY_PUBKEY_1, + beneficiary = DUMMY_PUBKEY_1, template = megaCorpDollarSettlement ) } @@ -114,12 +114,12 @@ class ObligationTests { // Test generation works. val ptx = TransactionType.General.Builder(DUMMY_NOTARY) Obligation().generateIssue(ptx, MINI_CORP, megaCorpDollarSettlement, 100.DOLLARS.quantity, - owner = DUMMY_PUBKEY_1, notary = DUMMY_NOTARY) + beneficiary = DUMMY_PUBKEY_1, notary = DUMMY_NOTARY) assertTrue(ptx.inputStates().isEmpty()) val s = ptx.outputStates()[0].data as Obligation.State - assertEquals(100.DOLLARS `issued by` MEGA_CORP.ref(1), s.amount) - assertEquals(MINI_CORP, s.issuer) - assertEquals(DUMMY_PUBKEY_1, s.owner) + assertEquals(100.DOLLARS, s.amount) + assertEquals(MINI_CORP, s.obligor) + assertEquals(DUMMY_PUBKEY_1, s.beneficiary) assertTrue(ptx.commands()[0].value is Obligation.Commands.Issue<*>) assertEquals(MINI_CORP_PUBKEY, ptx.commands()[0].signers[0]) @@ -131,7 +131,7 @@ class ObligationTests { // Move fails: not allowed to summon money. tweak { arg(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } - this `fails requirement` "at issuer MegaCorp the amounts balance" + this `fails requirement` "at obligor MegaCorp the amounts balance" } // Issue works. @@ -189,18 +189,46 @@ class ObligationTests { @Test(expected = IllegalStateException::class) fun `reject issuance with inputs`() { // Issue some obligation - var ptx = TransactionType.General.Builder(DUMMY_NOTARY) - - Obligation().generateIssue(ptx, MINI_CORP, megaCorpDollarSettlement, 100.DOLLARS.quantity, - owner = MINI_CORP_PUBKEY, notary = DUMMY_NOTARY) - ptx.signWith(MINI_CORP_KEY) - val tx = ptx.toSignedTransaction() + val tx = TransactionType.General.Builder(DUMMY_NOTARY).apply { + Obligation().generateIssue(this, MINI_CORP, megaCorpDollarSettlement, 100.DOLLARS.quantity, + beneficiary = MINI_CORP_PUBKEY, notary = DUMMY_NOTARY) + signWith(MINI_CORP_KEY) + }.toSignedTransaction() // Include the previously issued obligation in a new issuance command - ptx = TransactionType.General.Builder(DUMMY_NOTARY) + val ptx = TransactionType.General.Builder(DUMMY_NOTARY) ptx.addInputState(tx.tx.outRef>(0)) Obligation().generateIssue(ptx, MINI_CORP, megaCorpDollarSettlement, 100.DOLLARS.quantity, - owner = MINI_CORP_PUBKEY, notary = DUMMY_NOTARY) + beneficiary = MINI_CORP_PUBKEY, notary = DUMMY_NOTARY) + } + + /** Test generating a transaction to net two obligations of the same size, and therefore there are no outputs. */ + @Test + fun `generate close-out net transaction`() { + val obligationAliceToBob = oneMillionDollars.OBLIGATION `between` Pair(ALICE, BOB_PUBKEY) + val obligationBobToAlice = oneMillionDollars.OBLIGATION `between` Pair(BOB, ALICE_PUBKEY) + val tx = TransactionType.General.Builder(DUMMY_NOTARY).apply { + Obligation().generateCloseOutNetting(this, ALICE_PUBKEY, obligationAliceToBob, obligationBobToAlice) + signWith(ALICE_KEY) + signWith(DUMMY_NOTARY_KEY) + }.toSignedTransaction().tx + assertEquals(0, tx.outputs.size) + } + + /** Test generating a transaction to net two obligations of the different sizes, and confirm the balance is correct. */ + @Test + fun `generate close-out net transaction with remainder`() { + val obligationAliceToBob = (2000000.DOLLARS `issued by` defaultIssuer).OBLIGATION `between` Pair(ALICE, BOB_PUBKEY) + val obligationBobToAlice = oneMillionDollars.OBLIGATION `between` Pair(BOB, ALICE_PUBKEY) + val tx = TransactionType.General.Builder(DUMMY_NOTARY).apply { + Obligation().generateCloseOutNetting(this, ALICE_PUBKEY, obligationAliceToBob, obligationBobToAlice) + signWith(ALICE_KEY) + signWith(DUMMY_NOTARY_KEY) + }.toSignedTransaction().tx + assertEquals(1, tx.outputs.size) + + val actual = tx.outputs[0].data + assertEquals((1000000.DOLLARS `issued by` defaultIssuer).OBLIGATION `between` Pair(ALICE, BOB_PUBKEY), actual) } /** Test generating a transaction to net two obligations of the same size, and therefore there are no outputs. */ @@ -208,9 +236,13 @@ class ObligationTests { fun `generate payment net transaction`() { val obligationAliceToBob = oneMillionDollars.OBLIGATION `between` Pair(ALICE, BOB_PUBKEY) val obligationBobToAlice = oneMillionDollars.OBLIGATION `between` Pair(BOB, ALICE_PUBKEY) - val ptx = TransactionType.General.Builder(DUMMY_NOTARY) - Obligation().generatePaymentNetting(ptx, defaultUsd, DUMMY_NOTARY, obligationAliceToBob, obligationBobToAlice) - assertEquals(0, ptx.outputStates().size) + val tx = TransactionType.General.Builder(DUMMY_NOTARY).apply { + Obligation().generatePaymentNetting(this, defaultUsd, DUMMY_NOTARY, obligationAliceToBob, obligationBobToAlice) + signWith(ALICE_KEY) + signWith(BOB_KEY) + signWith(DUMMY_NOTARY_KEY) + }.toSignedTransaction().tx + assertEquals(0, tx.outputs.size) } /** Test generating a transaction to two obligations, where one is bigger than the other and therefore there is a remainder. */ @@ -218,25 +250,27 @@ class ObligationTests { fun `generate payment net transaction with remainder`() { val obligationAliceToBob = oneMillionDollars.OBLIGATION `between` Pair(ALICE, BOB_PUBKEY) val obligationBobToAlice = (2000000.DOLLARS `issued by` defaultIssuer).OBLIGATION `between` Pair(BOB, ALICE_PUBKEY) - val ptx = TransactionType.General.Builder(DUMMY_NOTARY) - Obligation().generatePaymentNetting(ptx, defaultUsd, DUMMY_NOTARY, obligationAliceToBob, obligationBobToAlice) - assertEquals(1, ptx.outputStates().size) - val out = ptx.outputStates().single().data as Obligation.State - assertEquals(1000000.DOLLARS.quantity, out.quantity) - assertEquals(BOB, out.issuer) - assertEquals(ALICE_PUBKEY, out.owner) + val tx = TransactionType.General.Builder(DUMMY_NOTARY).apply { + Obligation().generatePaymentNetting(this, defaultUsd, DUMMY_NOTARY, obligationAliceToBob, obligationBobToAlice) + signWith(ALICE_KEY) + signWith(BOB_KEY) + }.toSignedTransaction().tx + assertEquals(1, tx.outputs.size) + val expected = obligationBobToAlice.copy(quantity = obligationBobToAlice.quantity - obligationAliceToBob.quantity) + val actual = tx.outputs[0].data + assertEquals(expected, actual) } /** Test generating a transaction to mark outputs as having defaulted. */ @Test fun `generate set lifecycle`() { - // Issue some obligation - val dueBefore = Instant.parse("2010-01-01T17:00:00Z") + // We don't actually verify the states, this is just here to make things look sensible + val dueBefore = TEST_TX_TIME - Duration.ofDays(7) // Generate a transaction issuing the obligation var tx = TransactionType.General.Builder(DUMMY_NOTARY).apply { Obligation().generateIssue(this, MINI_CORP, megaCorpDollarSettlement.copy(dueBefore = dueBefore), 100.DOLLARS.quantity, - owner = MINI_CORP_PUBKEY, notary = DUMMY_NOTARY) + beneficiary = MINI_CORP_PUBKEY, notary = DUMMY_NOTARY) signWith(MINI_CORP_KEY) }.toSignedTransaction() var stateAndRef = tx.tx.outRef>(0) @@ -245,44 +279,47 @@ class ObligationTests { tx = TransactionType.General.Builder(DUMMY_NOTARY).apply { Obligation().generateSetLifecycle(this, listOf(stateAndRef), Obligation.Lifecycle.DEFAULTED, DUMMY_NOTARY) signWith(MINI_CORP_KEY) - }.toSignedTransaction(false) + signWith(DUMMY_NOTARY_KEY) + }.toSignedTransaction() assertEquals(1, tx.tx.outputs.size) assertEquals(stateAndRef.state.data.copy(lifecycle = Obligation.Lifecycle.DEFAULTED), tx.tx.outputs[0].data) + assertTrue(tx.verify().isEmpty()) // And set it back stateAndRef = tx.tx.outRef>(0) tx = TransactionType.General.Builder(DUMMY_NOTARY).apply { Obligation().generateSetLifecycle(this, listOf(stateAndRef), Obligation.Lifecycle.NORMAL, DUMMY_NOTARY) signWith(MINI_CORP_KEY) - }.toSignedTransaction(false) + signWith(DUMMY_NOTARY_KEY) + }.toSignedTransaction() assertEquals(1, tx.tx.outputs.size) assertEquals(stateAndRef.state.data.copy(lifecycle = Obligation.Lifecycle.NORMAL), tx.tx.outputs[0].data) + assertTrue(tx.verify().isEmpty()) } /** Test generating a transaction to settle an obligation. */ @Test fun `generate settlement transaction`() { - var ptx: TransactionBuilder - - // Generate a transaction to issue the cash we'll need - ptx = TransactionType.General.Builder(DUMMY_NOTARY) - Cash().generateIssue(ptx, 100.DOLLARS `issued by` defaultIssuer, MEGA_CORP_PUBKEY, DUMMY_NOTARY) - ptx.signWith(MEGA_CORP_KEY) - val cashTx = ptx.toSignedTransaction().tx + val cashTx = TransactionType.General.Builder(DUMMY_NOTARY).apply { + Cash().generateIssue(this, 100.DOLLARS `issued by` defaultIssuer, MINI_CORP_PUBKEY, DUMMY_NOTARY) + signWith(MEGA_CORP_KEY) + }.toSignedTransaction().tx // Generate a transaction issuing the obligation - ptx = TransactionType.General.Builder(DUMMY_NOTARY) - Obligation().generateIssue(ptx, MINI_CORP, megaCorpDollarSettlement, 100.DOLLARS.quantity, - owner = MINI_CORP_PUBKEY, notary = DUMMY_NOTARY) - ptx.signWith(MINI_CORP_KEY) - val obligationTx = ptx.toSignedTransaction().tx + val obligationTx = TransactionType.General.Builder(DUMMY_NOTARY).apply { + Obligation().generateIssue(this, MINI_CORP, megaCorpDollarSettlement, 100.DOLLARS.quantity, + beneficiary = MINI_CORP_PUBKEY, notary = DUMMY_NOTARY) + signWith(MINI_CORP_KEY) + }.toSignedTransaction().tx // Now generate a transaction settling the obligation - ptx = TransactionType.General.Builder(DUMMY_NOTARY) - val stateAndRef = obligationTx.outRef>(0) - Obligation().generateSettle(ptx, listOf(obligationTx.outRef(0)), listOf(cashTx.outRef(0)), DUMMY_NOTARY) - assertEquals(2, ptx.inputStates().size) - assertEquals(1, ptx.outputStates().size) + val settleTx = TransactionType.General.Builder(DUMMY_NOTARY).apply { + Obligation().generateSettle(this, listOf(obligationTx.outRef(0)), listOf(cashTx.outRef(0)), DUMMY_NOTARY) + signWith(DUMMY_NOTARY_KEY) + signWith(MINI_CORP_KEY) + }.toSignedTransaction().tx + assertEquals(2, settleTx.inputs.size) + assertEquals(1, settleTx.outputs.size) } @Test @@ -397,7 +434,7 @@ class ObligationTests { input("Alice's $1,000,000 obligation to Bob") input("Alice's $1,000,000") output("Bob's $1,000,000") { 1000000.DOLLARS.CASH `issued by` defaultIssuer `owned by` BOB_PUBKEY } - arg(ALICE_PUBKEY) { Obligation.Commands.Settle(Obligation.IssuanceDefinition(ALICE, defaultUsd.OBLIGATION_DEF), oneMillionDollars) } + arg(ALICE_PUBKEY) { Obligation.Commands.Settle(Obligation.IssuanceDefinition(ALICE, defaultUsd.OBLIGATION_DEF), Amount(oneMillionDollars.quantity, USD)) } arg(ALICE_PUBKEY) { Cash.Commands.Move(Obligation().legalContractReference) } } }.verify() @@ -415,13 +452,30 @@ class ObligationTests { } }.expectFailureOfTx(1, "there is a timestamp from the authority") - // Try defaulting an obligation + // Try defaulting an obligation due in the future + val pastTestTime = TEST_TX_TIME - Duration.ofDays(7) + val futureTestTime = TEST_TX_TIME + Duration.ofDays(7) transactionGroupFor>() { - obligationTestRoots(this) + roots { + transaction(oneMillionDollars.OBLIGATION `between` Pair(ALICE, BOB_PUBKEY) `at` futureTestTime `with notary` DUMMY_NOTARY label "Alice's $1,000,000 obligation to Bob") + } transaction("Settlement") { input("Alice's $1,000,000 obligation to Bob") - output("Alice's defaulted $1,000,000 obligation to Bob") { (oneMillionDollars.OBLIGATION `between` Pair(ALICE, BOB_PUBKEY)).copy(lifecycle = Obligation.Lifecycle.DEFAULTED) } - arg(BOB_PUBKEY) { Obligation.Commands.SetLifecycle(Obligation.IssuanceDefinition(ALICE, defaultUsd.OBLIGATION_DEF), Obligation.Lifecycle.DEFAULTED) } + output("Alice's defaulted $1,000,000 obligation to Bob") { (oneMillionDollars.OBLIGATION `between` Pair(ALICE, BOB_PUBKEY) `at` futureTestTime).copy(lifecycle = Obligation.Lifecycle.DEFAULTED) } + arg(BOB_PUBKEY) { Obligation.Commands.SetLifecycle(Obligation.IssuanceDefinition(ALICE, defaultUsd.OBLIGATION_DEF) `at` futureTestTime, Obligation.Lifecycle.DEFAULTED) } + timestamp(TEST_TX_TIME) + } + }.expectFailureOfTx(1, "the due date has passed") + + // Try defaulting an obligation that is now in the past + transactionGroupFor>() { + roots { + transaction(oneMillionDollars.OBLIGATION `between` Pair(ALICE, BOB_PUBKEY) `at` pastTestTime `with notary` DUMMY_NOTARY label "Alice's $1,000,000 obligation to Bob") + } + transaction("Settlement") { + input("Alice's $1,000,000 obligation to Bob") + output("Alice's defaulted $1,000,000 obligation to Bob") { (oneMillionDollars.OBLIGATION `between` Pair(ALICE, BOB_PUBKEY) `at` pastTestTime).copy(lifecycle = Obligation.Lifecycle.DEFAULTED) } + arg(BOB_PUBKEY) { Obligation.Commands.SetLifecycle(Obligation.IssuanceDefinition(ALICE, defaultUsd.OBLIGATION_DEF) `at` pastTestTime, Obligation.Lifecycle.DEFAULTED) } timestamp(TEST_TX_TIME) } }.verify() @@ -434,12 +488,12 @@ class ObligationTests { arg(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } tweak { input { inState } - for (i in 1..4) output { inState.copy(quantity = inState.quantity / 4) } + repeat(4) { output { inState.copy(quantity = inState.quantity / 4) } } this.accepts() } // Merging 4 inputs into 2 outputs works. tweak { - for (i in 1..4) input { inState.copy(quantity = inState.quantity / 4) } + repeat(4) { input { inState.copy(quantity = inState.quantity / 4) } } output { inState.copy(quantity = inState.quantity / 2) } output { inState.copy(quantity = inState.quantity / 2) } this.accepts() @@ -474,7 +528,7 @@ class ObligationTests { transaction { input { inState } output { outState `issued by` MINI_CORP } - this `fails requirement` "at issuer MegaCorp the amounts balance" + this `fails requirement` "at obligor MegaCorp the amounts balance" } // Can't mix currencies. transaction { @@ -489,7 +543,7 @@ class ObligationTests { inState.copy( quantity = 15000, template = megaCorpPoundSettlement, - owner = DUMMY_PUBKEY_2 + beneficiary = DUMMY_PUBKEY_2 ) } output { outState.copy(quantity = 115000) } @@ -502,7 +556,7 @@ class ObligationTests { output { outState } arg(DUMMY_PUBKEY_1) {Obligation.Commands.Move(inState.issuanceDef) } arg(DUMMY_PUBKEY_1) {Obligation.Commands.Move((inState `issued by` MINI_CORP).issuanceDef) } - this `fails requirement` "at issuer MiniCorp the amounts balance" + this `fails requirement` "at obligor MiniCorp the amounts balance" } } @@ -514,13 +568,13 @@ class ObligationTests { output { outState.copy(quantity = inState.quantity - 200.DOLLARS.quantity) } tweak { - arg(MEGA_CORP_PUBKEY) { Obligation.Commands.Exit(inState.issuanceDef, 100.DOLLARS `issued by` defaultIssuer) } + arg(MEGA_CORP_PUBKEY) { Obligation.Commands.Exit(inState.issuanceDef, 100.DOLLARS) } arg(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } this `fails requirement` "the amounts balance" } tweak { - arg(MEGA_CORP_PUBKEY) { Obligation.Commands.Exit(inState.issuanceDef, 200.DOLLARS `issued by` defaultIssuer) } + arg(MEGA_CORP_PUBKEY) { Obligation.Commands.Exit(inState.issuanceDef, 200.DOLLARS) } this `fails requirement` "required com.r3corda.contracts.Obligation.Commands.Move command" tweak { @@ -539,15 +593,15 @@ class ObligationTests { arg(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } - this `fails requirement` "at issuer MegaCorp the amounts balance" + this `fails requirement` "at obligor MegaCorp the amounts balance" - arg(MEGA_CORP_PUBKEY) { Obligation.Commands.Exit(inState.issuanceDef, 200.DOLLARS `issued by` defaultIssuer) } + arg(MEGA_CORP_PUBKEY) { Obligation.Commands.Exit(inState.issuanceDef, 200.DOLLARS) } tweak { - arg(MINI_CORP_PUBKEY) { Obligation.Commands.Exit((inState `issued by` MINI_CORP).issuanceDef, 0.DOLLARS `issued by` defaultIssuer) } + arg(MINI_CORP_PUBKEY) { Obligation.Commands.Exit((inState `issued by` MINI_CORP).issuanceDef, 0.DOLLARS) } arg(DUMMY_PUBKEY_1) { Obligation.Commands.Move((inState `issued by` MINI_CORP).issuanceDef) } - this `fails requirement` "at issuer MiniCorp the amounts balance" + this `fails requirement` "at obligor MiniCorp the amounts balance" } - arg(MINI_CORP_PUBKEY) { Obligation.Commands.Exit((inState `issued by` MINI_CORP).issuanceDef, 200.DOLLARS `issued by` defaultIssuer) } + arg(MINI_CORP_PUBKEY) { Obligation.Commands.Exit((inState `issued by` MINI_CORP).issuanceDef, 200.DOLLARS) } arg(DUMMY_PUBKEY_1) { Obligation.Commands.Move((inState `issued by` MINI_CORP).issuanceDef) } this.accepts() } @@ -562,19 +616,19 @@ class ObligationTests { // Can't merge them together. tweak { - output { inState.copy(owner = DUMMY_PUBKEY_2, quantity = 200000L) } - this `fails requirement` "at issuer MegaCorp the amounts balance" + output { inState.copy(beneficiary = DUMMY_PUBKEY_2, quantity = 200000L) } + this `fails requirement` "at obligor MegaCorp the amounts balance" } // Missing MiniCorp deposit tweak { - output { inState.copy(owner = DUMMY_PUBKEY_2) } - output { inState.copy(owner = DUMMY_PUBKEY_2) } - this `fails requirement` "at issuer MegaCorp the amounts balance" + output { inState.copy(beneficiary = DUMMY_PUBKEY_2) } + output { inState.copy(beneficiary = DUMMY_PUBKEY_2) } + this `fails requirement` "at obligor MegaCorp the amounts balance" } // This works. - output { inState.copy(owner = DUMMY_PUBKEY_2) } - output { inState.copy(owner = DUMMY_PUBKEY_2) `issued by` MINI_CORP } + output { inState.copy(beneficiary = DUMMY_PUBKEY_2) } + output { inState.copy(beneficiary = DUMMY_PUBKEY_2) `issued by` MINI_CORP } arg(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } arg(DUMMY_PUBKEY_1) { Obligation.Commands.Move((inState `issued by` MINI_CORP).issuanceDef) } this.accepts() @@ -631,7 +685,7 @@ class ObligationTests { // States must not be nettable if the trusted issuers differ val miniCorpIssuer = nonEmptySetOf(Issued(MINI_CORP.ref(1), USD)) assertNotEquals(fiveKDollarsFromMegaToMega.bilateralNetState, - fiveKDollarsFromMegaToMega.copy(template = megaCorpDollarSettlement.copy(acceptableIssuanceDefinitions = miniCorpIssuer)).bilateralNetState) + fiveKDollarsFromMegaToMega.copy(template = megaCorpDollarSettlement.copy(acceptableIssuedProducts = miniCorpIssuer)).bilateralNetState) } @Test(expected = IllegalStateException::class) @@ -686,7 +740,7 @@ class ObligationTests { val fiveKDollarsFromMegaToMini = Obligation.State(Lifecycle.NORMAL, MEGA_CORP, megaCorpDollarSettlement, 5000.DOLLARS.quantity, MINI_CORP_PUBKEY) val expected = mapOf(Pair(Pair(MEGA_CORP_PUBKEY, MINI_CORP_PUBKEY), fiveKDollarsFromMegaToMini.amount)) - val actual = extractAmountsDue(defaultUsd, listOf(fiveKDollarsFromMegaToMini)) + val actual = extractAmountsDue(USD, listOf(fiveKDollarsFromMegaToMini)) assertEquals(expected, actual) } @@ -697,8 +751,8 @@ class ObligationTests { Pair(Pair(ALICE_PUBKEY, BOB_PUBKEY), Amount(100000000, GBP)), Pair(Pair(BOB_PUBKEY, ALICE_PUBKEY), Amount(100000000, GBP)) ) - val expected: Map = emptyMap() // Zero balances are stripped before returning - val actual = sumAmountsDue(balanced) + val expected: Map, Amount> = emptyMap() // Zero balances are stripped before returning + val actual = netAmountsDue(balanced) assertEquals(expected, actual) } @@ -706,11 +760,11 @@ class ObligationTests { fun `netting difference balances due between parties`() { // Now try it with two balances, which cancel each other out val balanced = mapOf( - Pair(Pair(ALICE_PUBKEY, BOB_PUBKEY), Amount(100000000, GBP) `issued by` defaultIssuer), - Pair(Pair(BOB_PUBKEY, ALICE_PUBKEY), Amount(200000000, GBP) `issued by` defaultIssuer) + Pair(Pair(ALICE_PUBKEY, BOB_PUBKEY), Amount(100000000, GBP)), + Pair(Pair(BOB_PUBKEY, ALICE_PUBKEY), Amount(200000000, GBP)) ) val expected = mapOf( - Pair(Pair(BOB_PUBKEY, ALICE_PUBKEY), Amount(100000000, GBP) `issued by` defaultIssuer) + Pair(Pair(BOB_PUBKEY, ALICE_PUBKEY), Amount(100000000, GBP)) ) var actual = netAmountsDue(balanced) assertEquals(expected, actual) From 228513671d1728938809f46a009ee145525148a8 Mon Sep 17 00:00:00 2001 From: Ross Nicoll Date: Thu, 23 Jun 2016 15:03:13 +0100 Subject: [PATCH 005/114] Move Obligation contract into contracts module --- .../com/r3corda/contracts/Obligation.kt | 0 .../r3corda/contracts/testing/TestUtils.kt | 25 +++++++++++++ .../com/r3corda/contracts/ObligationTests.kt | 0 .../testing/ExperimentalTestUtils.kt | 37 ------------------- 4 files changed, 25 insertions(+), 37 deletions(-) rename {experimental => contracts}/src/main/kotlin/com/r3corda/contracts/Obligation.kt (100%) rename {experimental => contracts}/src/test/kotlin/com/r3corda/contracts/ObligationTests.kt (100%) delete mode 100644 experimental/src/main/kotlin/com/r3corda/contracts/testing/ExperimentalTestUtils.kt diff --git a/experimental/src/main/kotlin/com/r3corda/contracts/Obligation.kt b/contracts/src/main/kotlin/com/r3corda/contracts/Obligation.kt similarity index 100% rename from experimental/src/main/kotlin/com/r3corda/contracts/Obligation.kt rename to contracts/src/main/kotlin/com/r3corda/contracts/Obligation.kt diff --git a/contracts/src/main/kotlin/com/r3corda/contracts/testing/TestUtils.kt b/contracts/src/main/kotlin/com/r3corda/contracts/testing/TestUtils.kt index d7f3dfc526..f0f0ef36f0 100644 --- a/contracts/src/main/kotlin/com/r3corda/contracts/testing/TestUtils.kt +++ b/contracts/src/main/kotlin/com/r3corda/contracts/testing/TestUtils.kt @@ -14,7 +14,11 @@ import com.r3corda.core.contracts.TransactionState import com.r3corda.core.crypto.NullPublicKey import com.r3corda.core.crypto.Party import com.r3corda.core.crypto.generateKeyPair +import com.r3corda.core.testing.MINI_CORP +import com.r3corda.core.testing.TEST_TX_TIME +import com.r3corda.core.utilities.nonEmptySetOf import java.security.PublicKey +import java.time.Instant import java.util.* // In a real system this would be a persistent map of hash to bytecode and we'd instantiate the object as needed inside @@ -56,6 +60,12 @@ object JavaTestHelpers { @JvmStatic fun withNotary(state: Cash.State, notary: Party) = TransactionState(state, notary) @JvmStatic fun withDeposit(state: Cash.State, deposit: PartyAndReference) = state.copy(amount = state.amount.copy(token = state.amount.token.copy(issuer = deposit))) + @JvmStatic fun at(state: Obligation.State, dueBefore: Instant) = state.copy(template = state.template.copy(dueBefore = dueBefore)) + @JvmStatic fun at(issuanceDef: Obligation.IssuanceDefinition, dueBefore: Instant) = issuanceDef.copy(template = issuanceDef.template.copy(dueBefore = dueBefore)) + @JvmStatic fun between(state: Obligation.State, parties: Pair) = state.copy(obligor = parties.first, beneficiary = parties.second) + @JvmStatic fun ownedBy(state: Obligation.State, owner: PublicKey) = state.copy(beneficiary = owner) + @JvmStatic fun issuedBy(state: Obligation.State, party: Party) = state.copy(obligor = party) + @JvmStatic fun ownedBy(state: CommercialPaper.State, owner: PublicKey) = state.copy(owner = owner) @JvmStatic fun withNotary(state: CommercialPaper.State, notary: Party) = TransactionState(state, notary) @JvmStatic fun ownedBy(state: ICommercialPaperState, new_owner: PublicKey) = state.withOwner(new_owner) @@ -66,6 +76,12 @@ object JavaTestHelpers { Amount>(amount.quantity, Issued(DUMMY_CASH_ISSUER, amount.token)), NullPublicKey) @JvmStatic fun STATE(amount: Amount>) = Cash.State(amount, NullPublicKey) + + // Allows you to write 100.DOLLARS.OBLIGATION + @JvmStatic fun OBLIGATION_DEF(issued: Issued) + = Obligation.StateTemplate(nonEmptySetOf(Cash().legalContractReference), nonEmptySetOf(issued), TEST_TX_TIME) + @JvmStatic fun OBLIGATION(amount: Amount>) = Obligation.State(Obligation.Lifecycle.NORMAL, MINI_CORP, + OBLIGATION_DEF(amount.token), amount.quantity, NullPublicKey) } @@ -75,6 +91,12 @@ infix fun Cash.State.`issued by`(deposit: PartyAndReference) = JavaTestHelpers.i infix fun Cash.State.`with notary`(notary: Party) = JavaTestHelpers.withNotary(this, notary) infix fun Cash.State.`with deposit`(deposit: PartyAndReference): Cash.State = JavaTestHelpers.withDeposit(this, deposit) +infix fun Obligation.State.`at`(dueBefore: Instant) = JavaTestHelpers.at(this, dueBefore) +infix fun Obligation.IssuanceDefinition.`at`(dueBefore: Instant) = JavaTestHelpers.at(this, dueBefore) +infix fun Obligation.State.`between`(parties: Pair) = JavaTestHelpers.between(this, parties) +infix fun Obligation.State.`owned by`(owner: PublicKey) = JavaTestHelpers.ownedBy(this, owner) +infix fun Obligation.State.`issued by`(party: Party) = JavaTestHelpers.issuedBy(this, party) + infix fun CommercialPaper.State.`owned by`(owner: PublicKey) = JavaTestHelpers.ownedBy(this, owner) infix fun CommercialPaper.State.`with notary`(notary: Party) = JavaTestHelpers.withNotary(this, notary) infix fun ICommercialPaperState.`owned by`(new_owner: PublicKey) = JavaTestHelpers.ownedBy(this, new_owner) @@ -87,3 +109,6 @@ val DUMMY_CASH_ISSUER = Party("Snake Oil Issuer", DUMMY_CASH_ISSUER_KEY.public). val Amount.CASH: Cash.State get() = JavaTestHelpers.CASH(this) val Amount>.STATE: Cash.State get() = JavaTestHelpers.STATE(this) +/** Allows you to write 100.DOLLARS.CASH */ +val Issued.OBLIGATION_DEF: Obligation.StateTemplate get() = JavaTestHelpers.OBLIGATION_DEF(this) +val Amount>.OBLIGATION: Obligation.State get() = JavaTestHelpers.OBLIGATION(this) diff --git a/experimental/src/test/kotlin/com/r3corda/contracts/ObligationTests.kt b/contracts/src/test/kotlin/com/r3corda/contracts/ObligationTests.kt similarity index 100% rename from experimental/src/test/kotlin/com/r3corda/contracts/ObligationTests.kt rename to contracts/src/test/kotlin/com/r3corda/contracts/ObligationTests.kt diff --git a/experimental/src/main/kotlin/com/r3corda/contracts/testing/ExperimentalTestUtils.kt b/experimental/src/main/kotlin/com/r3corda/contracts/testing/ExperimentalTestUtils.kt deleted file mode 100644 index 112e5f03d6..0000000000 --- a/experimental/src/main/kotlin/com/r3corda/contracts/testing/ExperimentalTestUtils.kt +++ /dev/null @@ -1,37 +0,0 @@ -package com.r3corda.contracts.testing - -import com.r3corda.contracts.Obligation -import com.r3corda.contracts.cash.Cash -import com.r3corda.core.contracts.Amount -import com.r3corda.core.contracts.Issued -import com.r3corda.core.crypto.NullPublicKey -import com.r3corda.core.crypto.Party -import com.r3corda.core.testing.MINI_CORP -import com.r3corda.core.testing.TEST_TX_TIME -import com.r3corda.core.utilities.nonEmptySetOf -import java.security.PublicKey -import java.time.Instant -import java.util.* - -object JavaExperimental { - @JvmStatic fun at(state: Obligation.State, dueBefore: Instant) = state.copy(template = state.template.copy(dueBefore = dueBefore)) - @JvmStatic fun at(issuanceDef: Obligation.IssuanceDefinition, dueBefore: Instant) = issuanceDef.copy(template = issuanceDef.template.copy(dueBefore = dueBefore)) - @JvmStatic fun between(state: Obligation.State, parties: Pair) = state.copy(obligor = parties.first, beneficiary = parties.second) - @JvmStatic fun ownedBy(state: Obligation.State, owner: PublicKey) = state.copy(beneficiary = owner) - @JvmStatic fun issuedBy(state: Obligation.State, party: Party) = state.copy(obligor = party) - - // Allows you to write 100.DOLLARS.OBLIGATION - @JvmStatic fun OBLIGATION_DEF(issued: Issued) - = Obligation.StateTemplate(nonEmptySetOf(Cash().legalContractReference), nonEmptySetOf(issued), TEST_TX_TIME) - @JvmStatic fun OBLIGATION(amount: Amount>) = Obligation.State(Obligation.Lifecycle.NORMAL, MINI_CORP, - OBLIGATION_DEF(amount.token), amount.quantity, NullPublicKey) -} -infix fun Obligation.State.`at`(dueBefore: Instant) = JavaExperimental.at(this, dueBefore) -infix fun Obligation.IssuanceDefinition.`at`(dueBefore: Instant) = JavaExperimental.at(this, dueBefore) -infix fun Obligation.State.`between`(parties: Pair) = JavaExperimental.between(this, parties) -infix fun Obligation.State.`owned by`(owner: PublicKey) = JavaExperimental.ownedBy(this, owner) -infix fun Obligation.State.`issued by`(party: Party) = JavaExperimental.issuedBy(this, party) - -/** Allows you to write 100.DOLLARS.CASH */ -val Issued.OBLIGATION_DEF: Obligation.StateTemplate get() = JavaExperimental.OBLIGATION_DEF(this) -val Amount>.OBLIGATION: Obligation.State get() = JavaExperimental.OBLIGATION(this) From 0788e8d64c6cbaed57d6b61e958c6d5099c38bf9 Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Wed, 1 Jun 2016 13:31:48 +0100 Subject: [PATCH 006/114] IRS demo to now has roles for NodeA/NodeB and most options are now~ optional. NodeA can be run without the shell script. --- src/main/kotlin/com/r3corda/demos/IRSDemo.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt index e1d270b6bb..7fef5004d5 100644 --- a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt @@ -249,6 +249,7 @@ private fun runNode(nodeParams : NodeParams) : Unit { } catch(e: InterruptedException) { node.stop() } + exitProcess(0) } private fun runUploadRates() { From 963976806946ac6c3e8b7f8d4cd6adcb1991581f Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Mon, 6 Jun 2016 10:21:27 +0100 Subject: [PATCH 007/114] Corrected the currency mismatch in the example trade. --- src/main/resources/com/r3corda/demos/example-irs-trade.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/com/r3corda/demos/example-irs-trade.json b/src/main/resources/com/r3corda/demos/example-irs-trade.json index 19cc8e8951..5c602e3bbd 100644 --- a/src/main/resources/com/r3corda/demos/example-irs-trade.json +++ b/src/main/resources/com/r3corda/demos/example-irs-trade.json @@ -96,7 +96,7 @@ "addressForTransfers": "", "exposure": {}, "localBusinessDay": [ "London" , "NewYork" ], - "dailyInterestAmount": "(CashAmount * InterestRate ) / (fixedLeg.notional.token.currencyCode.equals('GBP')) ? 365 : 360", + "dailyInterestAmount": "(CashAmount * InterestRate ) / (fixedLeg.notional.currency.currencyCode.equals('GBP')) ? 365 : 360", "tradeID": "tradeXXX", "hashLegalDocs": "put hash here" } From 507d9ea4ae4b224b946d7898a81a604ea3929ce1 Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Fri, 3 Jun 2016 16:36:39 +0100 Subject: [PATCH 008/114] Added new integration test for the IRSDemo and refactored the demo to run in integration tests. --- .../kotlin/com/r3corda/node/internal/Node.kt | 2 +- src/main/kotlin/com/r3corda/demos/IRSDemo.kt | 85 ++++++++++++++++--- .../com/r3corda/core/testing/IRSDemoTest.kt | 66 ++++++++++++++ 3 files changed, 138 insertions(+), 15 deletions(-) create mode 100644 src/test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt diff --git a/node/src/main/kotlin/com/r3corda/node/internal/Node.kt b/node/src/main/kotlin/com/r3corda/node/internal/Node.kt index 6c3ddbdda4..f78fa99c71 100644 --- a/node/src/main/kotlin/com/r3corda/node/internal/Node.kt +++ b/node/src/main/kotlin/com/r3corda/node/internal/Node.kt @@ -52,7 +52,7 @@ class ConfigurationException(message: String) : Exception(message) * Listed clientAPI classes are assumed to have to take a single APIServer constructor parameter * @param clock The clock used within the node and by all protocols etc */ -class Node(dir: Path, val p2pAddr: HostAndPort, configuration: NodeConfiguration, +open class Node(dir: Path, val p2pAddr: HostAndPort, configuration: NodeConfiguration, networkMapAddress: NodeInfo?, advertisedServices: Set, clock: Clock = NodeClock(), val clientAPIs: List> = listOf()) : AbstractNode(dir, configuration, networkMapAddress, advertisedServices, clock) { diff --git a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt index 7fef5004d5..49300dbb4a 100644 --- a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt @@ -4,6 +4,7 @@ import com.google.common.net.HostAndPort import com.typesafe.config.ConfigFactory import com.r3corda.core.crypto.Party import com.r3corda.core.logElapsedTime +import com.r3corda.core.messaging.MessagingService import com.r3corda.node.internal.Node import com.r3corda.node.services.config.NodeConfiguration import com.r3corda.node.services.config.NodeConfigurationFromConfig @@ -26,6 +27,7 @@ import com.r3corda.node.services.transactions.SimpleNotaryService import joptsimple.OptionParser import joptsimple.OptionSet import joptsimple.OptionSpec +import joptsimple.OptionSpecBuilder import java.io.DataOutputStream import java.io.File import java.net.HttpURLConnection @@ -33,6 +35,7 @@ import java.net.URL import java.nio.file.Files import java.nio.file.Path import java.nio.file.Paths +import java.time.Clock import java.util.* import kotlin.concurrent.fixedRateTimer import kotlin.system.exitProcess @@ -83,7 +86,28 @@ private class NotSetupException: Throwable { constructor(message: String): super(message) {} } +val messageNetwork = InMemoryMessagingNetwork() + +class DemoNode(messagingService: MessagingService, dir: Path, p2pAddr: HostAndPort, config: NodeConfiguration, + networkMapAddress: NodeInfo?, advertisedServices: Set, + clock: Clock, clientAPIs: List> = listOf()) + : Node(dir, p2pAddr, config, networkMapAddress, advertisedServices, clock, clientAPIs) { + + val messagingService = messagingService + override fun makeMessagingService(): MessagingService { + return messagingService + } + + override fun startMessagingService() { + + } +} + fun main(args: Array) { + exitProcess(runIRSDemo(args)) +} + +fun runIRSDemo(args: Array, useInMemoryMessaging: Boolean = false): Int { val parser = OptionParser() val demoArgs = setupArgs(parser) val options = try { @@ -91,7 +115,7 @@ fun main(args: Array) { } catch (e: Exception) { println(e.message) printHelp() - exitProcess(1) + return 1 } // Suppress the Artemis MQ noise, and activate the demo logging. @@ -114,14 +138,12 @@ fun main(args: Array) { "http://localhost:" + (Node.DEFAULT_PORT + 1) } - if (runTrade(tradeId, host)) { - exitProcess(0) - } else { - exitProcess(1) + if (!runTrade(tradeId, host)) { + return 1 } } else { println("Please provide a trade ID") - exitProcess(1) + return 1 } } else if(role == IRSDemoRole.Date) { val dateStrArgs = options.valuesOf(demoArgs.nonOptions) @@ -133,10 +155,12 @@ fun main(args: Array) { "http://localhost:" + (Node.DEFAULT_PORT + 1) } - runDateChange(dateStr, host) + if(!runDateChange(dateStr)) { + return 1 + } } else { println("Please provide a date") - exitProcess(1) + return 1 } } else { // If these directory and identity file arguments aren't specified then we can assume a default setup and @@ -147,14 +171,14 @@ fun main(args: Array) { } try { - runNode(configureNodeParams(role, demoArgs, options)) + runNode(configureNodeParams(role, demoArgs, options), useInMemoryMessaging) } catch (e: NotSetupException) { println(e.message) - exitProcess(1) + return 1 } - - exitProcess(0) } + + return 0 } private fun setupArgs(parser: OptionParser): DemoArgs { @@ -233,8 +257,11 @@ private fun configureNodeParams(role: IRSDemoRole, args: DemoArgs, options: Opti return nodeParams } -private fun runNode(nodeParams : NodeParams) : Unit { - val node = startNode(nodeParams) +private fun runNode(nodeParams : NodeParams, useInMemoryMessaging: Boolean) : Unit { + val node = when(useInMemoryMessaging) { + true -> startDemoNode(nodeParams) + false -> startNode(nodeParams) + } // Register handlers for the demo AutoOfferProtocol.Handler.register(node) UpdateBusinessDayProtocol.Handler.register(node) @@ -417,6 +444,36 @@ private fun startNode(params : NodeParams) : Node { return node } +private fun startDemoNode(params : NodeParams) : Node { + val config = createNodeConfig(params) + val advertisedServices: Set + val myNetAddr = HostAndPort.fromString(params.address).withDefaultPort(Node.DEFAULT_PORT) + val networkMapId = if (params.mapAddress.equals(params.address)) { + // This node provides network map and notary services + advertisedServices = setOf(NetworkMapService.Type, NotaryService.Type) + null + } else { + advertisedServices = setOf(NodeInterestRates.Type) + + val handle = InMemoryMessagingNetwork.Handle(createNodeAParams().id, params.defaultLegalName) + nodeInfo(handle, params.identityFile, setOf(NetworkMapService.Type, NotaryService.Type)) + } + + val messageService = messageNetwork.createNodeWithID(false, params.id).start().get() + val node = logElapsedTime("Node startup") { DemoNode(messageService, params.dir, myNetAddr, config, networkMapId, + advertisedServices, DemoClock(), + listOf(InterestRateSwapAPI::class.java)).setup().start() } + + // TODO: This should all be replaced by the identity service being updated + // as the network map changes. + val identityFile = params.tradeWithIdentities[0] + val handle = InMemoryMessagingNetwork.Handle(1 - params.id, "Other Node") + val peerId = nodeInfo(handle, identityFile) + node.services.identityService.registerIdentity(peerId.identity) + + return node +} + private fun getRoleDir(role: IRSDemoRole) : Path { when(role) { IRSDemoRole.NodeA -> return Paths.get("nodeA") diff --git a/src/test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt b/src/test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt new file mode 100644 index 0000000000..d922be68fe --- /dev/null +++ b/src/test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt @@ -0,0 +1,66 @@ +package com.r3corda.core.testing + +import com.r3corda.demos.runIRSDemo +import kotlin.concurrent.thread +import kotlin.test.assertEquals +import org.junit.Test +import java.nio.file.Path +import java.nio.file.Paths + +class IRSDemoTest { + @Test fun `runs IRS demo`() { + val dirA = Paths.get("./nodeA") + val dirB = Paths.get("./nodeB") + try { + setupNodeA(dirA) + setupNodeB(dirB) + startNodeA(dirA) + startNodeB(dirB) + runTrade() + runDateChange() + stopNodeA() + stopNodeB() + } finally { + cleanup(dirA) + cleanup(dirB) + } + } +} + +private fun setupNodeA(dir: Path) { + runIRSDemo(arrayOf("--role", "SetupNodeA", "--dir", dir.toString())) +} + +private fun setupNodeB(dir: Path) { + runIRSDemo(arrayOf("--role", "SetupNodeB", "--dir", dir.toString())) +} +private fun startNodeA(dir: Path) { + thread(true, false, null, "NodeA", -1, { runIRSDemo(arrayOf("--role", "NodeA", "--dir", dir.toString()), true) }) + Thread.sleep(15000) +} + +private fun startNodeB(dir: Path) { + thread(true, false, null, "NodeB", -1, { runIRSDemo(arrayOf("--role", "NodeB", "--dir", dir.toString()), true) }) + Thread.sleep(15000) +} + +private fun stopNodeA() { + +} + +private fun stopNodeB() { + +} + +private fun runTrade() { + assertEquals(runIRSDemo(arrayOf("--role", "Trade", "trade1")), 0) +} + +private fun runDateChange() { + assertEquals(runIRSDemo(arrayOf("--role", "Date", "2017-01-02")), 0) +} + +private fun cleanup(dir: Path) { + println("Erasing: " + dir.toString()) + dir.toFile().deleteRecursively() +} \ No newline at end of file From 90a24588bc6c236950e25c7adf5b597b8feccf87 Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Mon, 6 Jun 2016 09:20:04 +0100 Subject: [PATCH 009/114] Added TODOs and replaced default path with an exception. --- src/main/kotlin/com/r3corda/demos/IRSDemo.kt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt index 49300dbb4a..10df92ac2f 100644 --- a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt @@ -98,9 +98,7 @@ class DemoNode(messagingService: MessagingService, dir: Path, p2pAddr: HostAndPo return messagingService } - override fun startMessagingService() { - - } + override fun startMessagingService() = Unit } fun main(args: Array) { @@ -276,7 +274,6 @@ private fun runNode(nodeParams : NodeParams, useInMemoryMessaging: Boolean) : Un } catch(e: InterruptedException) { node.stop() } - exitProcess(0) } private fun runUploadRates() { @@ -467,6 +464,8 @@ private fun startDemoNode(params : NodeParams) : Node { // TODO: This should all be replaced by the identity service being updated // as the network map changes. val identityFile = params.tradeWithIdentities[0] + // Since in integration tests there are only two nodes with IDs 0 and 1, this hack will work + // TODO: Get Artemis working with two nodes in the same process or come up with a better solution val handle = InMemoryMessagingNetwork.Handle(1 - params.id, "Other Node") val peerId = nodeInfo(handle, identityFile) node.services.identityService.registerIdentity(peerId.identity) From 9fc89fc4a20850ebd013766343ec2a9667376acf Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Mon, 6 Jun 2016 10:10:25 +0100 Subject: [PATCH 010/114] Connections now timeout correctly if something goes wrong with the server. --- src/main/kotlin/com/r3corda/demos/IRSDemo.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt index 10df92ac2f..36180c2d90 100644 --- a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt @@ -200,6 +200,7 @@ private fun setup(params: NodeParams) { } private fun runDateChange(date: String, host: String) : Boolean { + println("Changing date to " + date) val url = URL(host + "/api/irs/demodate") if(putJson(url, "\"" + date + "\"")) { println("Date changed") From 5de855e045aed65484b049910f6aade556e6bc90 Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Mon, 6 Jun 2016 15:55:15 +0100 Subject: [PATCH 011/114] Fixed a merge error and parameterised host for upload rates. --- src/main/kotlin/com/r3corda/demos/IRSDemo.kt | 8 ++++---- src/test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt index 36180c2d90..430b4dc611 100644 --- a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt @@ -153,7 +153,7 @@ fun runIRSDemo(args: Array, useInMemoryMessaging: Boolean = false): Int "http://localhost:" + (Node.DEFAULT_PORT + 1) } - if(!runDateChange(dateStr)) { + if(!runDateChange(dateStr, host)) { return 1 } } else { @@ -267,7 +267,7 @@ private fun runNode(nodeParams : NodeParams, useInMemoryMessaging: Boolean) : Un ExitServerProtocol.Handler.register(node) if(nodeParams.uploadRates) { - runUploadRates() + runUploadRates("http://localhost:31341") } try { @@ -277,12 +277,12 @@ private fun runNode(nodeParams : NodeParams, useInMemoryMessaging: Boolean) : Un } } -private fun runUploadRates() { +private fun runUploadRates(host) { val fileContents = IOUtils.toString(NodeParams::class.java.getResource("example.rates.txt")) var timer : Timer? = null timer = fixedRateTimer("upload-rates", false, 0, 5000, { try { - val url = URL("http://localhost:31341/upload/interest-rates") + val url = URL(host + "/upload/interest-rates") if(uploadFile(url, fileContents)) { timer!!.cancel() println("Rates uploaded successfully") diff --git a/src/test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt b/src/test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt index d922be68fe..5534ad7bb0 100644 --- a/src/test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt +++ b/src/test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt @@ -34,6 +34,7 @@ private fun setupNodeA(dir: Path) { private fun setupNodeB(dir: Path) { runIRSDemo(arrayOf("--role", "SetupNodeB", "--dir", dir.toString())) } + private fun startNodeA(dir: Path) { thread(true, false, null, "NodeA", -1, { runIRSDemo(arrayOf("--role", "NodeA", "--dir", dir.toString()), true) }) Thread.sleep(15000) From b050411810bf008db6a3e6eb9493d3754535cd64 Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Mon, 6 Jun 2016 16:13:34 +0100 Subject: [PATCH 012/114] Fixed compile error in IRSDemo and updated demo data to match new format. --- src/main/kotlin/com/r3corda/demos/IRSDemo.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt index 430b4dc611..10dde98431 100644 --- a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt @@ -277,7 +277,7 @@ private fun runNode(nodeParams : NodeParams, useInMemoryMessaging: Boolean) : Un } } -private fun runUploadRates(host) { +private fun runUploadRates(host: String) { val fileContents = IOUtils.toString(NodeParams::class.java.getResource("example.rates.txt")) var timer : Timer? = null timer = fixedRateTimer("upload-rates", false, 0, 5000, { From f6069e1e1533d4e1b7585282e60268152486de00 Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Tue, 7 Jun 2016 10:26:51 +0100 Subject: [PATCH 013/114] Error now occurs on upload if no files are sent. Added apache httpcomponents as a dependency. --- node/build.gradle | 2 ++ .../kotlin/com/r3corda/node/servlets/DataUploadServlet.kt | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/node/build.gradle b/node/build.gradle index f9005d9349..9716079360 100644 --- a/node/build.gradle +++ b/node/build.gradle @@ -90,6 +90,8 @@ dependencies { // TypeSafe Config: for simple and human friendly config files. compile "com.typesafe:config:1.3.0" + compile "org.apache.httpcomponents:httpclient:4.5.2" + // Unit testing helpers. testCompile 'junit:junit:4.12' testCompile 'org.assertj:assertj-core:3.4.1' diff --git a/node/src/main/kotlin/com/r3corda/node/servlets/DataUploadServlet.kt b/node/src/main/kotlin/com/r3corda/node/servlets/DataUploadServlet.kt index e8551d2b98..6a0944dd16 100644 --- a/node/src/main/kotlin/com/r3corda/node/servlets/DataUploadServlet.kt +++ b/node/src/main/kotlin/com/r3corda/node/servlets/DataUploadServlet.kt @@ -35,6 +35,13 @@ class DataUploadServlet : HttpServlet() { val upload = ServletFileUpload() val iterator = upload.getItemIterator(req) val messages = ArrayList() + + if(!iterator.hasNext()) + { + resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Got an upload request with no files") + return + } + while (iterator.hasNext()) { val item = iterator.next() if (item.name != null && !acceptor.acceptableFileExtensions.any { item.name.endsWith(it) }) { From 60daf8059fa798b8ae38422c68cc1c4574b1c169 Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Tue, 7 Jun 2016 14:30:58 +0100 Subject: [PATCH 014/114] Removed dependency added in previous commit. Fixed upload code on IRS Demo --- node/build.gradle | 2 -- src/main/kotlin/com/r3corda/demos/IRSDemo.kt | 6 +++++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/node/build.gradle b/node/build.gradle index 9716079360..f9005d9349 100644 --- a/node/build.gradle +++ b/node/build.gradle @@ -90,8 +90,6 @@ dependencies { // TypeSafe Config: for simple and human friendly config files. compile "com.typesafe:config:1.3.0" - compile "org.apache.httpcomponents:httpclient:4.5.2" - // Unit testing helpers. testCompile 'junit:junit:4.12' testCompile 'org.assertj:assertj-core:3.4.1' diff --git a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt index 10dde98431..a8b9ec9417 100644 --- a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt @@ -40,7 +40,11 @@ import java.util.* import kotlin.concurrent.fixedRateTimer import kotlin.system.exitProcess import org.apache.commons.io.IOUtils +import org.glassfish.jersey.client.JerseyClientBuilder +import org.glassfish.jersey.client.JerseyWebTarget import java.io.FileNotFoundException +import javax.ws.rs.client.Entity +import javax.ws.rs.client.Invocation // IRS DEMO // @@ -311,7 +315,7 @@ private fun sendJson(url: URL, data: String, method: String) : Boolean { outStream.writeBytes(data) outStream.close() - return when(connection.responseCode) { + return when (connection.responseCode) { 200 -> true 201 -> true else -> { From de27b1e8dec7ecd9e48d98af322e10e394f3f5d2 Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Tue, 7 Jun 2016 17:17:19 +0100 Subject: [PATCH 015/114] Improved error handling in IRS demo --- src/main/kotlin/com/r3corda/demos/IRSDemo.kt | 32 +++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt index a8b9ec9417..d598c010a4 100644 --- a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt @@ -40,11 +40,7 @@ import java.util.* import kotlin.concurrent.fixedRateTimer import kotlin.system.exitProcess import org.apache.commons.io.IOUtils -import org.glassfish.jersey.client.JerseyClientBuilder -import org.glassfish.jersey.client.JerseyWebTarget -import java.io.FileNotFoundException -import javax.ws.rs.client.Entity -import javax.ws.rs.client.Invocation +import java.net.SocketTimeoutException // IRS DEMO // @@ -306,22 +302,28 @@ private fun sendJson(url: URL, data: String, method: String) : Boolean { connection.useCaches = false connection.requestMethod = method connection.connectTimeout = 5000 - connection.readTimeout = 5000 + connection.readTimeout = 10000 connection.setRequestProperty("Connection", "Keep-Alive") connection.setRequestProperty("Cache-Control", "no-cache") connection.setRequestProperty("Content-Type", "application/json") connection.setRequestProperty("Content-Length", data.length.toString()) - val outStream = DataOutputStream(connection.outputStream) - outStream.writeBytes(data) - outStream.close() - return when (connection.responseCode) { - 200 -> true - 201 -> true - else -> { - println("Failed to " + method + " data. Status Code: " + connection.responseCode + ". Mesage: " + connection.responseMessage) - false + try { + val outStream = DataOutputStream(connection.outputStream) + outStream.writeBytes(data) + outStream.close() + + return when (connection.responseCode) { + 200 -> true + 201 -> true + else -> { + println("Failed to " + method + " data. Status Code: " + connection.responseCode + ". Mesage: " + connection.responseMessage) + false + } } + } catch(e: SocketTimeoutException) { + println("Server took too long to respond") + return false } } From b61b36289125105ac6c606c0459c34c17dc113c3 Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Tue, 7 Jun 2016 18:25:11 +0100 Subject: [PATCH 016/114] Setup TraderDemo test. Moved DemoNode to a common file. Modified TraderDemo to be tested. --- src/main/kotlin/com/r3corda/demos/DemoNode.kt | 27 +++++++++++++ src/main/kotlin/com/r3corda/demos/IRSDemo.kt | 15 ------- .../kotlin/com/r3corda/demos/TraderDemo.kt | 39 ++++++++++++------- .../com/r3corda/core/testing/TradeDemoTest.kt | 34 ++++++++++++++++ 4 files changed, 87 insertions(+), 28 deletions(-) create mode 100644 src/main/kotlin/com/r3corda/demos/DemoNode.kt create mode 100644 src/test/kotlin/com/r3corda/core/testing/TradeDemoTest.kt diff --git a/src/main/kotlin/com/r3corda/demos/DemoNode.kt b/src/main/kotlin/com/r3corda/demos/DemoNode.kt new file mode 100644 index 0000000000..6f04fbabea --- /dev/null +++ b/src/main/kotlin/com/r3corda/demos/DemoNode.kt @@ -0,0 +1,27 @@ +package com.r3corda.demos + +import com.google.common.net.HostAndPort +import com.r3corda.core.messaging.MessagingService +import com.r3corda.core.node.NodeInfo +import com.r3corda.core.node.services.ServiceType +import com.r3corda.node.internal.Node +import com.r3corda.node.serialization.NodeClock +import com.r3corda.node.services.config.NodeConfiguration +import com.r3corda.node.services.network.InMemoryMessagingNetwork +import java.nio.file.Path +import java.time.Clock + +val messageNetwork = InMemoryMessagingNetwork() + +class DemoNode(messagingService: MessagingService, dir: Path, p2pAddr: HostAndPort, config: NodeConfiguration, + networkMapAddress: NodeInfo?, advertisedServices: Set, + clock: Clock = NodeClock(), clientAPIs: List> = listOf()) +: Node(dir, p2pAddr, config, networkMapAddress, advertisedServices, clock, clientAPIs) { + + val messagingService = messagingService + override fun makeMessagingService(): MessagingService { + return messagingService + } + + override fun startMessagingService() = Unit +} \ No newline at end of file diff --git a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt index d598c010a4..f06f54097d 100644 --- a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt @@ -86,21 +86,6 @@ private class NotSetupException: Throwable { constructor(message: String): super(message) {} } -val messageNetwork = InMemoryMessagingNetwork() - -class DemoNode(messagingService: MessagingService, dir: Path, p2pAddr: HostAndPort, config: NodeConfiguration, - networkMapAddress: NodeInfo?, advertisedServices: Set, - clock: Clock, clientAPIs: List> = listOf()) - : Node(dir, p2pAddr, config, networkMapAddress, advertisedServices, clock, clientAPIs) { - - val messagingService = messagingService - override fun makeMessagingService(): MessagingService { - return messagingService - } - - override fun startMessagingService() = Unit -} - fun main(args: Array) { exitProcess(runIRSDemo(args)) } diff --git a/src/main/kotlin/com/r3corda/demos/TraderDemo.kt b/src/main/kotlin/com/r3corda/demos/TraderDemo.kt index 90d7917d7d..e89ae844df 100644 --- a/src/main/kotlin/com/r3corda/demos/TraderDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/TraderDemo.kt @@ -68,13 +68,27 @@ enum class Role { val DIRNAME = "trader-demo" fun main(args: Array) { + exitProcess(runTraderDemo(args)) +} + +fun runTraderDemo(args: Array, useInMemoryMessaging: Boolean = false): Int { + val cashIssuerKey = generateKeyPair() + val cashIssuer = Party("Trusted cash issuer", cashIssuerKey.public) + val amount = 1000.DOLLARS `issued by` cashIssuer.ref(1) val parser = OptionParser() val roleArg = parser.accepts("role").withRequiredArg().ofType(Role::class.java).required() val myNetworkAddress = parser.accepts("network-address").withRequiredArg().defaultsTo("localhost") val theirNetworkAddress = parser.accepts("other-network-address").withRequiredArg().defaultsTo("localhost") - val options = parseOptions(args, parser) + val options = try { + parser.parse(*args) + } catch (e: Exception) { + println(e.message) + println("Please refer to the documentation in docs/build/index.html to learn how to run the demo.") + return 1 + } + val role = options.valueOf(roleArg)!! val myNetAddr = HostAndPort.fromString(options.valueOf(myNetworkAddress)).withDefaultPort( @@ -130,6 +144,11 @@ fun main(args: Array) { NodeInfo(ArtemisMessagingService.makeRecipient(theirNetAddr), party, setOf(NetworkMapService.Type)) } + val id = when(role) { + Role.BUYER -> 0 + Role.SELLER -> 1 + } + val messageService = messageNetwork.createNodeWithID(false, id).start().get() // And now construct then start the node object. It takes a little while. val node = logElapsedTime("Node startup") { Node(directory, myNetAddr, config, networkMapId, advertisedServices).setup().start() @@ -148,19 +167,13 @@ fun main(args: Array) { } else { runSeller(myNetAddr, node, theirNetAddr, amount) } + + return 0 } -fun parseOptions(args: Array, parser: OptionParser): OptionSet { - try { - return parser.parse(*args) - } catch (e: Exception) { - println(e.message) - println("Please refer to the documentation in docs/build/index.html to learn how to run the demo.") - exitProcess(1) - } } -fun runSeller(myNetAddr: HostAndPort, node: Node, theirNetAddr: HostAndPort, amount: Amount>) { +private fun runSeller(myNetAddr: HostAndPort, node: Node, theirNetAddr: HostAndPort) { // The seller will sell some commercial paper to the buyer, who will pay with (self issued) cash. // // The CP sale transaction comes with a prospectus PDF, which will tag along for the ride in an @@ -187,7 +200,7 @@ fun runSeller(myNetAddr: HostAndPort, node: Node, theirNetAddr: HostAndPort, amo node.stop() } -fun runBuyer(node: Node, amount: Amount>) { +private fun runBuyer(node: Node, amount: Amount>) { // Buyer will fetch the attachment from the seller automatically when it resolves the transaction. // For demo purposes just extract attachment jars when saved to disk, so the user can explore them. val attachmentsPath = (node.storage.attachments as NodeAttachmentService).let { @@ -211,7 +224,7 @@ fun runBuyer(node: Node, amount: Amount>) { val DEMO_TOPIC = "initiate.demo.trade" -class TraderDemoProtocolBuyer(private val attachmentsPath: Path, +private class TraderDemoProtocolBuyer(private val attachmentsPath: Path, val notary: Party, val amount: Amount>) : ProtocolLogic() { companion object { @@ -289,7 +302,7 @@ ${Emoji.renderIfSupported(cpIssuance)}""") } } -class TraderDemoProtocolSeller(val myAddress: HostAndPort, +private class TraderDemoProtocolSeller(val myAddress: HostAndPort, val otherSide: SingleMessageRecipient, val amount: Amount>, override val progressTracker: ProgressTracker = TraderDemoProtocolSeller.tracker()) : ProtocolLogic() { diff --git a/src/test/kotlin/com/r3corda/core/testing/TradeDemoTest.kt b/src/test/kotlin/com/r3corda/core/testing/TradeDemoTest.kt new file mode 100644 index 0000000000..489cf5b74a --- /dev/null +++ b/src/test/kotlin/com/r3corda/core/testing/TradeDemoTest.kt @@ -0,0 +1,34 @@ +package com.r3corda.core.testing + +import com.r3corda.demos.runTraderDemo +import org.junit.Test +import java.nio.file.Path +import java.nio.file.Paths +import kotlin.concurrent.thread +import kotlin.test.assertEquals + +class TraderDemoTest { + @Test fun `runs trader demo`() { + try { + runBuyer() + runSeller() + } finally { + cleanup() + } + } +} + +private fun runBuyer() { + thread(true, false, null, "Buyer", -1, { runTraderDemo(arrayOf("--role", "BUYER"), true) }) + Thread.sleep(5000) +} + +private fun runSeller() { + assertEquals(runTraderDemo(arrayOf("--role", "SELLER"), true), 0) +} + +private fun cleanup() { + val dir = Paths.get("trader-demo") + println("Erasing " + dir) + dir.toFile().deleteRecursively() +} \ No newline at end of file From 89b8b164f7df42356f933d0dcb6723aecc099cef Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Tue, 7 Jun 2016 18:57:48 +0100 Subject: [PATCH 017/114] Trader Demo now has in memory nodes working. --- .../kotlin/com/r3corda/demos/TraderDemo.kt | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/com/r3corda/demos/TraderDemo.kt b/src/main/kotlin/com/r3corda/demos/TraderDemo.kt index e89ae844df..9a53abbaba 100644 --- a/src/main/kotlin/com/r3corda/demos/TraderDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/TraderDemo.kt @@ -24,6 +24,7 @@ import com.r3corda.core.utilities.ProgressTracker import com.r3corda.node.internal.Node import com.r3corda.node.services.config.NodeConfigurationFromConfig import com.r3corda.node.services.messaging.ArtemisMessagingService +import com.r3corda.node.services.network.InMemoryMessagingNetwork import com.r3corda.node.services.network.NetworkMapService import com.r3corda.node.services.persistence.NodeAttachmentService import com.r3corda.node.services.transactions.SimpleNotaryService @@ -122,6 +123,19 @@ fun runTraderDemo(args: Array, useInMemoryMessaging: Boolean = false): I NodeConfigurationFromConfig(override.withFallback(ConfigFactory.load())) } + val peerId: Int; + val id: Int + when (role) { + Role.BUYER -> { + peerId = 1 + id = 0 + } + Role.SELLER -> { + peerId = 0 + id = 1 + } + } + // Which services will this instance of the node provide to the network? val advertisedServices: Set @@ -142,11 +156,13 @@ fun runTraderDemo(args: Array, useInMemoryMessaging: Boolean = false): I advertisedServices = emptySet() cashIssuer = party NodeInfo(ArtemisMessagingService.makeRecipient(theirNetAddr), party, setOf(NetworkMapService.Type)) - } - val id = when(role) { - Role.BUYER -> 0 - Role.SELLER -> 1 + if(useInMemoryMessaging) { + val handle = InMemoryMessagingNetwork.Handle(peerId, "Other Node") + NodeInfo(handle, party, setOf(NetworkMapService.Type)) + } else { + NodeInfo(ArtemisMessagingService.makeRecipient(theirNetAddr), party, setOf(NetworkMapService.Type)) + } } val messageService = messageNetwork.createNodeWithID(false, id).start().get() // And now construct then start the node object. It takes a little while. @@ -171,8 +187,6 @@ fun runTraderDemo(args: Array, useInMemoryMessaging: Boolean = false): I return 0 } -} - private fun runSeller(myNetAddr: HostAndPort, node: Node, theirNetAddr: HostAndPort) { // The seller will sell some commercial paper to the buyer, who will pay with (self issued) cash. // From 929b752b428f48bc49e6149897cc1aa874510b09 Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Wed, 8 Jun 2016 11:58:46 +0100 Subject: [PATCH 018/114] Trader demo now works as a test using in memory messaging. --- .../kotlin/com/r3corda/demos/TraderDemo.kt | 66 ++++++++++++------- .../com/r3corda/core/testing/TradeDemoTest.kt | 3 +- 2 files changed, 45 insertions(+), 24 deletions(-) diff --git a/src/main/kotlin/com/r3corda/demos/TraderDemo.kt b/src/main/kotlin/com/r3corda/demos/TraderDemo.kt index 9a53abbaba..918b49a72b 100644 --- a/src/main/kotlin/com/r3corda/demos/TraderDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/TraderDemo.kt @@ -33,6 +33,7 @@ import com.r3corda.protocols.TwoPartyTradeProtocol import com.typesafe.config.ConfigFactory import joptsimple.OptionParser import joptsimple.OptionSet +import java.io.Serializable import java.nio.file.Files import java.nio.file.Path import java.nio.file.Paths @@ -64,6 +65,11 @@ enum class Role { SELLER } +private class Destination constructor(addr: Any, inMemory: Boolean): Serializable { + val inMemory = inMemory + val addr = addr +} + // And this is the directory under the current working directory where each node will create its own server directory, // which holds things like checkpoints, keys, databases, message logs etc. val DIRNAME = "trader-demo" @@ -105,6 +111,19 @@ fun runTraderDemo(args: Array, useInMemoryMessaging: Boolean = false): I } ) + val peerId: Int; + val id: Int + when (role) { + Role.BUYER -> { + peerId = 1 + id = 0 + } + Role.SELLER -> { + peerId = 0 + id = 1 + } + } + // Suppress the Artemis MQ noise, and activate the demo logging. // // The first two strings correspond to the first argument to StateMachineManager.add() but the way we handle logging @@ -123,19 +142,6 @@ fun runTraderDemo(args: Array, useInMemoryMessaging: Boolean = false): I NodeConfigurationFromConfig(override.withFallback(ConfigFactory.load())) } - val peerId: Int; - val id: Int - when (role) { - Role.BUYER -> { - peerId = 1 - id = 0 - } - Role.SELLER -> { - peerId = 0 - id = 1 - } - } - // Which services will this instance of the node provide to the network? val advertisedServices: Set @@ -181,13 +187,24 @@ fun runTraderDemo(args: Array, useInMemoryMessaging: Boolean = false): I if (role == Role.BUYER) { runBuyer(node, amount) } else { - runSeller(myNetAddr, node, theirNetAddr, amount) + val dest: Destination + val recipient: SingleMessageRecipient + + if(useInMemoryMessaging) { + recipient = InMemoryMessagingNetwork.Handle(peerId, "Other Node") + dest = Destination(InMemoryMessagingNetwork.Handle(id, role.toString()), true) + } else { + recipient = ArtemisMessagingService.makeRecipient(theirNetAddr) + dest = Destination(myNetAddr, false) + } + + runSeller(dest, node, recipient, amount)) } return 0 } -private fun runSeller(myNetAddr: HostAndPort, node: Node, theirNetAddr: HostAndPort) { +private fun runSeller(myAddr: Destination, node: Node, recipient: SingleMessageRecipient) { // The seller will sell some commercial paper to the buyer, who will pay with (self issued) cash. // // The CP sale transaction comes with a prospectus PDF, which will tag along for the ride in an @@ -206,8 +223,7 @@ private fun runSeller(myNetAddr: HostAndPort, node: Node, theirNetAddr: HostAndP it.second.get() } } else { - val otherSide = ArtemisMessagingService.makeRecipient(theirNetAddr) - val seller = TraderDemoProtocolSeller(myNetAddr, otherSide, amount) + val seller = TraderDemoProtocolSeller(myAddr, recipient, amount) node.smm.add("demo.seller", seller).get() } @@ -264,16 +280,20 @@ private class TraderDemoProtocolBuyer(private val attachmentsPath: Path, // As the seller initiates the two-party trade protocol, here, we will be the buyer. try { progressTracker.currentStep = WAITING_FOR_SELLER_TO_CONNECT - val hostname = receive(DEMO_TOPIC, 0).validate { it.withDefaultPort(Node.DEFAULT_PORT) } - val newPartnerAddr = ArtemisMessagingService.makeRecipient(hostname) + val origin: Destination = receive(DEMO_TOPIC, 0).validate { it } + val recipient: SingleMessageRecipient = if(origin.inMemory) { + origin.addr as InMemoryMessagingNetwork.Handle + } else { + ArtemisMessagingService.makeRecipient(origin.addr as HostAndPort) + } // The session ID disambiguates the test trade. val sessionID = random63BitValue() progressTracker.currentStep = STARTING_BUY - send(DEMO_TOPIC, newPartnerAddr, 0, sessionID) + send(DEMO_TOPIC, recipient, 0, sessionID) val notary = serviceHub.networkMapCache.notaryNodes[0] - val buyer = TwoPartyTradeProtocol.Buyer(newPartnerAddr, notary.identity, amount, + val buyer = TwoPartyTradeProtocol.Buyer(recipient, notary.identity, amount, CommercialPaper.State::class.java, sessionID) // This invokes the trading protocol and out pops our finished transaction. @@ -316,7 +336,7 @@ ${Emoji.renderIfSupported(cpIssuance)}""") } } -private class TraderDemoProtocolSeller(val myAddress: HostAndPort, +private class TraderDemoProtocolSeller(val myAddr: Destination, val otherSide: SingleMessageRecipient, val amount: Amount>, override val progressTracker: ProgressTracker = TraderDemoProtocolSeller.tracker()) : ProtocolLogic() { @@ -392,7 +412,7 @@ private class TraderDemoProtocolSeller(val myAddress: HostAndPort, // Now make a dummy transaction that moves it to a new key, just to show that resolving dependencies works. val move: SignedTransaction = run { - val builder = TransactionType.General.Builder() + val builder = TransactionBuilder() CommercialPaper().generateMove(builder, issuance.tx.outRef(0), ownedBy) builder.signWith(keyPair) val notarySignature = subProtocol(NotaryProtocol.Client(builder.toSignedTransaction(false))) diff --git a/src/test/kotlin/com/r3corda/core/testing/TradeDemoTest.kt b/src/test/kotlin/com/r3corda/core/testing/TradeDemoTest.kt index 489cf5b74a..4575cfc909 100644 --- a/src/test/kotlin/com/r3corda/core/testing/TradeDemoTest.kt +++ b/src/test/kotlin/com/r3corda/core/testing/TradeDemoTest.kt @@ -20,10 +20,11 @@ class TraderDemoTest { private fun runBuyer() { thread(true, false, null, "Buyer", -1, { runTraderDemo(arrayOf("--role", "BUYER"), true) }) - Thread.sleep(5000) + Thread.sleep(15000) } private fun runSeller() { + println("Running Seller") assertEquals(runTraderDemo(arrayOf("--role", "SELLER"), true), 0) } From a7ac54f28058b277dc6f8be18bd38e90511ba86f Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Wed, 8 Jun 2016 15:55:25 +0100 Subject: [PATCH 019/114] Removed thread waits from tests instead relying on a lock passed to the demo environment. --- src/main/kotlin/com/r3corda/demos/DemoNode.kt | 6 +++ src/main/kotlin/com/r3corda/demos/IRSDemo.kt | 11 ++--- .../kotlin/com/r3corda/demos/TraderDemo.kt | 13 ++++-- .../com/r3corda/core/testing/IRSDemoTest.kt | 46 ++++++++----------- .../com/r3corda/core/testing/TradeDemoTest.kt | 12 ++--- 5 files changed, 43 insertions(+), 45 deletions(-) diff --git a/src/main/kotlin/com/r3corda/demos/DemoNode.kt b/src/main/kotlin/com/r3corda/demos/DemoNode.kt index 6f04fbabea..508b2feb03 100644 --- a/src/main/kotlin/com/r3corda/demos/DemoNode.kt +++ b/src/main/kotlin/com/r3corda/demos/DemoNode.kt @@ -10,6 +10,7 @@ import com.r3corda.node.services.config.NodeConfiguration import com.r3corda.node.services.network.InMemoryMessagingNetwork import java.nio.file.Path import java.time.Clock +import java.util.concurrent.CountDownLatch val messageNetwork = InMemoryMessagingNetwork() @@ -24,4 +25,9 @@ class DemoNode(messagingService: MessagingService, dir: Path, p2pAddr: HostAndPo } override fun startMessagingService() = Unit +} + +class DemoConfig(useInMemoryMessaging: Boolean = false) { + val inMemory = useInMemoryMessaging + val nodeReady = CountDownLatch(1) } \ No newline at end of file diff --git a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt index f06f54097d..0dacb98323 100644 --- a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt @@ -4,7 +4,6 @@ import com.google.common.net.HostAndPort import com.typesafe.config.ConfigFactory import com.r3corda.core.crypto.Party import com.r3corda.core.logElapsedTime -import com.r3corda.core.messaging.MessagingService import com.r3corda.node.internal.Node import com.r3corda.node.services.config.NodeConfiguration import com.r3corda.node.services.config.NodeConfigurationFromConfig @@ -35,7 +34,6 @@ import java.net.URL import java.nio.file.Files import java.nio.file.Path import java.nio.file.Paths -import java.time.Clock import java.util.* import kotlin.concurrent.fixedRateTimer import kotlin.system.exitProcess @@ -90,7 +88,7 @@ fun main(args: Array) { exitProcess(runIRSDemo(args)) } -fun runIRSDemo(args: Array, useInMemoryMessaging: Boolean = false): Int { +fun runIRSDemo(args: Array, demoNodeConfig: DemoConfig = DemoConfig()): Int { val parser = OptionParser() val demoArgs = setupArgs(parser) val options = try { @@ -154,7 +152,7 @@ fun runIRSDemo(args: Array, useInMemoryMessaging: Boolean = false): Int } try { - runNode(configureNodeParams(role, demoArgs, options), useInMemoryMessaging) + runNode(configureNodeParams(role, demoArgs, options), demoNodeConfig) } catch (e: NotSetupException) { println(e.message) return 1 @@ -241,8 +239,8 @@ private fun configureNodeParams(role: IRSDemoRole, args: DemoArgs, options: Opti return nodeParams } -private fun runNode(nodeParams : NodeParams, useInMemoryMessaging: Boolean) : Unit { - val node = when(useInMemoryMessaging) { +private fun runNode(nodeParams : NodeParams, demoNodeConfig: DemoConfig) : Unit { + val node = when(demoNodeConfig.inMemory) { true -> startDemoNode(nodeParams) false -> startNode(nodeParams) } @@ -255,6 +253,7 @@ private fun runNode(nodeParams : NodeParams, useInMemoryMessaging: Boolean) : Un runUploadRates("http://localhost:31341") } + demoNodeConfig.nodeReady.countDown() try { while (true) Thread.sleep(Long.MAX_VALUE) } catch(e: InterruptedException) { diff --git a/src/main/kotlin/com/r3corda/demos/TraderDemo.kt b/src/main/kotlin/com/r3corda/demos/TraderDemo.kt index 918b49a72b..a3effd7b68 100644 --- a/src/main/kotlin/com/r3corda/demos/TraderDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/TraderDemo.kt @@ -32,7 +32,6 @@ import com.r3corda.protocols.NotaryProtocol import com.r3corda.protocols.TwoPartyTradeProtocol import com.typesafe.config.ConfigFactory import joptsimple.OptionParser -import joptsimple.OptionSet import java.io.Serializable import java.nio.file.Files import java.nio.file.Path @@ -78,7 +77,7 @@ fun main(args: Array) { exitProcess(runTraderDemo(args)) } -fun runTraderDemo(args: Array, useInMemoryMessaging: Boolean = false): Int { +fun runTraderDemo(args: Array, demoNodeConfig: DemoConfig = DemoConfig()): Int { val cashIssuerKey = generateKeyPair() val cashIssuer = Party("Trusted cash issuer", cashIssuerKey.public) val amount = 1000.DOLLARS `issued by` cashIssuer.ref(1) @@ -163,7 +162,7 @@ fun runTraderDemo(args: Array, useInMemoryMessaging: Boolean = false): I cashIssuer = party NodeInfo(ArtemisMessagingService.makeRecipient(theirNetAddr), party, setOf(NetworkMapService.Type)) - if(useInMemoryMessaging) { + if(demoNodeConfig.inMemory) { val handle = InMemoryMessagingNetwork.Handle(peerId, "Other Node") NodeInfo(handle, party, setOf(NetworkMapService.Type)) } else { @@ -173,7 +172,11 @@ fun runTraderDemo(args: Array, useInMemoryMessaging: Boolean = false): I val messageService = messageNetwork.createNodeWithID(false, id).start().get() // And now construct then start the node object. It takes a little while. val node = logElapsedTime("Node startup") { - Node(directory, myNetAddr, config, networkMapId, advertisedServices).setup().start() + if(demoNodeConfig.inMemory) { + DemoNode(messageService, directory, myNetAddr, config, networkMapId, advertisedServices).setup().start() + } else { + Node(directory, myNetAddr, config, networkMapId, advertisedServices).setup().start() + } } // TODO: Replace with a separate trusted cash issuer @@ -190,7 +193,7 @@ fun runTraderDemo(args: Array, useInMemoryMessaging: Boolean = false): I val dest: Destination val recipient: SingleMessageRecipient - if(useInMemoryMessaging) { + if(demoNodeConfig.inMemory) { recipient = InMemoryMessagingNetwork.Handle(peerId, "Other Node") dest = Destination(InMemoryMessagingNetwork.Handle(id, role.toString()), true) } else { diff --git a/src/test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt b/src/test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt index 5534ad7bb0..33a0a389f4 100644 --- a/src/test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt +++ b/src/test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt @@ -1,5 +1,6 @@ package com.r3corda.core.testing +import com.r3corda.demos.DemoConfig import com.r3corda.demos.runIRSDemo import kotlin.concurrent.thread import kotlin.test.assertEquals @@ -12,14 +13,12 @@ class IRSDemoTest { val dirA = Paths.get("./nodeA") val dirB = Paths.get("./nodeB") try { - setupNodeA(dirA) - setupNodeB(dirB) - startNodeA(dirA) - startNodeB(dirB) + setupNode(dirA, "NodeA") + setupNode(dirB, "NodeB") + startNode(dirA, "NodeA") + startNode(dirB, "NodeB") runTrade() runDateChange() - stopNodeA() - stopNodeB() } finally { cleanup(dirA) cleanup(dirB) @@ -27,30 +26,21 @@ class IRSDemoTest { } } -private fun setupNodeA(dir: Path) { - runIRSDemo(arrayOf("--role", "SetupNodeA", "--dir", dir.toString())) +private fun setupNode(dir: Path, nodeType: String) { + runIRSDemo(arrayOf("--role", "Setup" + nodeType, "--dir", dir.toString())) } -private fun setupNodeB(dir: Path) { - runIRSDemo(arrayOf("--role", "SetupNodeB", "--dir", dir.toString())) -} - -private fun startNodeA(dir: Path) { - thread(true, false, null, "NodeA", -1, { runIRSDemo(arrayOf("--role", "NodeA", "--dir", dir.toString()), true) }) - Thread.sleep(15000) -} - -private fun startNodeB(dir: Path) { - thread(true, false, null, "NodeB", -1, { runIRSDemo(arrayOf("--role", "NodeB", "--dir", dir.toString()), true) }) - Thread.sleep(15000) -} - -private fun stopNodeA() { - -} - -private fun stopNodeB() { - +private fun startNode(dir: Path, nodeType: String) { + val config = DemoConfig(true) + thread(true, false, null, nodeType, -1, { + try { + runIRSDemo(arrayOf("--role", nodeType, "--dir", dir.toString()), config) + } finally { + // Will only reach here during error or after node is stopped, so ensure lock is unlocked. + config.nodeReady.countDown() + } + }) + config.nodeReady.await() } private fun runTrade() { diff --git a/src/test/kotlin/com/r3corda/core/testing/TradeDemoTest.kt b/src/test/kotlin/com/r3corda/core/testing/TradeDemoTest.kt index 4575cfc909..ae75523736 100644 --- a/src/test/kotlin/com/r3corda/core/testing/TradeDemoTest.kt +++ b/src/test/kotlin/com/r3corda/core/testing/TradeDemoTest.kt @@ -1,10 +1,9 @@ package com.r3corda.core.testing +import com.r3corda.demos.DemoConfig import com.r3corda.demos.runTraderDemo import org.junit.Test -import java.nio.file.Path import java.nio.file.Paths -import kotlin.concurrent.thread import kotlin.test.assertEquals class TraderDemoTest { @@ -19,13 +18,14 @@ class TraderDemoTest { } private fun runBuyer() { - thread(true, false, null, "Buyer", -1, { runTraderDemo(arrayOf("--role", "BUYER"), true) }) - Thread.sleep(15000) + val config = DemoConfig(true) + runTraderDemo(arrayOf("--role", "BUYER"), config) + config.nodeReady.await() } private fun runSeller() { - println("Running Seller") - assertEquals(runTraderDemo(arrayOf("--role", "SELLER"), true), 0) + val config = DemoConfig(true) + assertEquals(runTraderDemo(arrayOf("--role", "SELLER"), config), 0) } private fun cleanup() { From 10fa86002d447a1469991bcca54fc5ee30124691 Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Thu, 9 Jun 2016 10:21:27 +0100 Subject: [PATCH 020/114] Fixed merge error causing IRSDemo to fail. --- src/main/kotlin/com/r3corda/demos/IRSDemo.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt index 0dacb98323..ba7f1884c3 100644 --- a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt @@ -286,7 +286,7 @@ private fun sendJson(url: URL, data: String, method: String) : Boolean { connection.useCaches = false connection.requestMethod = method connection.connectTimeout = 5000 - connection.readTimeout = 10000 + connection.readTimeout = 15000 connection.setRequestProperty("Connection", "Keep-Alive") connection.setRequestProperty("Cache-Control", "no-cache") connection.setRequestProperty("Content-Type", "application/json") @@ -438,13 +438,13 @@ private fun startDemoNode(params : NodeParams) : Node { val myNetAddr = HostAndPort.fromString(params.address).withDefaultPort(Node.DEFAULT_PORT) val networkMapId = if (params.mapAddress.equals(params.address)) { // This node provides network map and notary services - advertisedServices = setOf(NetworkMapService.Type, NotaryService.Type) + advertisedServices = setOf(NetworkMapService.Type, SimpleNotaryService.Type) null } else { advertisedServices = setOf(NodeInterestRates.Type) val handle = InMemoryMessagingNetwork.Handle(createNodeAParams().id, params.defaultLegalName) - nodeInfo(handle, params.identityFile, setOf(NetworkMapService.Type, NotaryService.Type)) + nodeInfo(handle, params.identityFile, setOf(NetworkMapService.Type, SimpleNotaryService.Type)) } val messageService = messageNetwork.createNodeWithID(false, params.id).start().get() From 560989a914f348897b8987623f15cc31e086396b Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Thu, 9 Jun 2016 10:31:42 +0100 Subject: [PATCH 021/114] Trader Demo test now works again. --- .../kotlin/com/r3corda/core/testing/TradeDemoTest.kt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/test/kotlin/com/r3corda/core/testing/TradeDemoTest.kt b/src/test/kotlin/com/r3corda/core/testing/TradeDemoTest.kt index ae75523736..bc29139cb4 100644 --- a/src/test/kotlin/com/r3corda/core/testing/TradeDemoTest.kt +++ b/src/test/kotlin/com/r3corda/core/testing/TradeDemoTest.kt @@ -4,6 +4,7 @@ import com.r3corda.demos.DemoConfig import com.r3corda.demos.runTraderDemo import org.junit.Test import java.nio.file.Paths +import kotlin.concurrent.thread import kotlin.test.assertEquals class TraderDemoTest { @@ -19,7 +20,14 @@ class TraderDemoTest { private fun runBuyer() { val config = DemoConfig(true) - runTraderDemo(arrayOf("--role", "BUYER"), config) + thread(true, false, null, "Buyer", -1, { + try { + runTraderDemo(arrayOf("--role", "BUYER"), config) + } finally { + // Will only reach here during error or after node is stopped, so ensure lock is unlocked. + config.nodeReady.countDown() + } + }) config.nodeReady.await() } From 5986e785cf6df9e160a045d90ac0606c6f13a76d Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Thu, 9 Jun 2016 11:00:13 +0100 Subject: [PATCH 022/114] Broke up the runIRSDemo function into smaller functions for readability. --- src/main/kotlin/com/r3corda/demos/IRSDemo.kt | 104 +++++++++++-------- 1 file changed, 58 insertions(+), 46 deletions(-) diff --git a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt index ba7f1884c3..aa534fc3cd 100644 --- a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt @@ -103,60 +103,71 @@ fun runIRSDemo(args: Array, demoNodeConfig: DemoConfig = DemoConfig()): BriefLogFormatter.initVerbose("+demo.irsdemo", "+api-call", "+platform.deal", "-org.apache.activemq") val role = options.valueOf(demoArgs.roleArg)!! - if(role == IRSDemoRole.SetupNodeA) { - val nodeParams = configureNodeParams(IRSDemoRole.NodeA, demoArgs, options) - setup(nodeParams) - } else if(role == IRSDemoRole.SetupNodeB) { - val nodeParams = configureNodeParams(IRSDemoRole.NodeB, demoArgs, options) - setup(nodeParams) - } else if(role == IRSDemoRole.Trade) { - val tradeIdArgs = options.valuesOf(demoArgs.nonOptions) - if (tradeIdArgs.size > 0) { - val tradeId = tradeIdArgs[0] - val host = if (options.has(demoArgs.networkAddressArg)) { - options.valueOf(demoArgs.networkAddressArg) - } else { - "http://localhost:" + (Node.DEFAULT_PORT + 1) - } + return when (role) { + IRSDemoRole.SetupNodeA -> setup(configureNodeParams(IRSDemoRole.NodeA, demoArgs, options)) + IRSDemoRole.SetupNodeB -> setup(configureNodeParams(IRSDemoRole.NodeB, demoArgs, options)) + IRSDemoRole.NodeA -> runNode(role, demoArgs, options, demoNodeConfig) + IRSDemoRole.NodeB -> runNode(role, demoArgs, options, demoNodeConfig) + IRSDemoRole.Trade -> runTrade(demoArgs, options) + IRSDemoRole.Date -> runDateChange(demoArgs, options) + } +} - if (!runTrade(tradeId, host)) { - return 1 - } +private fun runTrade(demoArgs: DemoArgs, options: OptionSet): Int { + val tradeIdArgs = options.valuesOf(demoArgs.nonOptions) + if (tradeIdArgs.size > 0) { + val tradeId = tradeIdArgs[0] + val host = if (options.has(demoArgs.networkAddressArg)) { + options.valueOf(demoArgs.networkAddressArg) } else { - println("Please provide a trade ID") - return 1 + "http://localhost:" + (Node.DEFAULT_PORT + 1) } - } else if(role == IRSDemoRole.Date) { - val dateStrArgs = options.valuesOf(demoArgs.nonOptions) - if (dateStrArgs.size > 0) { - val dateStr = dateStrArgs[0] - val host = if (options.has(demoArgs.networkAddressArg)) { - options.valueOf(demoArgs.networkAddressArg) - } else { - "http://localhost:" + (Node.DEFAULT_PORT + 1) - } - if(!runDateChange(dateStr, host)) { - return 1 - } - } else { - println("Please provide a date") + if (!uploadTrade(tradeId, host)) { return 1 } } else { - // If these directory and identity file arguments aren't specified then we can assume a default setup and - // create everything that is needed without needing to run setup. - if(!options.has(demoArgs.dirArg) && !options.has(demoArgs.fakeTradeWithIdentityFile)) { - createNodeConfig(createNodeAParams()); - createNodeConfig(createNodeBParams()); + println("Please provide a trade ID") + return 1 + } + + return 0 +} + +private fun runDateChange(demoArgs: DemoArgs, options: OptionSet): Int { + val dateStrArgs = options.valuesOf(demoArgs.nonOptions) + if (dateStrArgs.size > 0) { + val dateStr = dateStrArgs[0] + val host = if (options.has(demoArgs.networkAddressArg)) { + options.valueOf(demoArgs.networkAddressArg) + } else { + "http://localhost:" + (Node.DEFAULT_PORT + 1) } - try { - runNode(configureNodeParams(role, demoArgs, options), demoNodeConfig) - } catch (e: NotSetupException) { - println(e.message) + if(!changeDate(dateStr, host)) { return 1 } + } else { + println("Please provide a date") + return 1 + } + + return 0 +} + +private fun runNode(role: IRSDemoRole, demoArgs: DemoArgs, options: OptionSet, demoNodeConfig: DemoConfig): Int { + // If these directory and identity file arguments aren't specified then we can assume a default setup and + // create everything that is needed without needing to run setup. + if(!options.has(demoArgs.dirArg) && !options.has(demoArgs.fakeTradeWithIdentityFile)) { + createNodeConfig(createNodeAParams()); + createNodeConfig(createNodeBParams()); + } + + try { + runNode(configureNodeParams(role, demoArgs, options), demoNodeConfig) + } catch (e: NotSetupException) { + println(e.message) + return 1 } return 0 @@ -178,11 +189,12 @@ private fun setupArgs(parser: OptionParser): DemoArgs { return args } -private fun setup(params: NodeParams) { +private fun setup(params: NodeParams): Int { createNodeConfig(params) + return 0 } -private fun runDateChange(date: String, host: String) : Boolean { +private fun changeDate(date: String, host: String) : Boolean { println("Changing date to " + date) val url = URL(host + "/api/irs/demodate") if(putJson(url, "\"" + date + "\"")) { @@ -194,7 +206,7 @@ private fun runDateChange(date: String, host: String) : Boolean { } } -private fun runTrade(tradeId: String, host: String) : Boolean { +private fun uploadTrade(tradeId: String, host: String) : Boolean { println("Uploading tradeID " + tradeId) val fileContents = IOUtils.toString(NodeParams::class.java.getResourceAsStream("example-irs-trade.json")) val tradeFile = fileContents.replace("tradeXXX", tradeId) From 3c11c26b125e0e73e7ff4996083298b8c3c64b34 Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Thu, 9 Jun 2016 11:51:33 +0100 Subject: [PATCH 023/114] Refactored IRSDemo to be more readable and to have minimal branches due to in memory mode in order to ensure tests are as similar to the real things as possible. --- src/main/kotlin/com/r3corda/demos/IRSDemo.kt | 100 +++++++------------ 1 file changed, 38 insertions(+), 62 deletions(-) diff --git a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt index aa534fc3cd..339080752d 100644 --- a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt @@ -4,6 +4,8 @@ import com.google.common.net.HostAndPort import com.typesafe.config.ConfigFactory import com.r3corda.core.crypto.Party import com.r3corda.core.logElapsedTime +import com.r3corda.core.messaging.MessageRecipients +import com.r3corda.core.messaging.SingleMessageRecipient import com.r3corda.node.internal.Node import com.r3corda.node.services.config.NodeConfiguration import com.r3corda.node.services.config.NodeConfigurationFromConfig @@ -58,7 +60,6 @@ enum class IRSDemoRole { } private class NodeParams() { - var id: Int = -1 var dir : Path = Paths.get("") var address : String = "" var mapAddress: String = "" @@ -251,11 +252,13 @@ private fun configureNodeParams(role: IRSDemoRole, args: DemoArgs, options: Opti return nodeParams } -private fun runNode(nodeParams : NodeParams, demoNodeConfig: DemoConfig) : Unit { - val node = when(demoNodeConfig.inMemory) { - true -> startDemoNode(nodeParams) - false -> startNode(nodeParams) - } +private fun runNode(nodeParams: NodeParams, demoNodeConfig: DemoConfig) : Unit { + val networkMap = createRecipient(nodeParams.mapAddress, nodeParams, demoNodeConfig.inMemory) + val destinations = nodeParams.tradeWithAddrs.map({ + createRecipient(it, nodeParams, demoNodeConfig.inMemory) + }) + + val node = startNode(nodeParams, networkMap, destinations, demoNodeConfig.inMemory) // Register handlers for the demo AutoOfferProtocol.Handler.register(node) UpdateBusinessDayProtocol.Handler.register(node) @@ -273,6 +276,17 @@ private fun runNode(nodeParams : NodeParams, demoNodeConfig: DemoConfig) : Unit } } +private fun createRecipient(addr: String, params: NodeParams, inMemory: Boolean) : SingleMessageRecipient { + val hostAndPort = HostAndPort.fromString(addr).withDefaultPort(Node.DEFAULT_PORT) + return if(inMemory) { + // Assumption here is that all nodes run in memory and thus cannot share a port number. + val id = hostAndPort.port + InMemoryMessagingNetwork.Handle(id, "Node " + id) + } else { + ArtemisMessagingService.makeRecipient(hostAndPort) + } +} + private fun runUploadRates(host: String) { val fileContents = IOUtils.toString(NodeParams::class.java.getResource("example.rates.txt")) var timer : Timer? = null @@ -366,7 +380,6 @@ private fun uploadFile(url: URL, file: String) : Boolean { private fun createNodeAParams() : NodeParams { val params = NodeParams() - params.id = 0 params.dir = Paths.get("nodeA") params.address = "localhost" params.tradeWithAddrs = listOf("localhost:31340") @@ -377,7 +390,6 @@ private fun createNodeAParams() : NodeParams { private fun createNodeBParams() : NodeParams { val params = NodeParams() - params.id = 1 params.dir = Paths.get("nodeB") params.address = "localhost:31340" params.tradeWithAddrs = listOf("localhost") @@ -414,7 +426,7 @@ private fun getNodeConfig(params: NodeParams): NodeConfiguration { return loadConfigFile(configFile, params.defaultLegalName) } -private fun startNode(params : NodeParams) : Node { +private fun startNode(params : NodeParams, networkMap: SingleMessageRecipient, recipients: List, inMemory: Boolean) : Node { val config = getNodeConfig(params) val advertisedServices: Set val myNetAddr = HostAndPort.fromString(params.address).withDefaultPort(Node.DEFAULT_PORT) @@ -424,58 +436,34 @@ private fun startNode(params : NodeParams) : Node { null } else { advertisedServices = setOf(NodeInterestRates.Type) - nodeInfo(params.mapAddress, params.identityFile, setOf(NetworkMapService.Type, SimpleNotaryService.Type)) + nodeInfo(networkMap, params.identityFile, setOf(NetworkMapService.Type, SimpleNotaryService.Type)) } - val node = logElapsedTime("Node startup") { Node(params.dir, myNetAddr, config, networkMapId, - advertisedServices, DemoClock(), - listOf(InterestRateSwapAPI::class.java)).setup().start() } + val node = if(inMemory) { + // Port is ID for in memory since we assume in memory is all on the same machine, thus ports are unique. + val messageService = messageNetwork.createNodeWithID(false, myNetAddr.port).start().get() + logElapsedTime("Node startup") { DemoNode(messageService, params.dir, myNetAddr, config, networkMapId, + advertisedServices, DemoClock(), + listOf(InterestRateSwapAPI::class.java)).start() } + } else { + logElapsedTime("Node startup") { Node(params.dir, myNetAddr, config, networkMapId, + advertisedServices, DemoClock(), + listOf(InterestRateSwapAPI::class.java)).setup().start() } + } // TODO: This should all be replaced by the identity service being updated // as the network map changes. if (params.tradeWithAddrs.size != params.tradeWithIdentities.size) { throw IllegalArgumentException("Different number of peer addresses (${params.tradeWithAddrs.size}) and identities (${params.tradeWithIdentities.size})") } - for ((hostAndPortString, identityFile) in params.tradeWithAddrs.zip(params.tradeWithIdentities)) { - val peerId = nodeInfo(hostAndPortString, identityFile) + for ((recipient, identityFile) in recipients.zip(params.tradeWithIdentities)) { + val peerId = nodeInfo(recipient, identityFile) node.services.identityService.registerIdentity(peerId.identity) } return node } -private fun startDemoNode(params : NodeParams) : Node { - val config = createNodeConfig(params) - val advertisedServices: Set - val myNetAddr = HostAndPort.fromString(params.address).withDefaultPort(Node.DEFAULT_PORT) - val networkMapId = if (params.mapAddress.equals(params.address)) { - // This node provides network map and notary services - advertisedServices = setOf(NetworkMapService.Type, SimpleNotaryService.Type) - null - } else { - advertisedServices = setOf(NodeInterestRates.Type) - - val handle = InMemoryMessagingNetwork.Handle(createNodeAParams().id, params.defaultLegalName) - nodeInfo(handle, params.identityFile, setOf(NetworkMapService.Type, SimpleNotaryService.Type)) - } - - val messageService = messageNetwork.createNodeWithID(false, params.id).start().get() - val node = logElapsedTime("Node startup") { DemoNode(messageService, params.dir, myNetAddr, config, networkMapId, - advertisedServices, DemoClock(), - listOf(InterestRateSwapAPI::class.java)).setup().start() } - - // TODO: This should all be replaced by the identity service being updated - // as the network map changes. - val identityFile = params.tradeWithIdentities[0] - // Since in integration tests there are only two nodes with IDs 0 and 1, this hack will work - // TODO: Get Artemis working with two nodes in the same process or come up with a better solution - val handle = InMemoryMessagingNetwork.Handle(1 - params.id, "Other Node") - val peerId = nodeInfo(handle, identityFile) - node.services.identityService.registerIdentity(peerId.identity) - - return node -} - private fun getRoleDir(role: IRSDemoRole) : Path { when(role) { IRSDemoRole.NodeA -> return Paths.get("nodeA") @@ -486,23 +474,11 @@ private fun getRoleDir(role: IRSDemoRole) : Path { } } -private fun nodeInfo(hostAndPortString: String, identityFile: Path, advertisedServices: Set = emptySet()): NodeInfo { - try { - val addr = HostAndPort.fromString(hostAndPortString).withDefaultPort(Node.DEFAULT_PORT) - val path = identityFile - val party = Files.readAllBytes(path).deserialize() - return NodeInfo(ArtemisMessagingService.makeRecipient(addr), party, advertisedServices) - } catch (e: Exception) { - println("Could not find identify file $identityFile.") - throw e - } -} - -private fun nodeInfo(handle: InMemoryMessagingNetwork.Handle, identityFile: Path, advertisedServices: Set = emptySet()): NodeInfo { +private fun nodeInfo(recipient: SingleMessageRecipient, identityFile: Path, advertisedServices: Set = emptySet()): NodeInfo { try { val path = identityFile val party = Files.readAllBytes(path).deserialize() - return NodeInfo(handle, party, advertisedServices) + return NodeInfo(recipient, party, advertisedServices) } catch (e: Exception) { println("Could not find identify file $identityFile.") throw e @@ -521,7 +497,7 @@ private fun loadConfigFile(configFile: File, defaultLegalName: String): NodeConf private fun createIdentities(params: NodeParams, nodeConf: NodeConfiguration) { val mockNetwork = MockNetwork(false) - val node = MockNetwork.MockNode(params.dir, nodeConf, mockNetwork, null, setOf(NetworkMapService.Type, SimpleNotaryService.Type), params.id, null) + val node = MockNetwork.MockNode(params.dir, nodeConf, mockNetwork, null, setOf(NetworkMapService.Type, SimpleNotaryService.Type), 0, null) node.start() node.stop() } From 2d9989c5dfddda0db0afe45be66b35f5803d7f19 Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Thu, 9 Jun 2016 11:54:25 +0100 Subject: [PATCH 024/114] Rearranged code for improved reading locality. --- src/main/kotlin/com/r3corda/demos/IRSDemo.kt | 104 +++++++++---------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt index 339080752d..ada22245d6 100644 --- a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt @@ -253,9 +253,9 @@ private fun configureNodeParams(role: IRSDemoRole, args: DemoArgs, options: Opti } private fun runNode(nodeParams: NodeParams, demoNodeConfig: DemoConfig) : Unit { - val networkMap = createRecipient(nodeParams.mapAddress, nodeParams, demoNodeConfig.inMemory) + val networkMap = createRecipient(nodeParams.mapAddress, demoNodeConfig.inMemory) val destinations = nodeParams.tradeWithAddrs.map({ - createRecipient(it, nodeParams, demoNodeConfig.inMemory) + createRecipient(it, demoNodeConfig.inMemory) }) val node = startNode(nodeParams, networkMap, destinations, demoNodeConfig.inMemory) @@ -276,7 +276,7 @@ private fun runNode(nodeParams: NodeParams, demoNodeConfig: DemoConfig) : Unit { } } -private fun createRecipient(addr: String, params: NodeParams, inMemory: Boolean) : SingleMessageRecipient { +private fun createRecipient(addr: String, inMemory: Boolean) : SingleMessageRecipient { val hostAndPort = HostAndPort.fromString(addr).withDefaultPort(Node.DEFAULT_PORT) return if(inMemory) { // Assumption here is that all nodes run in memory and thus cannot share a port number. @@ -287,6 +287,55 @@ private fun createRecipient(addr: String, params: NodeParams, inMemory: Boolean) } } +private fun startNode(params : NodeParams, networkMap: SingleMessageRecipient, recipients: List, inMemory: Boolean) : Node { + val config = getNodeConfig(params) + val advertisedServices: Set + val myNetAddr = HostAndPort.fromString(params.address).withDefaultPort(Node.DEFAULT_PORT) + val networkMapId = if (params.mapAddress.equals(params.address)) { + // This node provides network map and notary services + advertisedServices = setOf(NetworkMapService.Type, SimpleNotaryService.Type) + null + } else { + advertisedServices = setOf(NodeInterestRates.Type) + nodeInfo(networkMap, params.identityFile, setOf(NetworkMapService.Type, SimpleNotaryService.Type)) + } + + val node = if(inMemory) { + // Port is ID for in memory since we assume in memory is all on the same machine, thus ports are unique. + val messageService = messageNetwork.createNodeWithID(false, myNetAddr.port).start().get() + logElapsedTime("Node startup") { DemoNode(messageService, params.dir, myNetAddr, config, networkMapId, + advertisedServices, DemoClock(), + listOf(InterestRateSwapAPI::class.java)).start() } + } else { + logElapsedTime("Node startup") { Node(params.dir, myNetAddr, config, networkMapId, + advertisedServices, DemoClock(), + listOf(InterestRateSwapAPI::class.java)).start() } + } + + // TODO: This should all be replaced by the identity service being updated + // as the network map changes. + if (params.tradeWithAddrs.size != params.tradeWithIdentities.size) { + throw IllegalArgumentException("Different number of peer addresses (${params.tradeWithAddrs.size}) and identities (${params.tradeWithIdentities.size})") + } + for ((recipient, identityFile) in recipients.zip(params.tradeWithIdentities)) { + val peerId = nodeInfo(recipient, identityFile) + node.services.identityService.registerIdentity(peerId.identity) + } + + return node +} + +private fun nodeInfo(recipient: SingleMessageRecipient, identityFile: Path, advertisedServices: Set = emptySet()): NodeInfo { + try { + val path = identityFile + val party = Files.readAllBytes(path).deserialize() + return NodeInfo(recipient, party, advertisedServices) + } catch (e: Exception) { + println("Could not find identify file $identityFile.") + throw e + } +} + private fun runUploadRates(host: String) { val fileContents = IOUtils.toString(NodeParams::class.java.getResource("example.rates.txt")) var timer : Timer? = null @@ -426,44 +475,6 @@ private fun getNodeConfig(params: NodeParams): NodeConfiguration { return loadConfigFile(configFile, params.defaultLegalName) } -private fun startNode(params : NodeParams, networkMap: SingleMessageRecipient, recipients: List, inMemory: Boolean) : Node { - val config = getNodeConfig(params) - val advertisedServices: Set - val myNetAddr = HostAndPort.fromString(params.address).withDefaultPort(Node.DEFAULT_PORT) - val networkMapId = if (params.mapAddress.equals(params.address)) { - // This node provides network map and notary services - advertisedServices = setOf(NetworkMapService.Type, SimpleNotaryService.Type) - null - } else { - advertisedServices = setOf(NodeInterestRates.Type) - nodeInfo(networkMap, params.identityFile, setOf(NetworkMapService.Type, SimpleNotaryService.Type)) - } - - val node = if(inMemory) { - // Port is ID for in memory since we assume in memory is all on the same machine, thus ports are unique. - val messageService = messageNetwork.createNodeWithID(false, myNetAddr.port).start().get() - logElapsedTime("Node startup") { DemoNode(messageService, params.dir, myNetAddr, config, networkMapId, - advertisedServices, DemoClock(), - listOf(InterestRateSwapAPI::class.java)).start() } - } else { - logElapsedTime("Node startup") { Node(params.dir, myNetAddr, config, networkMapId, - advertisedServices, DemoClock(), - listOf(InterestRateSwapAPI::class.java)).setup().start() } - } - - // TODO: This should all be replaced by the identity service being updated - // as the network map changes. - if (params.tradeWithAddrs.size != params.tradeWithIdentities.size) { - throw IllegalArgumentException("Different number of peer addresses (${params.tradeWithAddrs.size}) and identities (${params.tradeWithIdentities.size})") - } - for ((recipient, identityFile) in recipients.zip(params.tradeWithIdentities)) { - val peerId = nodeInfo(recipient, identityFile) - node.services.identityService.registerIdentity(peerId.identity) - } - - return node -} - private fun getRoleDir(role: IRSDemoRole) : Path { when(role) { IRSDemoRole.NodeA -> return Paths.get("nodeA") @@ -474,17 +485,6 @@ private fun getRoleDir(role: IRSDemoRole) : Path { } } -private fun nodeInfo(recipient: SingleMessageRecipient, identityFile: Path, advertisedServices: Set = emptySet()): NodeInfo { - try { - val path = identityFile - val party = Files.readAllBytes(path).deserialize() - return NodeInfo(recipient, party, advertisedServices) - } catch (e: Exception) { - println("Could not find identify file $identityFile.") - throw e - } -} - private fun loadConfigFile(configFile: File, defaultLegalName: String): NodeConfiguration { if (!configFile.exists()) { createDefaultConfigFile(configFile, defaultLegalName) From 532416ec5a8db3a1850dd79abe95c8dfd49bef6e Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Thu, 9 Jun 2016 11:57:35 +0100 Subject: [PATCH 025/114] Corrected name of the TraderDemoTest file. --- .../r3corda/core/testing/{TradeDemoTest.kt => TraderDemoTest.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/test/kotlin/com/r3corda/core/testing/{TradeDemoTest.kt => TraderDemoTest.kt} (100%) diff --git a/src/test/kotlin/com/r3corda/core/testing/TradeDemoTest.kt b/src/test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt similarity index 100% rename from src/test/kotlin/com/r3corda/core/testing/TradeDemoTest.kt rename to src/test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt From 99fdacd0dc1475d40955280ae7f6e78438f40200 Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Thu, 9 Jun 2016 14:11:18 +0100 Subject: [PATCH 026/114] Integration tests now run separately from unit tests (with caveats described in the gradle file) --- build.gradle | 29 +++++++++++++++++-- .../com/r3corda/core/testing/IRSDemoTest.kt | 0 .../r3corda/core/testing/IRSSimulationTest.kt | 0 .../r3corda/core/testing/TraderDemoTest.kt | 0 4 files changed, 27 insertions(+), 2 deletions(-) rename src/{test => integration-test}/kotlin/com/r3corda/core/testing/IRSDemoTest.kt (100%) rename src/{test => integration-test}/kotlin/com/r3corda/core/testing/IRSSimulationTest.kt (100%) rename src/{test => integration-test}/kotlin/com/r3corda/core/testing/TraderDemoTest.kt (100%) diff --git a/build.gradle b/build.gradle index 6af144aef3..99ee6ad948 100644 --- a/build.gradle +++ b/build.gradle @@ -44,10 +44,23 @@ repositories { jcenter() } +sourceSets { + integrationTest { + kotlin { + compileClasspath += main.output + test.output + runtimeClasspath += main.output + test.output + srcDir file('src/integration-test/kotlin') + } + } +} + //noinspection GroovyAssignabilityCheck configurations { // we don't want isolated.jar in classPath, since we want to test jar being dynamically loaded as an attachment runtime.exclude module: 'isolated' + + integrationTestCompile.extendsFrom testCompile + integrationTestRuntime.extendsFrom testRuntime } // This is required for quasar. I think. @@ -70,6 +83,10 @@ dependencies { testCompile 'junit:junit:4.12' testCompile 'org.assertj:assertj-core:3.4.1' testCompile 'com.pholser:junit-quickcheck-core:0.6' + + // Integration test helpers + integrationTestCompile 'junit:junit:4.12' + integrationTestCompile 'org.assertj:assertj-core:3.4.1' } // Package up the demo programs. @@ -99,8 +116,7 @@ task getTraderDemo(type: CreateStartScripts) { // Force windows script classpath to wildcard path to avoid the 'Command Line Is Too Long' issues // with generated scripts. Include Jolokia .war explicitly as this isn't picked up by wildcard -tasks.withType(CreateStartScripts) -{ +tasks.withType(CreateStartScripts) { doLast { windowsScript.text = windowsScript .readLines() @@ -109,6 +125,15 @@ tasks.withType(CreateStartScripts) } } +task integrationTest(type: Test) { + testClassesDir = sourceSets.integrationTest.output.classesDir + classpath = sourceSets.integrationTest.runtimeClasspath +} + +tasks.withType(Test) { + reports.html.destination = file("${reporting.baseDir}/${name}") +} + quasarScan.dependsOn('classes', 'core:classes', 'contracts:classes', 'node:classes') applicationDistribution.into("bin") { diff --git a/src/test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt b/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt similarity index 100% rename from src/test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt rename to src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt diff --git a/src/test/kotlin/com/r3corda/core/testing/IRSSimulationTest.kt b/src/integration-test/kotlin/com/r3corda/core/testing/IRSSimulationTest.kt similarity index 100% rename from src/test/kotlin/com/r3corda/core/testing/IRSSimulationTest.kt rename to src/integration-test/kotlin/com/r3corda/core/testing/IRSSimulationTest.kt diff --git a/src/test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt b/src/integration-test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt similarity index 100% rename from src/test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt rename to src/integration-test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt From ecdd0a23a2e88032f827ebf780ad9dcf6c522c43 Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Thu, 9 Jun 2016 14:11:47 +0100 Subject: [PATCH 027/114] Fixed bug in IRS demo where the node threads never exit during integration tests and cause other tests to fail. --- .../com/r3corda/core/testing/IRSDemoTest.kt | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt b/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt index 33a0a389f4..833690320c 100644 --- a/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt +++ b/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt @@ -15,10 +15,12 @@ class IRSDemoTest { try { setupNode(dirA, "NodeA") setupNode(dirB, "NodeB") - startNode(dirA, "NodeA") - startNode(dirB, "NodeB") + val threadA = startNode(dirA, "NodeA") + val threadB = startNode(dirB, "NodeB") runTrade() runDateChange() + stopNode(threadA) + stopNode(threadB) } finally { cleanup(dirA) cleanup(dirB) @@ -30,9 +32,9 @@ private fun setupNode(dir: Path, nodeType: String) { runIRSDemo(arrayOf("--role", "Setup" + nodeType, "--dir", dir.toString())) } -private fun startNode(dir: Path, nodeType: String) { +private fun startNode(dir: Path, nodeType: String): Thread { val config = DemoConfig(true) - thread(true, false, null, nodeType, -1, { + val nodeThread = thread(true, false, null, nodeType, -1, { try { runIRSDemo(arrayOf("--role", nodeType, "--dir", dir.toString()), config) } finally { @@ -41,6 +43,7 @@ private fun startNode(dir: Path, nodeType: String) { } }) config.nodeReady.await() + return nodeThread } private fun runTrade() { @@ -51,6 +54,11 @@ private fun runDateChange() { assertEquals(runIRSDemo(arrayOf("--role", "Date", "2017-01-02")), 0) } +private fun stopNode(nodeThread: Thread) { + // The demo is designed to exit on interrupt + nodeThread.interrupt() +} + private fun cleanup(dir: Path) { println("Erasing: " + dir.toString()) dir.toFile().deleteRecursively() From bef4258430d4590647a990996c79b020faa529d0 Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Thu, 9 Jun 2016 14:12:27 +0100 Subject: [PATCH 028/114] Fixed Emoji crash where LANG envvar is not defined in particularly exotic setups (msys bash in Powershell for example) --- core/src/main/kotlin/com/r3corda/core/utilities/Emoji.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/kotlin/com/r3corda/core/utilities/Emoji.kt b/core/src/main/kotlin/com/r3corda/core/utilities/Emoji.kt index 98fb29ad68..7a8ce93e84 100644 --- a/core/src/main/kotlin/com/r3corda/core/utilities/Emoji.kt +++ b/core/src/main/kotlin/com/r3corda/core/utilities/Emoji.kt @@ -4,7 +4,7 @@ package com.r3corda.core.utilities * A simple wrapper class that contains icons and support for printing them only when we're connected to a terminal. */ object Emoji { - val hasEmojiTerminal by lazy { System.getenv("TERM") != null && System.getenv("LANG").contains("UTF-8") } + val hasEmojiTerminal by lazy { System.getenv("TERM") != null && (System.getenv("LANG") != null) && System.getenv("LANG").contains("UTF-8") } const val CODE_DIAMOND = "\ud83d\udd37" const val CODE_BAG_OF_CASH = "\ud83d\udcb0" From 22dd36950c7f7ae8739c3b1fad94600b11fd6681 Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Thu, 9 Jun 2016 14:22:36 +0100 Subject: [PATCH 029/114] Moved the IRSSimulationTest back into the unit test directory. --- .../kotlin/com/r3corda/core/testing/IRSSimulationTest.kt | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{integration-test => test}/kotlin/com/r3corda/core/testing/IRSSimulationTest.kt (100%) diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/IRSSimulationTest.kt b/src/test/kotlin/com/r3corda/core/testing/IRSSimulationTest.kt similarity index 100% rename from src/integration-test/kotlin/com/r3corda/core/testing/IRSSimulationTest.kt rename to src/test/kotlin/com/r3corda/core/testing/IRSSimulationTest.kt From 03e2852880d4395e60044959089bce6a421bb049 Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Thu, 9 Jun 2016 16:42:06 +0100 Subject: [PATCH 030/114] The integration tests for demos now spawn a new JVM instead of using threads. Demos no longer need or contain any in memory node logic. --- .../com/r3corda/core/testing/IRSDemoTest.kt | 51 ++++++------ .../com/r3corda/core/testing/JVMSpawner.kt | 15 ++++ .../r3corda/core/testing/TraderDemoTest.kt | 29 +++---- src/main/kotlin/com/r3corda/demos/DemoNode.kt | 33 -------- src/main/kotlin/com/r3corda/demos/IRSDemo.kt | 45 ++++------- .../kotlin/com/r3corda/demos/TraderDemo.kt | 79 ++++--------------- 6 files changed, 81 insertions(+), 171 deletions(-) create mode 100644 src/integration-test/kotlin/com/r3corda/core/testing/JVMSpawner.kt delete mode 100644 src/main/kotlin/com/r3corda/demos/DemoNode.kt diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt b/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt index 833690320c..e7812cd784 100644 --- a/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt +++ b/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt @@ -1,8 +1,5 @@ package com.r3corda.core.testing -import com.r3corda.demos.DemoConfig -import com.r3corda.demos.runIRSDemo -import kotlin.concurrent.thread import kotlin.test.assertEquals import org.junit.Test import java.nio.file.Path @@ -12,51 +9,53 @@ class IRSDemoTest { @Test fun `runs IRS demo`() { val dirA = Paths.get("./nodeA") val dirB = Paths.get("./nodeB") + var procA: Process? = null + var procB: Process? = null try { setupNode(dirA, "NodeA") setupNode(dirB, "NodeB") - val threadA = startNode(dirA, "NodeA") - val threadB = startNode(dirB, "NodeB") + procA = startNode(dirA, "NodeA") + procB = startNode(dirB, "NodeB") runTrade() runDateChange() - stopNode(threadA) - stopNode(threadB) } finally { + stopNode(procA) + stopNode(procB) cleanup(dirA) cleanup(dirB) } } } - private fun setupNode(dir: Path, nodeType: String) { - runIRSDemo(arrayOf("--role", "Setup" + nodeType, "--dir", dir.toString())) + val args = listOf("--role", "Setup" + nodeType, "--dir", dir.toString()) + val proc = spawn("com.r3corda.demos.IRSDemoKt", args) + proc.waitFor(); + assertEquals(proc.exitValue(), 0) } -private fun startNode(dir: Path, nodeType: String): Thread { - val config = DemoConfig(true) - val nodeThread = thread(true, false, null, nodeType, -1, { - try { - runIRSDemo(arrayOf("--role", nodeType, "--dir", dir.toString()), config) - } finally { - // Will only reach here during error or after node is stopped, so ensure lock is unlocked. - config.nodeReady.countDown() - } - }) - config.nodeReady.await() - return nodeThread +private fun startNode(dir: Path, nodeType: String): Process { + val args = listOf("--role", nodeType, "--dir", dir.toString()) + val proc = spawn("com.r3corda.demos.IRSDemoKt", args) + Thread.sleep(15000) + return proc } private fun runTrade() { - assertEquals(runIRSDemo(arrayOf("--role", "Trade", "trade1")), 0) + val args = listOf("--role", "Trade", "trade1") + val proc = spawn("com.r3corda.demos.IRSDemoKt", args) + proc.waitFor(); + assertEquals(proc.exitValue(), 0) } private fun runDateChange() { - assertEquals(runIRSDemo(arrayOf("--role", "Date", "2017-01-02")), 0) + val args = listOf("--role", "Date", "2017-01-02") + val proc = spawn("com.r3corda.demos.IRSDemoKt", args) + proc.waitFor(); + assertEquals(proc.exitValue(), 0) } -private fun stopNode(nodeThread: Thread) { - // The demo is designed to exit on interrupt - nodeThread.interrupt() +private fun stopNode(nodeProc: Process?) { + nodeProc?.destroy() } private fun cleanup(dir: Path) { diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/JVMSpawner.kt b/src/integration-test/kotlin/com/r3corda/core/testing/JVMSpawner.kt new file mode 100644 index 0000000000..7ddf11a160 --- /dev/null +++ b/src/integration-test/kotlin/com/r3corda/core/testing/JVMSpawner.kt @@ -0,0 +1,15 @@ +package com.r3corda.core.testing + +import java.nio.file.Paths + +fun spawn(className: String, args: List): Process { + val separator = System.getProperty("file.separator") + val classpath = System.getProperty("java.class.path") + val path = System.getProperty("java.home") + separator + "bin" + separator + "java" + val javaArgs = listOf(path, "-javaagent:lib/quasar.jar", "-cp", classpath, className) + val builder = ProcessBuilder(javaArgs + args) + builder.redirectError(Paths.get("error.$className.log").toFile()) + builder.inheritIO() + val process = builder.start(); + return process +} diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt b/src/integration-test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt index bc29139cb4..576ab9d0be 100644 --- a/src/integration-test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt +++ b/src/integration-test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt @@ -1,39 +1,34 @@ package com.r3corda.core.testing -import com.r3corda.demos.DemoConfig -import com.r3corda.demos.runTraderDemo import org.junit.Test import java.nio.file.Paths -import kotlin.concurrent.thread import kotlin.test.assertEquals class TraderDemoTest { @Test fun `runs trader demo`() { + var nodeProc: Process? = null try { - runBuyer() + nodeProc = runBuyer() runSeller() } finally { + nodeProc?.destroy() cleanup() } } } -private fun runBuyer() { - val config = DemoConfig(true) - thread(true, false, null, "Buyer", -1, { - try { - runTraderDemo(arrayOf("--role", "BUYER"), config) - } finally { - // Will only reach here during error or after node is stopped, so ensure lock is unlocked. - config.nodeReady.countDown() - } - }) - config.nodeReady.await() +private fun runBuyer(): Process { + val args = listOf("--role", "BUYER") + val proc = spawn("com.r3corda.demos.TraderDemoKt", args) + Thread.sleep(15000) + return proc } private fun runSeller() { - val config = DemoConfig(true) - assertEquals(runTraderDemo(arrayOf("--role", "SELLER"), config), 0) + val args = listOf("--role", "SELLER") + val proc = spawn("com.r3corda.demos.TraderDemoKt", args) + proc.waitFor(); + assertEquals(proc.exitValue(), 0) } private fun cleanup() { diff --git a/src/main/kotlin/com/r3corda/demos/DemoNode.kt b/src/main/kotlin/com/r3corda/demos/DemoNode.kt deleted file mode 100644 index 508b2feb03..0000000000 --- a/src/main/kotlin/com/r3corda/demos/DemoNode.kt +++ /dev/null @@ -1,33 +0,0 @@ -package com.r3corda.demos - -import com.google.common.net.HostAndPort -import com.r3corda.core.messaging.MessagingService -import com.r3corda.core.node.NodeInfo -import com.r3corda.core.node.services.ServiceType -import com.r3corda.node.internal.Node -import com.r3corda.node.serialization.NodeClock -import com.r3corda.node.services.config.NodeConfiguration -import com.r3corda.node.services.network.InMemoryMessagingNetwork -import java.nio.file.Path -import java.time.Clock -import java.util.concurrent.CountDownLatch - -val messageNetwork = InMemoryMessagingNetwork() - -class DemoNode(messagingService: MessagingService, dir: Path, p2pAddr: HostAndPort, config: NodeConfiguration, - networkMapAddress: NodeInfo?, advertisedServices: Set, - clock: Clock = NodeClock(), clientAPIs: List> = listOf()) -: Node(dir, p2pAddr, config, networkMapAddress, advertisedServices, clock, clientAPIs) { - - val messagingService = messagingService - override fun makeMessagingService(): MessagingService { - return messagingService - } - - override fun startMessagingService() = Unit -} - -class DemoConfig(useInMemoryMessaging: Boolean = false) { - val inMemory = useInMemoryMessaging - val nodeReady = CountDownLatch(1) -} \ No newline at end of file diff --git a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt index ada22245d6..26a69eb1c3 100644 --- a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt @@ -89,7 +89,7 @@ fun main(args: Array) { exitProcess(runIRSDemo(args)) } -fun runIRSDemo(args: Array, demoNodeConfig: DemoConfig = DemoConfig()): Int { +fun runIRSDemo(args: Array): Int { val parser = OptionParser() val demoArgs = setupArgs(parser) val options = try { @@ -107,8 +107,8 @@ fun runIRSDemo(args: Array, demoNodeConfig: DemoConfig = DemoConfig()): return when (role) { IRSDemoRole.SetupNodeA -> setup(configureNodeParams(IRSDemoRole.NodeA, demoArgs, options)) IRSDemoRole.SetupNodeB -> setup(configureNodeParams(IRSDemoRole.NodeB, demoArgs, options)) - IRSDemoRole.NodeA -> runNode(role, demoArgs, options, demoNodeConfig) - IRSDemoRole.NodeB -> runNode(role, demoArgs, options, demoNodeConfig) + IRSDemoRole.NodeA -> runNode(role, demoArgs, options) + IRSDemoRole.NodeB -> runNode(role, demoArgs, options) IRSDemoRole.Trade -> runTrade(demoArgs, options) IRSDemoRole.Date -> runDateChange(demoArgs, options) } @@ -156,7 +156,7 @@ private fun runDateChange(demoArgs: DemoArgs, options: OptionSet): Int { return 0 } -private fun runNode(role: IRSDemoRole, demoArgs: DemoArgs, options: OptionSet, demoNodeConfig: DemoConfig): Int { +private fun runNode(role: IRSDemoRole, demoArgs: DemoArgs, options: OptionSet): Int { // If these directory and identity file arguments aren't specified then we can assume a default setup and // create everything that is needed without needing to run setup. if(!options.has(demoArgs.dirArg) && !options.has(demoArgs.fakeTradeWithIdentityFile)) { @@ -165,7 +165,7 @@ private fun runNode(role: IRSDemoRole, demoArgs: DemoArgs, options: OptionSet, d } try { - runNode(configureNodeParams(role, demoArgs, options), demoNodeConfig) + runNode(configureNodeParams(role, demoArgs, options)) } catch (e: NotSetupException) { println(e.message) return 1 @@ -252,13 +252,13 @@ private fun configureNodeParams(role: IRSDemoRole, args: DemoArgs, options: Opti return nodeParams } -private fun runNode(nodeParams: NodeParams, demoNodeConfig: DemoConfig) : Unit { - val networkMap = createRecipient(nodeParams.mapAddress, demoNodeConfig.inMemory) +private fun runNode(nodeParams: NodeParams) : Unit { + val networkMap = createRecipient(nodeParams.mapAddress) val destinations = nodeParams.tradeWithAddrs.map({ - createRecipient(it, demoNodeConfig.inMemory) + createRecipient(it) }) - val node = startNode(nodeParams, networkMap, destinations, demoNodeConfig.inMemory) + val node = startNode(nodeParams, networkMap, destinations) // Register handlers for the demo AutoOfferProtocol.Handler.register(node) UpdateBusinessDayProtocol.Handler.register(node) @@ -268,7 +268,6 @@ private fun runNode(nodeParams: NodeParams, demoNodeConfig: DemoConfig) : Unit { runUploadRates("http://localhost:31341") } - demoNodeConfig.nodeReady.countDown() try { while (true) Thread.sleep(Long.MAX_VALUE) } catch(e: InterruptedException) { @@ -276,18 +275,12 @@ private fun runNode(nodeParams: NodeParams, demoNodeConfig: DemoConfig) : Unit { } } -private fun createRecipient(addr: String, inMemory: Boolean) : SingleMessageRecipient { +private fun createRecipient(addr: String) : SingleMessageRecipient { val hostAndPort = HostAndPort.fromString(addr).withDefaultPort(Node.DEFAULT_PORT) - return if(inMemory) { - // Assumption here is that all nodes run in memory and thus cannot share a port number. - val id = hostAndPort.port - InMemoryMessagingNetwork.Handle(id, "Node " + id) - } else { - ArtemisMessagingService.makeRecipient(hostAndPort) - } + return ArtemisMessagingService.makeRecipient(hostAndPort) } -private fun startNode(params : NodeParams, networkMap: SingleMessageRecipient, recipients: List, inMemory: Boolean) : Node { +private fun startNode(params : NodeParams, networkMap: SingleMessageRecipient, recipients: List) : Node { val config = getNodeConfig(params) val advertisedServices: Set val myNetAddr = HostAndPort.fromString(params.address).withDefaultPort(Node.DEFAULT_PORT) @@ -300,17 +293,9 @@ private fun startNode(params : NodeParams, networkMap: SingleMessageRecipient, r nodeInfo(networkMap, params.identityFile, setOf(NetworkMapService.Type, SimpleNotaryService.Type)) } - val node = if(inMemory) { - // Port is ID for in memory since we assume in memory is all on the same machine, thus ports are unique. - val messageService = messageNetwork.createNodeWithID(false, myNetAddr.port).start().get() - logElapsedTime("Node startup") { DemoNode(messageService, params.dir, myNetAddr, config, networkMapId, - advertisedServices, DemoClock(), - listOf(InterestRateSwapAPI::class.java)).start() } - } else { - logElapsedTime("Node startup") { Node(params.dir, myNetAddr, config, networkMapId, - advertisedServices, DemoClock(), - listOf(InterestRateSwapAPI::class.java)).start() } - } + val node = logElapsedTime("Node startup") { Node(params.dir, myNetAddr, config, networkMapId, + advertisedServices, DemoClock(), + listOf(InterestRateSwapAPI::class.java)).start() } // TODO: This should all be replaced by the identity service being updated // as the network map changes. diff --git a/src/main/kotlin/com/r3corda/demos/TraderDemo.kt b/src/main/kotlin/com/r3corda/demos/TraderDemo.kt index a3effd7b68..8967f1f459 100644 --- a/src/main/kotlin/com/r3corda/demos/TraderDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/TraderDemo.kt @@ -24,7 +24,6 @@ import com.r3corda.core.utilities.ProgressTracker import com.r3corda.node.internal.Node import com.r3corda.node.services.config.NodeConfigurationFromConfig import com.r3corda.node.services.messaging.ArtemisMessagingService -import com.r3corda.node.services.network.InMemoryMessagingNetwork import com.r3corda.node.services.network.NetworkMapService import com.r3corda.node.services.persistence.NodeAttachmentService import com.r3corda.node.services.transactions.SimpleNotaryService @@ -63,10 +62,6 @@ enum class Role { BUYER, SELLER } - -private class Destination constructor(addr: Any, inMemory: Boolean): Serializable { - val inMemory = inMemory - val addr = addr } // And this is the directory under the current working directory where each node will create its own server directory, @@ -77,7 +72,7 @@ fun main(args: Array) { exitProcess(runTraderDemo(args)) } -fun runTraderDemo(args: Array, demoNodeConfig: DemoConfig = DemoConfig()): Int { +fun runTraderDemo(args: Array): Int { val cashIssuerKey = generateKeyPair() val cashIssuer = Party("Trusted cash issuer", cashIssuerKey.public) val amount = 1000.DOLLARS `issued by` cashIssuer.ref(1) @@ -110,19 +105,6 @@ fun runTraderDemo(args: Array, demoNodeConfig: DemoConfig = DemoConfig() } ) - val peerId: Int; - val id: Int - when (role) { - Role.BUYER -> { - peerId = 1 - id = 0 - } - Role.SELLER -> { - peerId = 0 - id = 1 - } - } - // Suppress the Artemis MQ noise, and activate the demo logging. // // The first two strings correspond to the first argument to StateMachineManager.add() but the way we handle logging @@ -161,28 +143,9 @@ fun runTraderDemo(args: Array, demoNodeConfig: DemoConfig = DemoConfig() advertisedServices = emptySet() cashIssuer = party NodeInfo(ArtemisMessagingService.makeRecipient(theirNetAddr), party, setOf(NetworkMapService.Type)) - - if(demoNodeConfig.inMemory) { - val handle = InMemoryMessagingNetwork.Handle(peerId, "Other Node") - NodeInfo(handle, party, setOf(NetworkMapService.Type)) - } else { - NodeInfo(ArtemisMessagingService.makeRecipient(theirNetAddr), party, setOf(NetworkMapService.Type)) - } } - val messageService = messageNetwork.createNodeWithID(false, id).start().get() // And now construct then start the node object. It takes a little while. - val node = logElapsedTime("Node startup") { - if(demoNodeConfig.inMemory) { - DemoNode(messageService, directory, myNetAddr, config, networkMapId, advertisedServices).setup().start() - } else { - Node(directory, myNetAddr, config, networkMapId, advertisedServices).setup().start() - } - } - - // TODO: Replace with a separate trusted cash issuer - if (cashIssuer == null) { - cashIssuer = node.services.storageService.myLegalIdentity - } + val node = logElapsedTime("Node startup") { Node(directory, myNetAddr, config, networkMapId, advertisedServices).setup().start() } // What happens next depends on the role. The buyer sits around waiting for a trade to start. The seller role // will contact the buyer and actually make something happen. @@ -190,24 +153,14 @@ fun runTraderDemo(args: Array, demoNodeConfig: DemoConfig = DemoConfig() if (role == Role.BUYER) { runBuyer(node, amount) } else { - val dest: Destination - val recipient: SingleMessageRecipient - - if(demoNodeConfig.inMemory) { - recipient = InMemoryMessagingNetwork.Handle(peerId, "Other Node") - dest = Destination(InMemoryMessagingNetwork.Handle(id, role.toString()), true) - } else { - recipient = ArtemisMessagingService.makeRecipient(theirNetAddr) - dest = Destination(myNetAddr, false) - } - - runSeller(dest, node, recipient, amount)) + val recipient = ArtemisMessagingService.makeRecipient(theirNetAddr) + runSeller(myNetAddr, node, recipient, amount) } return 0 } -private fun runSeller(myAddr: Destination, node: Node, recipient: SingleMessageRecipient) { +private fun runSeller(myAddr: HostAndPort, node: Node, recipient: SingleMessageRecipient) { // The seller will sell some commercial paper to the buyer, who will pay with (self issued) cash. // // The CP sale transaction comes with a prospectus PDF, which will tag along for the ride in an @@ -283,12 +236,8 @@ private class TraderDemoProtocolBuyer(private val attachmentsPath: Path, // As the seller initiates the two-party trade protocol, here, we will be the buyer. try { progressTracker.currentStep = WAITING_FOR_SELLER_TO_CONNECT - val origin: Destination = receive(DEMO_TOPIC, 0).validate { it } - val recipient: SingleMessageRecipient = if(origin.inMemory) { - origin.addr as InMemoryMessagingNetwork.Handle - } else { - ArtemisMessagingService.makeRecipient(origin.addr as HostAndPort) - } + val origin = receive(DEMO_TOPIC, 0).validate { it.withDefaultPort(Node.DEFAULT_PORT) } + val recipient = ArtemisMessagingService.makeRecipient(origin as HostAndPort) // The session ID disambiguates the test trade. val sessionID = random63BitValue() @@ -296,7 +245,7 @@ private class TraderDemoProtocolBuyer(private val attachmentsPath: Path, send(DEMO_TOPIC, recipient, 0, sessionID) val notary = serviceHub.networkMapCache.notaryNodes[0] - val buyer = TwoPartyTradeProtocol.Buyer(recipient, notary.identity, amount, + val buyer = TwoPartyTradeProtocol.Buyer(recipient, notary.identity, 1000.DOLLARS, CommercialPaper.State::class.java, sessionID) // This invokes the trading protocol and out pops our finished transaction. @@ -339,7 +288,7 @@ ${Emoji.renderIfSupported(cpIssuance)}""") } } -private class TraderDemoProtocolSeller(val myAddr: Destination, +private class TraderDemoProtocolSeller(val myAddr: HostAndPort, val otherSide: SingleMessageRecipient, val amount: Amount>, override val progressTracker: ProgressTracker = TraderDemoProtocolSeller.tracker()) : ProtocolLogic() { @@ -350,21 +299,21 @@ private class TraderDemoProtocolSeller(val myAddr: Destination, object SELF_ISSUING : ProgressTracker.Step("Got session ID back, issuing and timestamping some commercial paper") - object TRADING : ProgressTracker.Step("Starting the trade protocol") { - override fun childProgressTracker(): ProgressTracker = TwoPartyTradeProtocol.Seller.tracker() - } + object TRADING : ProgressTracker.Step("Starting the trade protocol") // We vend a progress tracker that already knows there's going to be a TwoPartyTradingProtocol involved at some // point: by setting up the tracker in advance, the user can see what's coming in more detail, instead of being // surprised when it appears as a new set of tasks below the current one. - fun tracker() = ProgressTracker(ANNOUNCING, SELF_ISSUING, TRADING) + fun tracker() = ProgressTracker(ANNOUNCING, SELF_ISSUING, TRADING).apply { + childrenFor[TRADING] = TwoPartyTradeProtocol.Seller.tracker() + } } @Suspendable override fun call() { progressTracker.currentStep = ANNOUNCING - val sessionID = sendAndReceive(DEMO_TOPIC, otherSide, 0, 0, myAddress).validate { it } + val sessionID = sendAndReceive(DEMO_TOPIC, otherSide, 0, 0, myAddr).validate { it } progressTracker.currentStep = SELF_ISSUING From 36a0ff0503b4398d6bb2e0c7c9056343ed01e482 Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Thu, 9 Jun 2016 17:28:46 +0100 Subject: [PATCH 031/114] Added an endpoint that allows querying for status of node. --- node/src/main/kotlin/com/r3corda/node/api/APIServer.kt | 9 +++++++++ .../kotlin/com/r3corda/node/internal/APIServerImpl.kt | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/node/src/main/kotlin/com/r3corda/node/api/APIServer.kt b/node/src/main/kotlin/com/r3corda/node/api/APIServer.kt index 7e3979c16a..9883faab5f 100644 --- a/node/src/main/kotlin/com/r3corda/node/api/APIServer.kt +++ b/node/src/main/kotlin/com/r3corda/node/api/APIServer.kt @@ -11,6 +11,7 @@ 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. @@ -30,6 +31,14 @@ interface APIServer { @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 + /** * 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 diff --git a/node/src/main/kotlin/com/r3corda/node/internal/APIServerImpl.kt b/node/src/main/kotlin/com/r3corda/node/internal/APIServerImpl.kt index 4a8fd1f038..6f4eae6e6c 100644 --- a/node/src/main/kotlin/com/r3corda/node/internal/APIServerImpl.kt +++ b/node/src/main/kotlin/com/r3corda/node/internal/APIServerImpl.kt @@ -10,6 +10,7 @@ import com.r3corda.core.serialization.SerializedBytes import com.r3corda.node.api.* import java.time.LocalDateTime import java.util.* +import javax.ws.rs.core.Response import kotlin.reflect.KParameter import kotlin.reflect.jvm.javaType @@ -17,6 +18,14 @@ 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 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 From 9638ea5b9e29bd277e4bd5649241dfd0c0237ee4 Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Thu, 9 Jun 2016 17:47:58 +0100 Subject: [PATCH 032/114] IRS demo test now uses the new status endpoint --- .../com/r3corda/core/testing/IRSDemoTest.kt | 40 +++++++++++++++++-- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt b/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt index e7812cd784..c0e45c3bc0 100644 --- a/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt +++ b/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt @@ -2,9 +2,17 @@ package com.r3corda.core.testing import kotlin.test.assertEquals import org.junit.Test +import java.io.InputStreamReader +import java.net.ConnectException +import java.net.HttpURLConnection +import java.net.URL import java.nio.file.Path import java.nio.file.Paths +private class NodeDidNotStartException: Throwable { + constructor(message: String): super(message) {} +} + class IRSDemoTest { @Test fun `runs IRS demo`() { val dirA = Paths.get("./nodeA") @@ -14,8 +22,8 @@ class IRSDemoTest { try { setupNode(dirA, "NodeA") setupNode(dirB, "NodeB") - procA = startNode(dirA, "NodeA") - procB = startNode(dirB, "NodeB") + procA = startNode(dirA, "NodeA", "http://localhost:31338") + procB = startNode(dirB, "NodeB", "http://localhost:31341") runTrade() runDateChange() } finally { @@ -33,13 +41,37 @@ private fun setupNode(dir: Path, nodeType: String) { assertEquals(proc.exitValue(), 0) } -private fun startNode(dir: Path, nodeType: String): Process { +private fun startNode(dir: Path, nodeType: String, nodeAddr: String): Process { val args = listOf("--role", nodeType, "--dir", dir.toString()) val proc = spawn("com.r3corda.demos.IRSDemoKt", args) - Thread.sleep(15000) + waitForNode(nodeAddr) return proc } +// Todo: Move this to a library and use it in the trade demo +private fun waitForNode(nodeAddr: String) { + var retries = 0 + var respCode: Int = 404 + do { + retries++ + val url = URL(nodeAddr + "/api/status") + val err = try { + val conn = url.openConnection() as HttpURLConnection + conn.requestMethod = "GET" + respCode = conn.responseCode + InputStreamReader(conn.inputStream).readLines().joinToString { it } + } catch(e: ConnectException) { + // This is to be expected while it loads up + respCode = 404 + "Node hasn't started" + } + + if(retries > 200) { + throw NodeDidNotStartException("The node did not start: " + err) + } + } while (respCode != 200) +} + private fun runTrade() { val args = listOf("--role", "Trade", "trade1") val proc = spawn("com.r3corda.demos.IRSDemoKt", args) From 9973f8a33e9e4ade7d6e488f679c83b04f8d01aa Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Fri, 10 Jun 2016 09:48:48 +0100 Subject: [PATCH 033/114] Moved integration test utilities into a utility folder. --- .../com/r3corda/core/testing/IRSDemoTest.kt | 36 ++----------------- .../r3corda/core/testing/TraderDemoTest.kt | 4 ++- .../testing/{ => utilities}/JVMSpawner.kt | 2 +- .../r3corda/core/testing/utilities/NodeApi.kt | 33 +++++++++++++++++ 4 files changed, 40 insertions(+), 35 deletions(-) rename src/integration-test/kotlin/com/r3corda/core/testing/{ => utilities}/JVMSpawner.kt (93%) create mode 100644 src/integration-test/kotlin/com/r3corda/core/testing/utilities/NodeApi.kt diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt b/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt index c0e45c3bc0..e55ffc01b2 100644 --- a/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt +++ b/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt @@ -1,18 +1,12 @@ package com.r3corda.core.testing +import com.r3corda.core.testing.utilities.spawn +import com.r3corda.core.testing.utilities.waitForNodeStartup import kotlin.test.assertEquals import org.junit.Test -import java.io.InputStreamReader -import java.net.ConnectException -import java.net.HttpURLConnection -import java.net.URL import java.nio.file.Path import java.nio.file.Paths -private class NodeDidNotStartException: Throwable { - constructor(message: String): super(message) {} -} - class IRSDemoTest { @Test fun `runs IRS demo`() { val dirA = Paths.get("./nodeA") @@ -44,34 +38,10 @@ private fun setupNode(dir: Path, nodeType: String) { private fun startNode(dir: Path, nodeType: String, nodeAddr: String): Process { val args = listOf("--role", nodeType, "--dir", dir.toString()) val proc = spawn("com.r3corda.demos.IRSDemoKt", args) - waitForNode(nodeAddr) + waitForNodeStartup(nodeAddr) return proc } -// Todo: Move this to a library and use it in the trade demo -private fun waitForNode(nodeAddr: String) { - var retries = 0 - var respCode: Int = 404 - do { - retries++ - val url = URL(nodeAddr + "/api/status") - val err = try { - val conn = url.openConnection() as HttpURLConnection - conn.requestMethod = "GET" - respCode = conn.responseCode - InputStreamReader(conn.inputStream).readLines().joinToString { it } - } catch(e: ConnectException) { - // This is to be expected while it loads up - respCode = 404 - "Node hasn't started" - } - - if(retries > 200) { - throw NodeDidNotStartException("The node did not start: " + err) - } - } while (respCode != 200) -} - private fun runTrade() { val args = listOf("--role", "Trade", "trade1") val proc = spawn("com.r3corda.demos.IRSDemoKt", args) diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt b/src/integration-test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt index 576ab9d0be..d74c97532c 100644 --- a/src/integration-test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt +++ b/src/integration-test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt @@ -1,5 +1,7 @@ package com.r3corda.core.testing +import com.r3corda.core.testing.utilities.spawn +import com.r3corda.core.testing.utilities.waitForNodeStartup import org.junit.Test import java.nio.file.Paths import kotlin.test.assertEquals @@ -20,7 +22,7 @@ class TraderDemoTest { private fun runBuyer(): Process { val args = listOf("--role", "BUYER") val proc = spawn("com.r3corda.demos.TraderDemoKt", args) - Thread.sleep(15000) + waitForNodeStartup("http://localhost:31338") return proc } diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/JVMSpawner.kt b/src/integration-test/kotlin/com/r3corda/core/testing/utilities/JVMSpawner.kt similarity index 93% rename from src/integration-test/kotlin/com/r3corda/core/testing/JVMSpawner.kt rename to src/integration-test/kotlin/com/r3corda/core/testing/utilities/JVMSpawner.kt index 7ddf11a160..f88d55131b 100644 --- a/src/integration-test/kotlin/com/r3corda/core/testing/JVMSpawner.kt +++ b/src/integration-test/kotlin/com/r3corda/core/testing/utilities/JVMSpawner.kt @@ -1,4 +1,4 @@ -package com.r3corda.core.testing +package com.r3corda.core.testing.utilities import java.nio.file.Paths diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/utilities/NodeApi.kt b/src/integration-test/kotlin/com/r3corda/core/testing/utilities/NodeApi.kt new file mode 100644 index 0000000000..95ef74c27c --- /dev/null +++ b/src/integration-test/kotlin/com/r3corda/core/testing/utilities/NodeApi.kt @@ -0,0 +1,33 @@ +package com.r3corda.core.testing.utilities + +import java.io.InputStreamReader +import java.net.ConnectException +import java.net.HttpURLConnection +import java.net.URL + +class NodeDidNotStartException: Throwable { + constructor(message: String): super(message) {} +} + +fun waitForNodeStartup(nodeAddr: String) { + var retries = 0 + var respCode: Int + do { + retries++ + val url = URL(nodeAddr + "/api/status") + val err = try { + val conn = url.openConnection() as HttpURLConnection + conn.requestMethod = "GET" + respCode = conn.responseCode + InputStreamReader(conn.inputStream).readLines().joinToString { it } + } catch(e: ConnectException) { + // This is to be expected while it loads up + respCode = 404 + "Node hasn't started" + } + + if(retries > 200) { + throw NodeDidNotStartException("The node did not start: " + err) + } + } while (respCode != 200) +} \ No newline at end of file From 5a4215a31240540fe680c307d6cd0da47a37bcb4 Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Fri, 10 Jun 2016 10:00:29 +0100 Subject: [PATCH 034/114] Fixed a change resulting from an incorrect merge. --- src/main/resources/com/r3corda/demos/example-irs-trade.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/com/r3corda/demos/example-irs-trade.json b/src/main/resources/com/r3corda/demos/example-irs-trade.json index 5c602e3bbd..19cc8e8951 100644 --- a/src/main/resources/com/r3corda/demos/example-irs-trade.json +++ b/src/main/resources/com/r3corda/demos/example-irs-trade.json @@ -96,7 +96,7 @@ "addressForTransfers": "", "exposure": {}, "localBusinessDay": [ "London" , "NewYork" ], - "dailyInterestAmount": "(CashAmount * InterestRate ) / (fixedLeg.notional.currency.currencyCode.equals('GBP')) ? 365 : 360", + "dailyInterestAmount": "(CashAmount * InterestRate ) / (fixedLeg.notional.token.currencyCode.equals('GBP')) ? 365 : 360", "tradeID": "tradeXXX", "hashLegalDocs": "put hash here" } From 7a4a1363cbdf13a5f3993bdff3e5c4a84b13f584 Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Fri, 10 Jun 2016 11:38:14 +0100 Subject: [PATCH 035/114] Removed unnecessary changes. --- .../main/kotlin/com/r3corda/node/internal/Node.kt | 2 +- src/main/kotlin/com/r3corda/demos/TraderDemo.kt | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/node/src/main/kotlin/com/r3corda/node/internal/Node.kt b/node/src/main/kotlin/com/r3corda/node/internal/Node.kt index f78fa99c71..6c3ddbdda4 100644 --- a/node/src/main/kotlin/com/r3corda/node/internal/Node.kt +++ b/node/src/main/kotlin/com/r3corda/node/internal/Node.kt @@ -52,7 +52,7 @@ class ConfigurationException(message: String) : Exception(message) * Listed clientAPI classes are assumed to have to take a single APIServer constructor parameter * @param clock The clock used within the node and by all protocols etc */ -open class Node(dir: Path, val p2pAddr: HostAndPort, configuration: NodeConfiguration, +class Node(dir: Path, val p2pAddr: HostAndPort, configuration: NodeConfiguration, networkMapAddress: NodeInfo?, advertisedServices: Set, clock: Clock = NodeClock(), val clientAPIs: List> = listOf()) : AbstractNode(dir, configuration, networkMapAddress, advertisedServices, clock) { diff --git a/src/main/kotlin/com/r3corda/demos/TraderDemo.kt b/src/main/kotlin/com/r3corda/demos/TraderDemo.kt index 8967f1f459..6bf3d06996 100644 --- a/src/main/kotlin/com/r3corda/demos/TraderDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/TraderDemo.kt @@ -31,7 +31,6 @@ import com.r3corda.protocols.NotaryProtocol import com.r3corda.protocols.TwoPartyTradeProtocol import com.typesafe.config.ConfigFactory import joptsimple.OptionParser -import java.io.Serializable import java.nio.file.Files import java.nio.file.Path import java.nio.file.Paths @@ -62,7 +61,6 @@ enum class Role { BUYER, SELLER } -} // And this is the directory under the current working directory where each node will create its own server directory, // which holds things like checkpoints, keys, databases, message logs etc. @@ -145,7 +143,9 @@ fun runTraderDemo(args: Array): Int { NodeInfo(ArtemisMessagingService.makeRecipient(theirNetAddr), party, setOf(NetworkMapService.Type)) } // And now construct then start the node object. It takes a little while. - val node = logElapsedTime("Node startup") { Node(directory, myNetAddr, config, networkMapId, advertisedServices).setup().start() } + val node = logElapsedTime("Node startup") { + Node(directory, myNetAddr, config, networkMapId, advertisedServices).setup().start() + } // What happens next depends on the role. The buyer sits around waiting for a trade to start. The seller role // will contact the buyer and actually make something happen. @@ -160,7 +160,7 @@ fun runTraderDemo(args: Array): Int { return 0 } -private fun runSeller(myAddr: HostAndPort, node: Node, recipient: SingleMessageRecipient) { +private fun runSeller(myNetAddr: HostAndPort, node: Node, recipient: SingleMessageRecipient) { // The seller will sell some commercial paper to the buyer, who will pay with (self issued) cash. // // The CP sale transaction comes with a prospectus PDF, which will tag along for the ride in an @@ -288,7 +288,7 @@ ${Emoji.renderIfSupported(cpIssuance)}""") } } -private class TraderDemoProtocolSeller(val myAddr: HostAndPort, +private class TraderDemoProtocolSeller(val myAddress: HostAndPort, val otherSide: SingleMessageRecipient, val amount: Amount>, override val progressTracker: ProgressTracker = TraderDemoProtocolSeller.tracker()) : ProtocolLogic() { @@ -313,7 +313,7 @@ private class TraderDemoProtocolSeller(val myAddr: HostAndPort, override fun call() { progressTracker.currentStep = ANNOUNCING - val sessionID = sendAndReceive(DEMO_TOPIC, otherSide, 0, 0, myAddr).validate { it } + val sessionID = sendAndReceive(DEMO_TOPIC, otherSide, 0, 0, myAddress).validate { it } progressTracker.currentStep = SELF_ISSUING From 609d80e63096abd3e30a91f9a8c6e99885698175 Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Tue, 14 Jun 2016 00:33:31 +0100 Subject: [PATCH 036/114] Integration test module set correctly. --- .idea/modules.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/.idea/modules.xml b/.idea/modules.xml index 327bffd348..8a1bd10f31 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -21,6 +21,7 @@ + From 21dc8e7fd4d7d862cc5ba1342003e51e241570db Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Tue, 14 Jun 2016 11:18:11 +0100 Subject: [PATCH 037/114] Increased timeout time for reads during HTTP connections to avoid demo failing when date it set far in the future. --- src/main/kotlin/com/r3corda/demos/IRSDemo.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt index 26a69eb1c3..af485386df 100644 --- a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt @@ -346,7 +346,7 @@ private fun sendJson(url: URL, data: String, method: String) : Boolean { connection.useCaches = false connection.requestMethod = method connection.connectTimeout = 5000 - connection.readTimeout = 15000 + connection.readTimeout = 60000 connection.setRequestProperty("Connection", "Keep-Alive") connection.setRequestProperty("Cache-Control", "no-cache") connection.setRequestProperty("Content-Type", "application/json") @@ -391,7 +391,7 @@ private fun uploadFile(url: URL, file: String) : Boolean { connection.useCaches = false connection.requestMethod = "POST" connection.connectTimeout = 5000 - connection.readTimeout = 5000 + connection.readTimeout = 60000 connection.setRequestProperty("Connection", "Keep-Alive") connection.setRequestProperty("Cache-Control", "no-cache") connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary) From 9a2a7165a50dea0d100194e17b8132081f6b7b5f Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Fri, 17 Jun 2016 11:00:33 +0100 Subject: [PATCH 038/114] Fixed merge errors. --- src/main/kotlin/com/r3corda/demos/TraderDemo.kt | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/main/kotlin/com/r3corda/demos/TraderDemo.kt b/src/main/kotlin/com/r3corda/demos/TraderDemo.kt index 6bf3d06996..796f19f697 100644 --- a/src/main/kotlin/com/r3corda/demos/TraderDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/TraderDemo.kt @@ -160,7 +160,10 @@ fun runTraderDemo(args: Array): Int { return 0 } -private fun runSeller(myNetAddr: HostAndPort, node: Node, recipient: SingleMessageRecipient) { +private fun runSeller(myNetAddr: HostAndPort, + node: Node, + recipient: SingleMessageRecipient, + amount: Amount>) { // The seller will sell some commercial paper to the buyer, who will pay with (self issued) cash. // // The CP sale transaction comes with a prospectus PDF, which will tag along for the ride in an @@ -179,7 +182,7 @@ private fun runSeller(myNetAddr: HostAndPort, node: Node, recipient: SingleMessa it.second.get() } } else { - val seller = TraderDemoProtocolSeller(myAddr, recipient, amount) + val seller = TraderDemoProtocolSeller(myNetAddr, recipient, amount) node.smm.add("demo.seller", seller).get() } @@ -245,7 +248,7 @@ private class TraderDemoProtocolBuyer(private val attachmentsPath: Path, send(DEMO_TOPIC, recipient, 0, sessionID) val notary = serviceHub.networkMapCache.notaryNodes[0] - val buyer = TwoPartyTradeProtocol.Buyer(recipient, notary.identity, 1000.DOLLARS, + val buyer = TwoPartyTradeProtocol.Buyer(recipient, notary.identity, amount, CommercialPaper.State::class.java, sessionID) // This invokes the trading protocol and out pops our finished transaction. @@ -299,14 +302,14 @@ private class TraderDemoProtocolSeller(val myAddress: HostAndPort, object SELF_ISSUING : ProgressTracker.Step("Got session ID back, issuing and timestamping some commercial paper") - object TRADING : ProgressTracker.Step("Starting the trade protocol") + object TRADING : ProgressTracker.Step("Starting the trade protocol") { + override fun childProgressTracker(): ProgressTracker = TwoPartyTradeProtocol.Seller.tracker() + } // We vend a progress tracker that already knows there's going to be a TwoPartyTradingProtocol involved at some // point: by setting up the tracker in advance, the user can see what's coming in more detail, instead of being // surprised when it appears as a new set of tasks below the current one. - fun tracker() = ProgressTracker(ANNOUNCING, SELF_ISSUING, TRADING).apply { - childrenFor[TRADING] = TwoPartyTradeProtocol.Seller.tracker() - } + fun tracker() = ProgressTracker(ANNOUNCING, SELF_ISSUING, TRADING) } @Suspendable From ad45b5deafa25468fb5936e5f96dc31d496bdd9a Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Fri, 17 Jun 2016 11:01:09 +0100 Subject: [PATCH 039/114] Tests now fail if spawned processes take too long to finish. --- .idea/modules.xml | 1 + .../kotlin/com/r3corda/core/testing/IRSDemoTest.kt | 7 ++++--- .../kotlin/com/r3corda/core/testing/TraderDemoTest.kt | 3 ++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.idea/modules.xml b/.idea/modules.xml index 8a1bd10f31..e38ea5ee5e 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -22,6 +22,7 @@ + diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt b/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt index e55ffc01b2..48ce8d1a1b 100644 --- a/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt +++ b/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt @@ -6,6 +6,7 @@ import kotlin.test.assertEquals import org.junit.Test import java.nio.file.Path import java.nio.file.Paths +import java.util.concurrent.TimeUnit class IRSDemoTest { @Test fun `runs IRS demo`() { @@ -31,7 +32,7 @@ class IRSDemoTest { private fun setupNode(dir: Path, nodeType: String) { val args = listOf("--role", "Setup" + nodeType, "--dir", dir.toString()) val proc = spawn("com.r3corda.demos.IRSDemoKt", args) - proc.waitFor(); + assertEquals(proc.waitFor(30, TimeUnit.SECONDS), true); assertEquals(proc.exitValue(), 0) } @@ -45,14 +46,14 @@ private fun startNode(dir: Path, nodeType: String, nodeAddr: String): Process { private fun runTrade() { val args = listOf("--role", "Trade", "trade1") val proc = spawn("com.r3corda.demos.IRSDemoKt", args) - proc.waitFor(); + assertEquals(proc.waitFor(30, TimeUnit.SECONDS), true); assertEquals(proc.exitValue(), 0) } private fun runDateChange() { val args = listOf("--role", "Date", "2017-01-02") val proc = spawn("com.r3corda.demos.IRSDemoKt", args) - proc.waitFor(); + assertEquals(proc.waitFor(30, TimeUnit.SECONDS), true); assertEquals(proc.exitValue(), 0) } diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt b/src/integration-test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt index d74c97532c..e9073d6c5f 100644 --- a/src/integration-test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt +++ b/src/integration-test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt @@ -4,6 +4,7 @@ import com.r3corda.core.testing.utilities.spawn import com.r3corda.core.testing.utilities.waitForNodeStartup import org.junit.Test import java.nio.file.Paths +import java.util.concurrent.TimeUnit import kotlin.test.assertEquals class TraderDemoTest { @@ -29,7 +30,7 @@ private fun runBuyer(): Process { private fun runSeller() { val args = listOf("--role", "SELLER") val proc = spawn("com.r3corda.demos.TraderDemoKt", args) - proc.waitFor(); + assertEquals(proc.waitFor(30, TimeUnit.SECONDS), true); assertEquals(proc.exitValue(), 0) } From 5858ff5c45ee4e3a0aa652354091e61c7dc9e168 Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Fri, 17 Jun 2016 11:38:13 +0100 Subject: [PATCH 040/114] Ensured that test passes under correct conditions, which may be slow, but also that the node lives until the end. --- .../kotlin/com/r3corda/core/testing/IRSDemoTest.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt b/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt index 48ce8d1a1b..a81a63a6f0 100644 --- a/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt +++ b/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt @@ -32,7 +32,7 @@ class IRSDemoTest { private fun setupNode(dir: Path, nodeType: String) { val args = listOf("--role", "Setup" + nodeType, "--dir", dir.toString()) val proc = spawn("com.r3corda.demos.IRSDemoKt", args) - assertEquals(proc.waitFor(30, TimeUnit.SECONDS), true); + assertEquals(proc.waitFor(2, TimeUnit.MINUTES), true); assertEquals(proc.exitValue(), 0) } @@ -46,18 +46,19 @@ private fun startNode(dir: Path, nodeType: String, nodeAddr: String): Process { private fun runTrade() { val args = listOf("--role", "Trade", "trade1") val proc = spawn("com.r3corda.demos.IRSDemoKt", args) - assertEquals(proc.waitFor(30, TimeUnit.SECONDS), true); + assertEquals(proc.waitFor(2, TimeUnit.MINUTES), true); assertEquals(proc.exitValue(), 0) } private fun runDateChange() { val args = listOf("--role", "Date", "2017-01-02") val proc = spawn("com.r3corda.demos.IRSDemoKt", args) - assertEquals(proc.waitFor(30, TimeUnit.SECONDS), true); + assertEquals(proc.waitFor(2, TimeUnit.MINUTES), true); assertEquals(proc.exitValue(), 0) } private fun stopNode(nodeProc: Process?) { + assertEquals(nodeProc?.isAlive, true) nodeProc?.destroy() } From 9d4f75f24171f240291c9af958210a865d7f5b14 Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Fri, 17 Jun 2016 11:44:40 +0100 Subject: [PATCH 041/114] Improved readability and brevity of hasEmojiTerminal. --- core/src/main/kotlin/com/r3corda/core/utilities/Emoji.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/kotlin/com/r3corda/core/utilities/Emoji.kt b/core/src/main/kotlin/com/r3corda/core/utilities/Emoji.kt index 7a8ce93e84..864cb4c044 100644 --- a/core/src/main/kotlin/com/r3corda/core/utilities/Emoji.kt +++ b/core/src/main/kotlin/com/r3corda/core/utilities/Emoji.kt @@ -4,7 +4,7 @@ package com.r3corda.core.utilities * A simple wrapper class that contains icons and support for printing them only when we're connected to a terminal. */ object Emoji { - val hasEmojiTerminal by lazy { System.getenv("TERM") != null && (System.getenv("LANG") != null) && System.getenv("LANG").contains("UTF-8") } + val hasEmojiTerminal by lazy { System.getenv("TERM") != null && (System.getenv("LANG")?.contains("UTF-8") == true) } const val CODE_DIAMOND = "\ud83d\udd37" const val CODE_BAG_OF_CASH = "\ud83d\udcb0" From 5bf5e37572aa7d643a0bc445762cac1d9cfc4a18 Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Fri, 17 Jun 2016 19:17:27 +0100 Subject: [PATCH 042/114] Demos now fully handle process managment except in the case where the process is killed with something like pkill or the JVM being ended by task manager. --- .idea/modules.xml | 1 - .../com/r3corda/core/testing/IRSDemoTest.kt | 17 ++++++++-------- .../r3corda/core/testing/TraderDemoTest.kt | 16 +++++++++------ .../core/testing/utilities/JVMSpawner.kt | 20 ++++++++++++++++++- .../r3corda/core/testing/utilities/NodeApi.kt | 17 +++++++++++++++- 5 files changed, 53 insertions(+), 18 deletions(-) diff --git a/.idea/modules.xml b/.idea/modules.xml index e38ea5ee5e..8a1bd10f31 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -22,7 +22,6 @@ - diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt b/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt index a81a63a6f0..2a0e485a7d 100644 --- a/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt +++ b/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt @@ -1,12 +1,10 @@ package com.r3corda.core.testing -import com.r3corda.core.testing.utilities.spawn -import com.r3corda.core.testing.utilities.waitForNodeStartup +import com.r3corda.core.testing.utilities.* import kotlin.test.assertEquals import org.junit.Test import java.nio.file.Path import java.nio.file.Paths -import java.util.concurrent.TimeUnit class IRSDemoTest { @Test fun `runs IRS demo`() { @@ -32,34 +30,35 @@ class IRSDemoTest { private fun setupNode(dir: Path, nodeType: String) { val args = listOf("--role", "Setup" + nodeType, "--dir", dir.toString()) val proc = spawn("com.r3corda.demos.IRSDemoKt", args) - assertEquals(proc.waitFor(2, TimeUnit.MINUTES), true); + assertExitOrKill(proc) assertEquals(proc.exitValue(), 0) } private fun startNode(dir: Path, nodeType: String, nodeAddr: String): Process { val args = listOf("--role", nodeType, "--dir", dir.toString()) val proc = spawn("com.r3corda.demos.IRSDemoKt", args) - waitForNodeStartup(nodeAddr) + ensureNodeStartsOrKill(proc, nodeAddr) return proc } private fun runTrade() { val args = listOf("--role", "Trade", "trade1") val proc = spawn("com.r3corda.demos.IRSDemoKt", args) - assertEquals(proc.waitFor(2, TimeUnit.MINUTES), true); + assertExitOrKill(proc) assertEquals(proc.exitValue(), 0) } private fun runDateChange() { val args = listOf("--role", "Date", "2017-01-02") val proc = spawn("com.r3corda.demos.IRSDemoKt", args) - assertEquals(proc.waitFor(2, TimeUnit.MINUTES), true); + assertExitOrKill(proc) assertEquals(proc.exitValue(), 0) } private fun stopNode(nodeProc: Process?) { - assertEquals(nodeProc?.isAlive, true) - nodeProc?.destroy() + if(nodeProc != null) { + assertAliveAndKill(nodeProc) + } } private fun cleanup(dir: Path) { diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt b/src/integration-test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt index e9073d6c5f..2e492f5fd3 100644 --- a/src/integration-test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt +++ b/src/integration-test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt @@ -1,40 +1,44 @@ package com.r3corda.core.testing +import com.r3corda.core.testing.utilities.assertExitOrKill +import com.r3corda.core.testing.utilities.ensureNodeStartsOrKill import com.r3corda.core.testing.utilities.spawn -import com.r3corda.core.testing.utilities.waitForNodeStartup import org.junit.Test import java.nio.file.Paths -import java.util.concurrent.TimeUnit import kotlin.test.assertEquals class TraderDemoTest { @Test fun `runs trader demo`() { var nodeProc: Process? = null try { + cleanupFiles() nodeProc = runBuyer() runSeller() } finally { nodeProc?.destroy() - cleanup() + cleanupFiles() } } } private fun runBuyer(): Process { + println("Running Buyer") val args = listOf("--role", "BUYER") val proc = spawn("com.r3corda.demos.TraderDemoKt", args) - waitForNodeStartup("http://localhost:31338") + ensureNodeStartsOrKill(proc, "http://localhost:31338") return proc } private fun runSeller() { + println("Running Seller") val args = listOf("--role", "SELLER") val proc = spawn("com.r3corda.demos.TraderDemoKt", args) - assertEquals(proc.waitFor(30, TimeUnit.SECONDS), true); + assertExitOrKill(proc); assertEquals(proc.exitValue(), 0) } -private fun cleanup() { +private fun cleanupFiles() { + println("Cleaning up TraderDemoTest files") val dir = Paths.get("trader-demo") println("Erasing " + dir) dir.toFile().deleteRecursively() diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/utilities/JVMSpawner.kt b/src/integration-test/kotlin/com/r3corda/core/testing/utilities/JVMSpawner.kt index f88d55131b..b1495e3512 100644 --- a/src/integration-test/kotlin/com/r3corda/core/testing/utilities/JVMSpawner.kt +++ b/src/integration-test/kotlin/com/r3corda/core/testing/utilities/JVMSpawner.kt @@ -1,6 +1,8 @@ package com.r3corda.core.testing.utilities import java.nio.file.Paths +import java.util.concurrent.TimeUnit +import kotlin.test.assertEquals fun spawn(className: String, args: List): Process { val separator = System.getProperty("file.separator") @@ -9,7 +11,23 @@ fun spawn(className: String, args: List): Process { val javaArgs = listOf(path, "-javaagent:lib/quasar.jar", "-cp", classpath, className) val builder = ProcessBuilder(javaArgs + args) builder.redirectError(Paths.get("error.$className.log").toFile()) - builder.inheritIO() val process = builder.start(); return process } + +fun assertExitOrKill(proc: Process) { + try { + assertEquals(proc.waitFor(2, TimeUnit.MINUTES), true) + } catch (e: Throwable) { + proc.destroy() + throw e + } +} + +fun assertAliveAndKill(proc: Process) { + try { + assertEquals(proc.isAlive, true) + } finally { + proc.destroy() + } +} \ No newline at end of file diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/utilities/NodeApi.kt b/src/integration-test/kotlin/com/r3corda/core/testing/utilities/NodeApi.kt index 95ef74c27c..e206bb25bb 100644 --- a/src/integration-test/kotlin/com/r3corda/core/testing/utilities/NodeApi.kt +++ b/src/integration-test/kotlin/com/r3corda/core/testing/utilities/NodeApi.kt @@ -2,14 +2,26 @@ package com.r3corda.core.testing.utilities import java.io.InputStreamReader import java.net.ConnectException +import java.net.SocketException import java.net.HttpURLConnection import java.net.URL +import kotlin.test.assertEquals class NodeDidNotStartException: Throwable { constructor(message: String): super(message) {} } -fun waitForNodeStartup(nodeAddr: String) { +fun ensureNodeStartsOrKill(proc: Process, nodeAddr: String) { + try { + assertEquals(proc.isAlive, true) + waitForNodeStartup(nodeAddr) + } catch (e: Exception) { + proc.destroy() + throw e + } +} + +private fun waitForNodeStartup(nodeAddr: String) { var retries = 0 var respCode: Int do { @@ -24,6 +36,9 @@ fun waitForNodeStartup(nodeAddr: String) { // This is to be expected while it loads up respCode = 404 "Node hasn't started" + } catch(e: SocketException) { + respCode = -1 + "Could not connect: ${e.toString()}" } if(retries > 200) { From 68867d21bb81fa585fb14502b012d29209f3aedf Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Tue, 21 Jun 2016 14:56:37 +0100 Subject: [PATCH 043/114] Fixed merge conflict problems. --- src/main/kotlin/com/r3corda/demos/TraderDemo.kt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/com/r3corda/demos/TraderDemo.kt b/src/main/kotlin/com/r3corda/demos/TraderDemo.kt index 796f19f697..ec93fe7780 100644 --- a/src/main/kotlin/com/r3corda/demos/TraderDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/TraderDemo.kt @@ -72,8 +72,6 @@ fun main(args: Array) { fun runTraderDemo(args: Array): Int { val cashIssuerKey = generateKeyPair() - val cashIssuer = Party("Trusted cash issuer", cashIssuerKey.public) - val amount = 1000.DOLLARS `issued by` cashIssuer.ref(1) val parser = OptionParser() val roleArg = parser.accepts("role").withRequiredArg().ofType(Role::class.java).required() @@ -142,11 +140,17 @@ fun runTraderDemo(args: Array): Int { cashIssuer = party NodeInfo(ArtemisMessagingService.makeRecipient(theirNetAddr), party, setOf(NetworkMapService.Type)) } + // And now construct then start the node object. It takes a little while. val node = logElapsedTime("Node startup") { Node(directory, myNetAddr, config, networkMapId, advertisedServices).setup().start() } + // TODO: Replace with a separate trusted cash issuer + if (cashIssuer == null) { + cashIssuer = node.services.storageService.myLegalIdentity + } + // What happens next depends on the role. The buyer sits around waiting for a trade to start. The seller role // will contact the buyer and actually make something happen. val amount = 1000.DOLLARS `issued by` cashIssuer.ref(0) // Note: "0" has to match the reference used in the wallet filler @@ -367,7 +371,7 @@ private class TraderDemoProtocolSeller(val myAddress: HostAndPort, // Now make a dummy transaction that moves it to a new key, just to show that resolving dependencies works. val move: SignedTransaction = run { - val builder = TransactionBuilder() + val builder = TransactionType.General.Builder() CommercialPaper().generateMove(builder, issuance.tx.outRef(0), ownedBy) builder.signWith(keyPair) val notarySignature = subProtocol(NotaryProtocol.Client(builder.toSignedTransaction(false))) From b52f344eb3cb1ed9ba413efb7f2e4eb93f77e33c Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Tue, 21 Jun 2016 16:48:43 +0100 Subject: [PATCH 044/114] Ensured that nodes are killed by process.destroyForcibly. Added random port numbers to test. --- .../com/r3corda/core/testing/IRSDemoTest.kt | 29 ++++++++++++------- .../r3corda/core/testing/TraderDemoTest.kt | 2 +- .../core/testing/utilities/JVMSpawner.kt | 5 ++-- .../r3corda/core/testing/utilities/NodeApi.kt | 16 ++++++---- 4 files changed, 34 insertions(+), 18 deletions(-) diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt b/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt index 2a0e485a7d..229d74e406 100644 --- a/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt +++ b/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt @@ -1,5 +1,6 @@ package com.r3corda.core.testing +import com.google.common.net.HostAndPort import com.r3corda.core.testing.utilities.* import kotlin.test.assertEquals import org.junit.Test @@ -8,6 +9,8 @@ import java.nio.file.Paths class IRSDemoTest { @Test fun `runs IRS demo`() { + val nodeAddrA = freeLocalHostAndPort() + val apiAddrA = HostAndPort.fromString("${nodeAddrA.hostText}:${nodeAddrA.port + 1}") val dirA = Paths.get("./nodeA") val dirB = Paths.get("./nodeB") var procA: Process? = null @@ -15,10 +18,10 @@ class IRSDemoTest { try { setupNode(dirA, "NodeA") setupNode(dirB, "NodeB") - procA = startNode(dirA, "NodeA", "http://localhost:31338") - procB = startNode(dirB, "NodeB", "http://localhost:31341") - runTrade() - runDateChange() + procA = startNode(dirA, "NodeA", nodeAddrA) + procB = startNode(dirB, "NodeB", freeLocalHostAndPort()) + runTrade(apiAddrA) + runDateChange(apiAddrA) } finally { stopNode(procA) stopNode(procB) @@ -28,28 +31,33 @@ class IRSDemoTest { } } private fun setupNode(dir: Path, nodeType: String) { + println("Running setup for $nodeType") val args = listOf("--role", "Setup" + nodeType, "--dir", dir.toString()) val proc = spawn("com.r3corda.demos.IRSDemoKt", args) assertExitOrKill(proc) assertEquals(proc.exitValue(), 0) } -private fun startNode(dir: Path, nodeType: String, nodeAddr: String): Process { - val args = listOf("--role", nodeType, "--dir", dir.toString()) +private fun startNode(dir: Path, nodeType: String, nodeAddr: HostAndPort): Process { + println("Running node $nodeType") + println("Node addr: ${nodeAddr.toString()}") + val args = listOf("--role", nodeType, "--dir", dir.toString(), "--network-address", nodeAddr.toString()) val proc = spawn("com.r3corda.demos.IRSDemoKt", args) ensureNodeStartsOrKill(proc, nodeAddr) return proc } -private fun runTrade() { - val args = listOf("--role", "Trade", "trade1") +private fun runTrade(nodeAddr: HostAndPort) { + println("Running trade") + val args = listOf("--role", "Trade", "trade1", "--network-address", "http://" + nodeAddr.toString()) val proc = spawn("com.r3corda.demos.IRSDemoKt", args) assertExitOrKill(proc) assertEquals(proc.exitValue(), 0) } -private fun runDateChange() { - val args = listOf("--role", "Date", "2017-01-02") +private fun runDateChange(nodeAddr: HostAndPort) { + println("Running date change") + val args = listOf("--role", "Date", "2017-01-02", "--network-address", "http://" + nodeAddr.toString()) val proc = spawn("com.r3corda.demos.IRSDemoKt", args) assertExitOrKill(proc) assertEquals(proc.exitValue(), 0) @@ -57,6 +65,7 @@ private fun runDateChange() { private fun stopNode(nodeProc: Process?) { if(nodeProc != null) { + println("Stopping node") assertAliveAndKill(nodeProc) } } diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt b/src/integration-test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt index 2e492f5fd3..62ab740729 100644 --- a/src/integration-test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt +++ b/src/integration-test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt @@ -25,7 +25,7 @@ private fun runBuyer(): Process { println("Running Buyer") val args = listOf("--role", "BUYER") val proc = spawn("com.r3corda.demos.TraderDemoKt", args) - ensureNodeStartsOrKill(proc, "http://localhost:31338") + ensureNodeStartsOrKill(proc, freeLocalHostAndPort()) return proc } diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/utilities/JVMSpawner.kt b/src/integration-test/kotlin/com/r3corda/core/testing/utilities/JVMSpawner.kt index b1495e3512..bfc7b3f8f2 100644 --- a/src/integration-test/kotlin/com/r3corda/core/testing/utilities/JVMSpawner.kt +++ b/src/integration-test/kotlin/com/r3corda/core/testing/utilities/JVMSpawner.kt @@ -11,6 +11,7 @@ fun spawn(className: String, args: List): Process { val javaArgs = listOf(path, "-javaagent:lib/quasar.jar", "-cp", classpath, className) val builder = ProcessBuilder(javaArgs + args) builder.redirectError(Paths.get("error.$className.log").toFile()) + builder.inheritIO() val process = builder.start(); return process } @@ -19,7 +20,7 @@ fun assertExitOrKill(proc: Process) { try { assertEquals(proc.waitFor(2, TimeUnit.MINUTES), true) } catch (e: Throwable) { - proc.destroy() + proc.destroyForcibly() throw e } } @@ -28,6 +29,6 @@ fun assertAliveAndKill(proc: Process) { try { assertEquals(proc.isAlive, true) } finally { - proc.destroy() + proc.destroyForcibly() } } \ No newline at end of file diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/utilities/NodeApi.kt b/src/integration-test/kotlin/com/r3corda/core/testing/utilities/NodeApi.kt index e206bb25bb..f2739046dc 100644 --- a/src/integration-test/kotlin/com/r3corda/core/testing/utilities/NodeApi.kt +++ b/src/integration-test/kotlin/com/r3corda/core/testing/utilities/NodeApi.kt @@ -1,5 +1,7 @@ package com.r3corda.core.testing.utilities +import com.google.common.net.HostAndPort +import java.io.IOException import java.io.InputStreamReader import java.net.ConnectException import java.net.SocketException @@ -11,22 +13,23 @@ class NodeDidNotStartException: Throwable { constructor(message: String): super(message) {} } -fun ensureNodeStartsOrKill(proc: Process, nodeAddr: String) { +fun ensureNodeStartsOrKill(proc: Process, nodeAddr: HostAndPort) { try { assertEquals(proc.isAlive, true) waitForNodeStartup(nodeAddr) } catch (e: Exception) { - proc.destroy() + println("Forcibly killing node process") + proc.destroyForcibly() throw e } } -private fun waitForNodeStartup(nodeAddr: String) { +private fun waitForNodeStartup(nodeAddr: HostAndPort) { + val url = URL("http://${nodeAddr.hostText}:${nodeAddr.port + 1}/api/status") var retries = 0 var respCode: Int do { retries++ - val url = URL(nodeAddr + "/api/status") val err = try { val conn = url.openConnection() as HttpURLConnection conn.requestMethod = "GET" @@ -39,9 +42,12 @@ private fun waitForNodeStartup(nodeAddr: String) { } catch(e: SocketException) { respCode = -1 "Could not connect: ${e.toString()}" + } catch (e: IOException) { + respCode = -1 + "IOException: ${e.toString()}" } - if(retries > 200) { + if(retries > 50) { throw NodeDidNotStartException("The node did not start: " + err) } } while (respCode != 200) From 4900c7eb2688ae518b51b1570b7e4270bddd4a74 Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Tue, 21 Jun 2016 21:32:38 +0100 Subject: [PATCH 045/114] Ports now randomised during demo tests. --- .../com/r3corda/core/testing/IRSDemoTest.kt | 20 +++++++++------- .../r3corda/core/testing/TraderDemoTest.kt | 24 ++++++++++++------- .../core/testing/utilities/JVMSpawner.kt | 4 ++-- .../r3corda/core/testing/utilities/NodeApi.kt | 6 ++--- src/main/kotlin/com/r3corda/demos/IRSDemo.kt | 16 ++++++------- 5 files changed, 40 insertions(+), 30 deletions(-) diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt b/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt index 229d74e406..1dc4220e80 100644 --- a/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt +++ b/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt @@ -18,8 +18,8 @@ class IRSDemoTest { try { setupNode(dirA, "NodeA") setupNode(dirB, "NodeB") - procA = startNode(dirA, "NodeA", nodeAddrA) - procB = startNode(dirB, "NodeB", freeLocalHostAndPort()) + procA = startNode(dirA, "NodeA", nodeAddrA, nodeAddrA) + procB = startNode(dirB, "NodeB", freeLocalHostAndPort(), nodeAddrA) runTrade(apiAddrA) runDateChange(apiAddrA) } finally { @@ -33,16 +33,20 @@ class IRSDemoTest { private fun setupNode(dir: Path, nodeType: String) { println("Running setup for $nodeType") val args = listOf("--role", "Setup" + nodeType, "--dir", dir.toString()) - val proc = spawn("com.r3corda.demos.IRSDemoKt", args) + val proc = spawn("com.r3corda.demos.IRSDemoKt", args, "IRSDemoSetup$nodeType") assertExitOrKill(proc) assertEquals(proc.exitValue(), 0) } -private fun startNode(dir: Path, nodeType: String, nodeAddr: HostAndPort): Process { +private fun startNode(dir: Path, nodeType: String, nodeAddr: HostAndPort, networkMapAddr: HostAndPort): Process { println("Running node $nodeType") println("Node addr: ${nodeAddr.toString()}") - val args = listOf("--role", nodeType, "--dir", dir.toString(), "--network-address", nodeAddr.toString()) - val proc = spawn("com.r3corda.demos.IRSDemoKt", args) + val args = listOf( + "--role", nodeType, + "--dir", dir.toString(), + "--network-address", nodeAddr.toString(), + "--network-map-address", networkMapAddr.toString()) + val proc = spawn("com.r3corda.demos.IRSDemoKt", args, "IRSDemo$nodeType") ensureNodeStartsOrKill(proc, nodeAddr) return proc } @@ -50,7 +54,7 @@ private fun startNode(dir: Path, nodeType: String, nodeAddr: HostAndPort): Proce private fun runTrade(nodeAddr: HostAndPort) { println("Running trade") val args = listOf("--role", "Trade", "trade1", "--network-address", "http://" + nodeAddr.toString()) - val proc = spawn("com.r3corda.demos.IRSDemoKt", args) + val proc = spawn("com.r3corda.demos.IRSDemoKt", args, "IRSDemoTrade") assertExitOrKill(proc) assertEquals(proc.exitValue(), 0) } @@ -58,7 +62,7 @@ private fun runTrade(nodeAddr: HostAndPort) { private fun runDateChange(nodeAddr: HostAndPort) { println("Running date change") val args = listOf("--role", "Date", "2017-01-02", "--network-address", "http://" + nodeAddr.toString()) - val proc = spawn("com.r3corda.demos.IRSDemoKt", args) + val proc = spawn("com.r3corda.demos.IRSDemoKt", args, "IRSDemoDate") assertExitOrKill(proc) assertEquals(proc.exitValue(), 0) } diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt b/src/integration-test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt index 62ab740729..0dcb4c0793 100644 --- a/src/integration-test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt +++ b/src/integration-test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt @@ -1,5 +1,6 @@ package com.r3corda.core.testing +import com.google.common.net.HostAndPort import com.r3corda.core.testing.utilities.assertExitOrKill import com.r3corda.core.testing.utilities.ensureNodeStartsOrKill import com.r3corda.core.testing.utilities.spawn @@ -9,11 +10,12 @@ import kotlin.test.assertEquals class TraderDemoTest { @Test fun `runs trader demo`() { + val buyerAddr = freeLocalHostAndPort() var nodeProc: Process? = null try { cleanupFiles() - nodeProc = runBuyer() - runSeller() + nodeProc = runBuyer(buyerAddr) + runSeller(buyerAddr) } finally { nodeProc?.destroy() cleanupFiles() @@ -21,18 +23,22 @@ class TraderDemoTest { } } -private fun runBuyer(): Process { +private fun runBuyer(buyerAddr: HostAndPort): Process { println("Running Buyer") - val args = listOf("--role", "BUYER") - val proc = spawn("com.r3corda.demos.TraderDemoKt", args) - ensureNodeStartsOrKill(proc, freeLocalHostAndPort()) + val args = listOf("--role", "BUYER", "--network-address", buyerAddr.toString()) + val proc = spawn("com.r3corda.demos.TraderDemoKt", args, "TradeDemoBuyer") + ensureNodeStartsOrKill(proc, buyerAddr) return proc } -private fun runSeller() { +private fun runSeller(buyerAddr: HostAndPort) { println("Running Seller") - val args = listOf("--role", "SELLER") - val proc = spawn("com.r3corda.demos.TraderDemoKt", args) + val sellerAddr = freeLocalHostAndPort() + val args = listOf( + "--role", "SELLER", + "--network-address", sellerAddr.toString(), + "--other-network-address", buyerAddr.toString()) + val proc = spawn("com.r3corda.demos.TraderDemoKt", args, "TradeDemoSeller") assertExitOrKill(proc); assertEquals(proc.exitValue(), 0) } diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/utilities/JVMSpawner.kt b/src/integration-test/kotlin/com/r3corda/core/testing/utilities/JVMSpawner.kt index bfc7b3f8f2..5d7a063c1b 100644 --- a/src/integration-test/kotlin/com/r3corda/core/testing/utilities/JVMSpawner.kt +++ b/src/integration-test/kotlin/com/r3corda/core/testing/utilities/JVMSpawner.kt @@ -4,11 +4,11 @@ import java.nio.file.Paths import java.util.concurrent.TimeUnit import kotlin.test.assertEquals -fun spawn(className: String, args: List): Process { +fun spawn(className: String, args: List, appName: String): Process { val separator = System.getProperty("file.separator") val classpath = System.getProperty("java.class.path") val path = System.getProperty("java.home") + separator + "bin" + separator + "java" - val javaArgs = listOf(path, "-javaagent:lib/quasar.jar", "-cp", classpath, className) + val javaArgs = listOf(path, "-Dname=$appName", "-javaagent:lib/quasar.jar", "-cp", classpath, className) val builder = ProcessBuilder(javaArgs + args) builder.redirectError(Paths.get("error.$className.log").toFile()) builder.inheritIO() diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/utilities/NodeApi.kt b/src/integration-test/kotlin/com/r3corda/core/testing/utilities/NodeApi.kt index f2739046dc..f589da19a4 100644 --- a/src/integration-test/kotlin/com/r3corda/core/testing/utilities/NodeApi.kt +++ b/src/integration-test/kotlin/com/r3corda/core/testing/utilities/NodeApi.kt @@ -9,7 +9,7 @@ import java.net.HttpURLConnection import java.net.URL import kotlin.test.assertEquals -class NodeDidNotStartException: Throwable { +class NodeDidNotStartException: Exception { constructor(message: String): super(message) {} } @@ -17,7 +17,7 @@ fun ensureNodeStartsOrKill(proc: Process, nodeAddr: HostAndPort) { try { assertEquals(proc.isAlive, true) waitForNodeStartup(nodeAddr) - } catch (e: Exception) { + } catch (e: Throwable) { println("Forcibly killing node process") proc.destroyForcibly() throw e @@ -47,7 +47,7 @@ private fun waitForNodeStartup(nodeAddr: HostAndPort) { "IOException: ${e.toString()}" } - if(retries > 50) { + if(retries > 25) { throw NodeDidNotStartException("The node did not start: " + err) } } while (respCode != 200) diff --git a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt index af485386df..e8e983d166 100644 --- a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt @@ -61,7 +61,7 @@ enum class IRSDemoRole { private class NodeParams() { var dir : Path = Paths.get("") - var address : String = "" + var address : HostAndPort = HostAndPort.fromString("localhost").withDefaultPort(Node.DEFAULT_PORT) var mapAddress: String = "" var identityFile: Path = Paths.get("") var tradeWithAddrs: List = listOf() @@ -235,7 +235,7 @@ private fun configureNodeParams(role: IRSDemoRole, args: DemoArgs, options: Opti nodeParams.dir = Paths.get(options.valueOf(args.dirArg)) } if (options.has(args.networkAddressArg)) { - nodeParams.address = options.valueOf(args.networkAddressArg) + nodeParams.address = HostAndPort.fromString(options.valueOf(args.networkAddressArg)).withDefaultPort(Node.DEFAULT_PORT) } nodeParams.identityFile = if (options.has(args.networkMapIdentityFile)) { Paths.get(options.valueOf(args.networkMapIdentityFile)) @@ -265,7 +265,8 @@ private fun runNode(nodeParams: NodeParams) : Unit { ExitServerProtocol.Handler.register(node) if(nodeParams.uploadRates) { - runUploadRates("http://localhost:31341") + val apiAddr = "http://${nodeParams.address.hostText}:${nodeParams.address.port + 1}"; + runUploadRates(apiAddr) } try { @@ -283,8 +284,7 @@ private fun createRecipient(addr: String) : SingleMessageRecipient { private fun startNode(params : NodeParams, networkMap: SingleMessageRecipient, recipients: List) : Node { val config = getNodeConfig(params) val advertisedServices: Set - val myNetAddr = HostAndPort.fromString(params.address).withDefaultPort(Node.DEFAULT_PORT) - val networkMapId = if (params.mapAddress.equals(params.address)) { + val networkMapId = if (params.mapAddress.equals(params.address.toString())) { // This node provides network map and notary services advertisedServices = setOf(NetworkMapService.Type, SimpleNotaryService.Type) null @@ -293,7 +293,7 @@ private fun startNode(params : NodeParams, networkMap: SingleMessageRecipient, r nodeInfo(networkMap, params.identityFile, setOf(NetworkMapService.Type, SimpleNotaryService.Type)) } - val node = logElapsedTime("Node startup") { Node(params.dir, myNetAddr, config, networkMapId, + val node = logElapsedTime("Node startup") { Node(params.dir, params.address, config, networkMapId, advertisedServices, DemoClock(), listOf(InterestRateSwapAPI::class.java)).start() } @@ -415,7 +415,7 @@ private fun uploadFile(url: URL, file: String) : Boolean { private fun createNodeAParams() : NodeParams { val params = NodeParams() params.dir = Paths.get("nodeA") - params.address = "localhost" + params.address = HostAndPort.fromString("localhost") params.tradeWithAddrs = listOf("localhost:31340") params.tradeWithIdentities = listOf(getRoleDir(IRSDemoRole.NodeB).resolve(AbstractNode.PUBLIC_IDENTITY_FILE_NAME)) params.defaultLegalName = "Bank A" @@ -425,7 +425,7 @@ private fun createNodeAParams() : NodeParams { private fun createNodeBParams() : NodeParams { val params = NodeParams() params.dir = Paths.get("nodeB") - params.address = "localhost:31340" + params.address = HostAndPort.fromString("localhost:31340") params.tradeWithAddrs = listOf("localhost") params.tradeWithIdentities = listOf(getRoleDir(IRSDemoRole.NodeA).resolve(AbstractNode.PUBLIC_IDENTITY_FILE_NAME)) params.defaultLegalName = "Bank B" From ffa9ad1bc94c67dfddb572121bb742aace10956e Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Wed, 22 Jun 2016 16:21:44 +0100 Subject: [PATCH 046/114] Added port argument for IRS demo to allow web servers to not have binding collisions during testing and to allow more granular control over demos. --- .../kotlin/com/r3corda/node/internal/Node.kt | 12 +++++++--- .../com/r3corda/core/testing/IRSDemoTest.kt | 18 ++++++++++----- .../r3corda/core/testing/utilities/NodeApi.kt | 2 +- src/main/kotlin/com/r3corda/demos/IRSDemo.kt | 22 ++++++++++++++----- 4 files changed, 38 insertions(+), 16 deletions(-) diff --git a/node/src/main/kotlin/com/r3corda/node/internal/Node.kt b/node/src/main/kotlin/com/r3corda/node/internal/Node.kt index 6c3ddbdda4..e23436acbf 100644 --- a/node/src/main/kotlin/com/r3corda/node/internal/Node.kt +++ b/node/src/main/kotlin/com/r3corda/node/internal/Node.kt @@ -71,6 +71,9 @@ class Node(dir: Path, val p2pAddr: HostAndPort, configuration: NodeConfiguration // when our process shuts down, but we try in stop() anyway just to be nice. private var nodeFileLock: FileLock? = null + // Todo: Move to node config file + private var webServerPort: Int = p2pAddr.port + 1 + override fun makeMessagingService(): MessagingService = ArtemisMessagingService(dir, p2pAddr, serverThread) override fun startMessagingService() { @@ -78,11 +81,14 @@ class Node(dir: Path, val p2pAddr: HostAndPort, configuration: NodeConfiguration (net as ArtemisMessagingService).start() } + fun setWebServerPort(port: Int): Node { + webServerPort = port + return this + } + private fun initWebServer(): Server { // Note that the web server handlers will all run concurrently, and not on the node thread. - - val port = p2pAddr.port + 1 // TODO: Move this into the node config file. - val server = Server(port) + val server = Server(webServerPort) val handlerCollection = HandlerCollection() diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt b/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt index 1dc4220e80..57810c625d 100644 --- a/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt +++ b/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt @@ -10,7 +10,8 @@ import java.nio.file.Paths class IRSDemoTest { @Test fun `runs IRS demo`() { val nodeAddrA = freeLocalHostAndPort() - val apiAddrA = HostAndPort.fromString("${nodeAddrA.hostText}:${nodeAddrA.port + 1}") + val apiAddrA = freeLocalHostAndPort() + val apiAddrB = freeLocalHostAndPort() val dirA = Paths.get("./nodeA") val dirB = Paths.get("./nodeB") var procA: Process? = null @@ -18,8 +19,8 @@ class IRSDemoTest { try { setupNode(dirA, "NodeA") setupNode(dirB, "NodeB") - procA = startNode(dirA, "NodeA", nodeAddrA, nodeAddrA) - procB = startNode(dirB, "NodeB", freeLocalHostAndPort(), nodeAddrA) + procA = startNode(dirA, "NodeA", nodeAddrA, nodeAddrA, apiAddrA) + procB = startNode(dirB, "NodeB", freeLocalHostAndPort(), nodeAddrA, apiAddrB) runTrade(apiAddrA) runDateChange(apiAddrA) } finally { @@ -38,16 +39,21 @@ private fun setupNode(dir: Path, nodeType: String) { assertEquals(proc.exitValue(), 0) } -private fun startNode(dir: Path, nodeType: String, nodeAddr: HostAndPort, networkMapAddr: HostAndPort): Process { +private fun startNode(dir: Path, + nodeType: String, + nodeAddr: HostAndPort, + networkMapAddr: HostAndPort, + apiAddr: HostAndPort): Process { println("Running node $nodeType") println("Node addr: ${nodeAddr.toString()}") val args = listOf( "--role", nodeType, "--dir", dir.toString(), "--network-address", nodeAddr.toString(), - "--network-map-address", networkMapAddr.toString()) + "--network-map-address", networkMapAddr.toString(), + "--api-address", apiAddr.port.toString()) val proc = spawn("com.r3corda.demos.IRSDemoKt", args, "IRSDemo$nodeType") - ensureNodeStartsOrKill(proc, nodeAddr) + ensureNodeStartsOrKill(proc, apiAddr) return proc } diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/utilities/NodeApi.kt b/src/integration-test/kotlin/com/r3corda/core/testing/utilities/NodeApi.kt index f589da19a4..536acaf758 100644 --- a/src/integration-test/kotlin/com/r3corda/core/testing/utilities/NodeApi.kt +++ b/src/integration-test/kotlin/com/r3corda/core/testing/utilities/NodeApi.kt @@ -25,7 +25,7 @@ fun ensureNodeStartsOrKill(proc: Process, nodeAddr: HostAndPort) { } private fun waitForNodeStartup(nodeAddr: HostAndPort) { - val url = URL("http://${nodeAddr.hostText}:${nodeAddr.port + 1}/api/status") + val url = URL("http://${nodeAddr.toString()}/api/status") var retries = 0 var respCode: Int do { diff --git a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt index e8e983d166..84f37276ac 100644 --- a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt @@ -63,6 +63,7 @@ private class NodeParams() { var dir : Path = Paths.get("") var address : HostAndPort = HostAndPort.fromString("localhost").withDefaultPort(Node.DEFAULT_PORT) var mapAddress: String = "" + var apiPort : Int = Node.DEFAULT_PORT + 1 var identityFile: Path = Paths.get("") var tradeWithAddrs: List = listOf() var tradeWithIdentities: List = listOf() @@ -73,6 +74,7 @@ private class NodeParams() { private class DemoArgs() { lateinit var roleArg: OptionSpec lateinit var networkAddressArg: OptionSpec + lateinit var apiPort: OptionSpec lateinit var dirArg: OptionSpec lateinit var networkMapIdentityFile: OptionSpec lateinit var networkMapNetAddr: OptionSpec @@ -179,6 +181,7 @@ private fun setupArgs(parser: OptionParser): DemoArgs { args.roleArg = parser.accepts("role").withRequiredArg().ofType(IRSDemoRole::class.java).required() args.networkAddressArg = parser.accepts("network-address").withOptionalArg() + args.apiPort = parser.accepts("api-address").withOptionalArg().ofType(Int::class.java) args.dirArg = parser.accepts("directory").withOptionalArg() args.networkMapIdentityFile = parser.accepts("network-map-identity-file").withOptionalArg() args.networkMapNetAddr = parser.accepts("network-map-address").withRequiredArg().defaultsTo("localhost") @@ -237,6 +240,12 @@ private fun configureNodeParams(role: IRSDemoRole, args: DemoArgs, options: Opti if (options.has(args.networkAddressArg)) { nodeParams.address = HostAndPort.fromString(options.valueOf(args.networkAddressArg)).withDefaultPort(Node.DEFAULT_PORT) } + if(options.has(args.apiPort)) { + nodeParams.apiPort = options.valueOf(args.apiPort) + } else if(options.has(args.networkAddressArg)) { + nodeParams.apiPort = nodeParams.address.port + 1 + } + nodeParams.identityFile = if (options.has(args.networkMapIdentityFile)) { Paths.get(options.valueOf(args.networkMapIdentityFile)) } else { @@ -265,8 +274,7 @@ private fun runNode(nodeParams: NodeParams) : Unit { ExitServerProtocol.Handler.register(node) if(nodeParams.uploadRates) { - val apiAddr = "http://${nodeParams.address.hostText}:${nodeParams.address.port + 1}"; - runUploadRates(apiAddr) + runUploadRates(HostAndPort.fromString("localhost:${nodeParams.apiPort}")) } try { @@ -295,7 +303,7 @@ private fun startNode(params : NodeParams, networkMap: SingleMessageRecipient, r val node = logElapsedTime("Node startup") { Node(params.dir, params.address, config, networkMapId, advertisedServices, DemoClock(), - listOf(InterestRateSwapAPI::class.java)).start() } + listOf(InterestRateSwapAPI::class.java)).setWebServerPort(params.apiPort).start() } // TODO: This should all be replaced by the identity service being updated // as the network map changes. @@ -321,12 +329,12 @@ private fun nodeInfo(recipient: SingleMessageRecipient, identityFile: Path, adve } } -private fun runUploadRates(host: String) { +private fun runUploadRates(host: HostAndPort) { val fileContents = IOUtils.toString(NodeParams::class.java.getResource("example.rates.txt")) var timer : Timer? = null timer = fixedRateTimer("upload-rates", false, 0, 5000, { try { - val url = URL(host + "/upload/interest-rates") + val url = URL("http://${host.toString()}/upload/interest-rates") if(uploadFile(url, fileContents)) { timer!!.cancel() println("Rates uploaded successfully") @@ -415,7 +423,8 @@ private fun uploadFile(url: URL, file: String) : Boolean { private fun createNodeAParams() : NodeParams { val params = NodeParams() params.dir = Paths.get("nodeA") - params.address = HostAndPort.fromString("localhost") + params.address = HostAndPort.fromString("localhost").withDefaultPort(Node.DEFAULT_PORT) + params.apiPort = Node.DEFAULT_PORT + 1 params.tradeWithAddrs = listOf("localhost:31340") params.tradeWithIdentities = listOf(getRoleDir(IRSDemoRole.NodeB).resolve(AbstractNode.PUBLIC_IDENTITY_FILE_NAME)) params.defaultLegalName = "Bank A" @@ -426,6 +435,7 @@ private fun createNodeBParams() : NodeParams { val params = NodeParams() params.dir = Paths.get("nodeB") params.address = HostAndPort.fromString("localhost:31340") + params.apiPort = 31341 params.tradeWithAddrs = listOf("localhost") params.tradeWithIdentities = listOf(getRoleDir(IRSDemoRole.NodeA).resolve(AbstractNode.PUBLIC_IDENTITY_FILE_NAME)) params.defaultLegalName = "Bank B" From 429d8aab74dad9e938967ff9e8fa564b942aaa17 Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Mon, 27 Jun 2016 10:23:48 +0100 Subject: [PATCH 047/114] node, integtest: Code style --- .../r3corda/node/internal/APIServerImpl.kt | 2 +- .../kotlin/com/r3corda/node/internal/Node.kt | 2 +- .../node/servlets/DataUploadServlet.kt | 3 +-- .../com/r3corda/core/testing/IRSDemoTest.kt | 5 ++-- .../r3corda/core/testing/utilities/NodeApi.kt | 4 +-- src/main/kotlin/com/r3corda/demos/IRSDemo.kt | 26 +++++++++---------- 6 files changed, 21 insertions(+), 21 deletions(-) diff --git a/node/src/main/kotlin/com/r3corda/node/internal/APIServerImpl.kt b/node/src/main/kotlin/com/r3corda/node/internal/APIServerImpl.kt index 6f4eae6e6c..85cafc6692 100644 --- a/node/src/main/kotlin/com/r3corda/node/internal/APIServerImpl.kt +++ b/node/src/main/kotlin/com/r3corda/node/internal/APIServerImpl.kt @@ -19,7 +19,7 @@ class APIServerImpl(val node: AbstractNode) : APIServer { override fun serverTime(): LocalDateTime = LocalDateTime.now(node.services.clock) override fun status(): Response { - return if(node.started) { + return if (node.started) { Response.ok("started").build() } else { Response.status(Response.Status.SERVICE_UNAVAILABLE).entity("not started").build() diff --git a/node/src/main/kotlin/com/r3corda/node/internal/Node.kt b/node/src/main/kotlin/com/r3corda/node/internal/Node.kt index e23436acbf..3c444317c2 100644 --- a/node/src/main/kotlin/com/r3corda/node/internal/Node.kt +++ b/node/src/main/kotlin/com/r3corda/node/internal/Node.kt @@ -71,7 +71,7 @@ class Node(dir: Path, val p2pAddr: HostAndPort, configuration: NodeConfiguration // when our process shuts down, but we try in stop() anyway just to be nice. private var nodeFileLock: FileLock? = null - // Todo: Move to node config file + // TODO: Move to node config file private var webServerPort: Int = p2pAddr.port + 1 override fun makeMessagingService(): MessagingService = ArtemisMessagingService(dir, p2pAddr, serverThread) diff --git a/node/src/main/kotlin/com/r3corda/node/servlets/DataUploadServlet.kt b/node/src/main/kotlin/com/r3corda/node/servlets/DataUploadServlet.kt index 6a0944dd16..742061b22d 100644 --- a/node/src/main/kotlin/com/r3corda/node/servlets/DataUploadServlet.kt +++ b/node/src/main/kotlin/com/r3corda/node/servlets/DataUploadServlet.kt @@ -36,8 +36,7 @@ class DataUploadServlet : HttpServlet() { val iterator = upload.getItemIterator(req) val messages = ArrayList() - if(!iterator.hasNext()) - { + if (!iterator.hasNext()) { resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Got an upload request with no files") return } diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt b/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt index 57810c625d..9b7dbbd530 100644 --- a/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt +++ b/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt @@ -31,6 +31,7 @@ class IRSDemoTest { } } } + private fun setupNode(dir: Path, nodeType: String) { println("Running setup for $nodeType") val args = listOf("--role", "Setup" + nodeType, "--dir", dir.toString()) @@ -74,7 +75,7 @@ private fun runDateChange(nodeAddr: HostAndPort) { } private fun stopNode(nodeProc: Process?) { - if(nodeProc != null) { + if (nodeProc != null) { println("Stopping node") assertAliveAndKill(nodeProc) } @@ -83,4 +84,4 @@ private fun stopNode(nodeProc: Process?) { private fun cleanup(dir: Path) { println("Erasing: " + dir.toString()) dir.toFile().deleteRecursively() -} \ No newline at end of file +} diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/utilities/NodeApi.kt b/src/integration-test/kotlin/com/r3corda/core/testing/utilities/NodeApi.kt index 536acaf758..0f6d6239e7 100644 --- a/src/integration-test/kotlin/com/r3corda/core/testing/utilities/NodeApi.kt +++ b/src/integration-test/kotlin/com/r3corda/core/testing/utilities/NodeApi.kt @@ -47,8 +47,8 @@ private fun waitForNodeStartup(nodeAddr: HostAndPort) { "IOException: ${e.toString()}" } - if(retries > 25) { + if (retries > 25) { throw NodeDidNotStartException("The node did not start: " + err) } } while (respCode != 200) -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt index 84f37276ac..091837bf01 100644 --- a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt @@ -147,7 +147,7 @@ private fun runDateChange(demoArgs: DemoArgs, options: OptionSet): Int { "http://localhost:" + (Node.DEFAULT_PORT + 1) } - if(!changeDate(dateStr, host)) { + if (!changeDate(dateStr, host)) { return 1 } } else { @@ -161,7 +161,7 @@ private fun runDateChange(demoArgs: DemoArgs, options: OptionSet): Int { private fun runNode(role: IRSDemoRole, demoArgs: DemoArgs, options: OptionSet): Int { // If these directory and identity file arguments aren't specified then we can assume a default setup and // create everything that is needed without needing to run setup. - if(!options.has(demoArgs.dirArg) && !options.has(demoArgs.fakeTradeWithIdentityFile)) { + if (!options.has(demoArgs.dirArg) && !options.has(demoArgs.fakeTradeWithIdentityFile)) { createNodeConfig(createNodeAParams()); createNodeConfig(createNodeBParams()); } @@ -201,7 +201,7 @@ private fun setup(params: NodeParams): Int { private fun changeDate(date: String, host: String) : Boolean { println("Changing date to " + date) val url = URL(host + "/api/irs/demodate") - if(putJson(url, "\"" + date + "\"")) { + if (putJson(url, "\"" + date + "\"")) { println("Date changed") return true } else { @@ -215,7 +215,7 @@ private fun uploadTrade(tradeId: String, host: String) : Boolean { val fileContents = IOUtils.toString(NodeParams::class.java.getResourceAsStream("example-irs-trade.json")) val tradeFile = fileContents.replace("tradeXXX", tradeId) val url = URL(host + "/api/irs/deals") - if(postJson(url, tradeFile)) { + if (postJson(url, tradeFile)) { println("Trade sent") return true } else { @@ -240,9 +240,9 @@ private fun configureNodeParams(role: IRSDemoRole, args: DemoArgs, options: Opti if (options.has(args.networkAddressArg)) { nodeParams.address = HostAndPort.fromString(options.valueOf(args.networkAddressArg)).withDefaultPort(Node.DEFAULT_PORT) } - if(options.has(args.apiPort)) { + if (options.has(args.apiPort)) { nodeParams.apiPort = options.valueOf(args.apiPort) - } else if(options.has(args.networkAddressArg)) { + } else if (options.has(args.networkAddressArg)) { nodeParams.apiPort = nodeParams.address.port + 1 } @@ -261,7 +261,7 @@ private fun configureNodeParams(role: IRSDemoRole, args: DemoArgs, options: Opti return nodeParams } -private fun runNode(nodeParams: NodeParams) : Unit { +private fun runNode(nodeParams: NodeParams): Unit { val networkMap = createRecipient(nodeParams.mapAddress) val destinations = nodeParams.tradeWithAddrs.map({ createRecipient(it) @@ -273,7 +273,7 @@ private fun runNode(nodeParams: NodeParams) : Unit { UpdateBusinessDayProtocol.Handler.register(node) ExitServerProtocol.Handler.register(node) - if(nodeParams.uploadRates) { + if (nodeParams.uploadRates) { runUploadRates(HostAndPort.fromString("localhost:${nodeParams.apiPort}")) } @@ -335,7 +335,7 @@ private fun runUploadRates(host: HostAndPort) { timer = fixedRateTimer("upload-rates", false, 0, 5000, { try { val url = URL("http://${host.toString()}/upload/interest-rates") - if(uploadFile(url, fileContents)) { + if (uploadFile(url, fileContents)) { timer!!.cancel() println("Rates uploaded successfully") } else { @@ -450,7 +450,7 @@ private fun createNodeConfig(params: NodeParams) : NodeConfiguration { val configFile = params.dir.resolve("config").toFile() val config = loadConfigFile(configFile, params.defaultLegalName) - if(!Files.exists(params.dir.resolve(AbstractNode.PUBLIC_IDENTITY_FILE_NAME))) { + if (!Files.exists(params.dir.resolve(AbstractNode.PUBLIC_IDENTITY_FILE_NAME))) { createIdentities(params, config) } @@ -458,11 +458,11 @@ private fun createNodeConfig(params: NodeParams) : NodeConfiguration { } private fun getNodeConfig(params: NodeParams): NodeConfiguration { - if(!Files.exists(params.dir)) { + if (!Files.exists(params.dir)) { throw NotSetupException("Missing config directory. Please run node setup before running the node") } - if(!Files.exists(params.dir.resolve(AbstractNode.PUBLIC_IDENTITY_FILE_NAME))) { + if (!Files.exists(params.dir.resolve(AbstractNode.PUBLIC_IDENTITY_FILE_NAME))) { throw NotSetupException("Missing identity file. Please run node setup before running the node") } @@ -471,7 +471,7 @@ private fun getNodeConfig(params: NodeParams): NodeConfiguration { } private fun getRoleDir(role: IRSDemoRole) : Path { - when(role) { + when (role) { IRSDemoRole.NodeA -> return Paths.get("nodeA") IRSDemoRole.NodeB -> return Paths.get("nodeB") else -> { From e54dad9a8b90643c366f8ce26eb0e0f79327b0c6 Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Mon, 27 Jun 2016 14:10:30 +0100 Subject: [PATCH 048/114] node: Add apiAddress constructor parameter --- .../kotlin/com/r3corda/node/internal/Node.kt | 13 ++------- .../com/r3corda/core/testing/IRSDemoTest.kt | 2 +- .../r3corda/core/testing/TraderDemoTest.kt | 18 ++++++++---- src/main/kotlin/com/r3corda/demos/IRSDemo.kt | 29 ++++++++----------- .../kotlin/com/r3corda/demos/RateFixDemo.kt | 7 +++-- .../kotlin/com/r3corda/demos/TraderDemo.kt | 4 ++- 6 files changed, 37 insertions(+), 36 deletions(-) diff --git a/node/src/main/kotlin/com/r3corda/node/internal/Node.kt b/node/src/main/kotlin/com/r3corda/node/internal/Node.kt index 3c444317c2..85cfac29a3 100644 --- a/node/src/main/kotlin/com/r3corda/node/internal/Node.kt +++ b/node/src/main/kotlin/com/r3corda/node/internal/Node.kt @@ -25,6 +25,7 @@ import org.glassfish.jersey.server.ServerProperties import org.glassfish.jersey.servlet.ServletContainer import java.io.RandomAccessFile import java.lang.management.ManagementFactory +import java.net.InetSocketAddress import java.nio.channels.FileLock import java.nio.file.Files import java.nio.file.Path @@ -52,7 +53,7 @@ class ConfigurationException(message: String) : Exception(message) * Listed clientAPI classes are assumed to have to take a single APIServer constructor parameter * @param clock The clock used within the node and by all protocols etc */ -class Node(dir: Path, val p2pAddr: HostAndPort, configuration: NodeConfiguration, +class Node(dir: Path, val p2pAddr: HostAndPort, val webServerAddr: HostAndPort, configuration: NodeConfiguration, networkMapAddress: NodeInfo?, advertisedServices: Set, clock: Clock = NodeClock(), val clientAPIs: List> = listOf()) : AbstractNode(dir, configuration, networkMapAddress, advertisedServices, clock) { @@ -71,9 +72,6 @@ class Node(dir: Path, val p2pAddr: HostAndPort, configuration: NodeConfiguration // when our process shuts down, but we try in stop() anyway just to be nice. private var nodeFileLock: FileLock? = null - // TODO: Move to node config file - private var webServerPort: Int = p2pAddr.port + 1 - override fun makeMessagingService(): MessagingService = ArtemisMessagingService(dir, p2pAddr, serverThread) override fun startMessagingService() { @@ -81,14 +79,9 @@ class Node(dir: Path, val p2pAddr: HostAndPort, configuration: NodeConfiguration (net as ArtemisMessagingService).start() } - fun setWebServerPort(port: Int): Node { - webServerPort = port - return this - } - private fun initWebServer(): Server { // Note that the web server handlers will all run concurrently, and not on the node thread. - val server = Server(webServerPort) + val server = Server(InetSocketAddress(webServerAddr.hostText, webServerAddr.port)) val handlerCollection = HandlerCollection() diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt b/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt index 9b7dbbd530..d8f4016078 100644 --- a/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt +++ b/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt @@ -52,7 +52,7 @@ private fun startNode(dir: Path, "--dir", dir.toString(), "--network-address", nodeAddr.toString(), "--network-map-address", networkMapAddr.toString(), - "--api-address", apiAddr.port.toString()) + "--api-address", apiAddr.toString()) val proc = spawn("com.r3corda.demos.IRSDemoKt", args, "IRSDemo$nodeType") ensureNodeStartsOrKill(proc, apiAddr) return proc diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt b/src/integration-test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt index 0dcb4c0793..7c1cd52ec2 100644 --- a/src/integration-test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt +++ b/src/integration-test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt @@ -11,10 +11,11 @@ import kotlin.test.assertEquals class TraderDemoTest { @Test fun `runs trader demo`() { val buyerAddr = freeLocalHostAndPort() + val buyerApiAddr = freeLocalHostAndPort() var nodeProc: Process? = null try { cleanupFiles() - nodeProc = runBuyer(buyerAddr) + nodeProc = runBuyer(buyerAddr, buyerApiAddr) runSeller(buyerAddr) } finally { nodeProc?.destroy() @@ -23,9 +24,13 @@ class TraderDemoTest { } } -private fun runBuyer(buyerAddr: HostAndPort): Process { +private fun runBuyer(buyerAddr: HostAndPort, buyerApiAddr: HostAndPort): Process { println("Running Buyer") - val args = listOf("--role", "BUYER", "--network-address", buyerAddr.toString()) + val args = listOf( + "--role", "BUYER", + "--network-address", buyerAddr.toString(), + "--api-address", buyerApiAddr.toString() + ) val proc = spawn("com.r3corda.demos.TraderDemoKt", args, "TradeDemoBuyer") ensureNodeStartsOrKill(proc, buyerAddr) return proc @@ -34,10 +39,13 @@ private fun runBuyer(buyerAddr: HostAndPort): Process { private fun runSeller(buyerAddr: HostAndPort) { println("Running Seller") val sellerAddr = freeLocalHostAndPort() + val sellerApiAddr = freeLocalHostAndPort() val args = listOf( "--role", "SELLER", "--network-address", sellerAddr.toString(), - "--other-network-address", buyerAddr.toString()) + "--api-address", sellerApiAddr.toString(), + "--other-network-address", buyerAddr.toString() + ) val proc = spawn("com.r3corda.demos.TraderDemoKt", args, "TradeDemoSeller") assertExitOrKill(proc); assertEquals(proc.exitValue(), 0) @@ -48,4 +56,4 @@ private fun cleanupFiles() { val dir = Paths.get("trader-demo") println("Erasing " + dir) dir.toFile().deleteRecursively() -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt index 091837bf01..48022c022a 100644 --- a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt @@ -4,7 +4,6 @@ import com.google.common.net.HostAndPort import com.typesafe.config.ConfigFactory import com.r3corda.core.crypto.Party import com.r3corda.core.logElapsedTime -import com.r3corda.core.messaging.MessageRecipients import com.r3corda.core.messaging.SingleMessageRecipient import com.r3corda.node.internal.Node import com.r3corda.node.services.config.NodeConfiguration @@ -12,7 +11,6 @@ import com.r3corda.node.services.config.NodeConfigurationFromConfig import com.r3corda.core.node.NodeInfo import com.r3corda.node.services.network.NetworkMapService import com.r3corda.node.services.clientapi.NodeInterestRates -import com.r3corda.node.services.transactions.NotaryService import com.r3corda.core.node.services.ServiceType import com.r3corda.node.services.messaging.ArtemisMessagingService import com.r3corda.core.serialization.deserialize @@ -23,12 +21,10 @@ import com.r3corda.demos.protocols.ExitServerProtocol import com.r3corda.demos.protocols.UpdateBusinessDayProtocol import com.r3corda.node.internal.AbstractNode import com.r3corda.node.internal.testing.MockNetwork -import com.r3corda.node.services.network.InMemoryMessagingNetwork import com.r3corda.node.services.transactions.SimpleNotaryService import joptsimple.OptionParser import joptsimple.OptionSet import joptsimple.OptionSpec -import joptsimple.OptionSpecBuilder import java.io.DataOutputStream import java.io.File import java.net.HttpURLConnection @@ -63,7 +59,7 @@ private class NodeParams() { var dir : Path = Paths.get("") var address : HostAndPort = HostAndPort.fromString("localhost").withDefaultPort(Node.DEFAULT_PORT) var mapAddress: String = "" - var apiPort : Int = Node.DEFAULT_PORT + 1 + var apiAddress: HostAndPort = HostAndPort.fromString("localhost").withDefaultPort(Node.DEFAULT_PORT + 1) var identityFile: Path = Paths.get("") var tradeWithAddrs: List = listOf() var tradeWithIdentities: List = listOf() @@ -74,7 +70,7 @@ private class NodeParams() { private class DemoArgs() { lateinit var roleArg: OptionSpec lateinit var networkAddressArg: OptionSpec - lateinit var apiPort: OptionSpec + lateinit var apiAddressArg: OptionSpec lateinit var dirArg: OptionSpec lateinit var networkMapIdentityFile: OptionSpec lateinit var networkMapNetAddr: OptionSpec @@ -181,7 +177,7 @@ private fun setupArgs(parser: OptionParser): DemoArgs { args.roleArg = parser.accepts("role").withRequiredArg().ofType(IRSDemoRole::class.java).required() args.networkAddressArg = parser.accepts("network-address").withOptionalArg() - args.apiPort = parser.accepts("api-address").withOptionalArg().ofType(Int::class.java) + args.apiAddressArg = parser.accepts("api-address").withOptionalArg() args.dirArg = parser.accepts("directory").withOptionalArg() args.networkMapIdentityFile = parser.accepts("network-map-identity-file").withOptionalArg() args.networkMapNetAddr = parser.accepts("network-map-address").withRequiredArg().defaultsTo("localhost") @@ -240,10 +236,8 @@ private fun configureNodeParams(role: IRSDemoRole, args: DemoArgs, options: Opti if (options.has(args.networkAddressArg)) { nodeParams.address = HostAndPort.fromString(options.valueOf(args.networkAddressArg)).withDefaultPort(Node.DEFAULT_PORT) } - if (options.has(args.apiPort)) { - nodeParams.apiPort = options.valueOf(args.apiPort) - } else if (options.has(args.networkAddressArg)) { - nodeParams.apiPort = nodeParams.address.port + 1 + if (options.has(args.apiAddressArg)) { + nodeParams.apiAddress = HostAndPort.fromString(options.valueOf(args.apiAddressArg)).withDefaultPort(Node.DEFAULT_PORT + 1) } nodeParams.identityFile = if (options.has(args.networkMapIdentityFile)) { @@ -274,7 +268,7 @@ private fun runNode(nodeParams: NodeParams): Unit { ExitServerProtocol.Handler.register(node) if (nodeParams.uploadRates) { - runUploadRates(HostAndPort.fromString("localhost:${nodeParams.apiPort}")) + runUploadRates(nodeParams.apiAddress) } try { @@ -301,9 +295,10 @@ private fun startNode(params : NodeParams, networkMap: SingleMessageRecipient, r nodeInfo(networkMap, params.identityFile, setOf(NetworkMapService.Type, SimpleNotaryService.Type)) } - val node = logElapsedTime("Node startup") { Node(params.dir, params.address, config, networkMapId, - advertisedServices, DemoClock(), - listOf(InterestRateSwapAPI::class.java)).setWebServerPort(params.apiPort).start() } + val node = logElapsedTime("Node startup") { + Node(params.dir, params.address, params.apiAddress, config, networkMapId, advertisedServices, DemoClock(), + listOf(InterestRateSwapAPI::class.java)).start() + } // TODO: This should all be replaced by the identity service being updated // as the network map changes. @@ -424,7 +419,7 @@ private fun createNodeAParams() : NodeParams { val params = NodeParams() params.dir = Paths.get("nodeA") params.address = HostAndPort.fromString("localhost").withDefaultPort(Node.DEFAULT_PORT) - params.apiPort = Node.DEFAULT_PORT + 1 + params.apiAddress = HostAndPort.fromString("localhost").withDefaultPort(Node.DEFAULT_PORT + 1) params.tradeWithAddrs = listOf("localhost:31340") params.tradeWithIdentities = listOf(getRoleDir(IRSDemoRole.NodeB).resolve(AbstractNode.PUBLIC_IDENTITY_FILE_NAME)) params.defaultLegalName = "Bank A" @@ -435,7 +430,7 @@ private fun createNodeBParams() : NodeParams { val params = NodeParams() params.dir = Paths.get("nodeB") params.address = HostAndPort.fromString("localhost:31340") - params.apiPort = 31341 + params.apiAddress = HostAndPort.fromString("localhost:31341") params.tradeWithAddrs = listOf("localhost") params.tradeWithIdentities = listOf(getRoleDir(IRSDemoRole.NodeA).resolve(AbstractNode.PUBLIC_IDENTITY_FILE_NAME)) params.defaultLegalName = "Bank B" diff --git a/src/main/kotlin/com/r3corda/demos/RateFixDemo.kt b/src/main/kotlin/com/r3corda/demos/RateFixDemo.kt index ee5f7fa4de..97bbbf2e4c 100644 --- a/src/main/kotlin/com/r3corda/demos/RateFixDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/RateFixDemo.kt @@ -1,5 +1,6 @@ package com.r3corda.demos +import com.google.common.net.HostAndPort import com.r3corda.contracts.cash.Cash import com.r3corda.core.contracts.* import com.r3corda.core.crypto.Party @@ -71,7 +72,9 @@ fun main(args: Array) { override val nearestCity: String = "Atlantis" } - val node = logElapsedTime("Node startup") { Node(dir, myNetAddr, config, networkMapAddress, + val apiAddr = HostAndPort.fromParts(myNetAddr.hostText, myNetAddr.port + 1) + + val node = logElapsedTime("Node startup") { Node(dir, myNetAddr, apiAddr, config, networkMapAddress, advertisedServices, DemoClock(), listOf(InterestRateSwapAPI::class.java)).setup().start() } @@ -89,4 +92,4 @@ fun main(args: Array) { println() print(Emoji.renderIfSupported(tx.toWireTransaction())) println(tx.toSignedTransaction().sigs) -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/r3corda/demos/TraderDemo.kt b/src/main/kotlin/com/r3corda/demos/TraderDemo.kt index ec93fe7780..83ecc5c418 100644 --- a/src/main/kotlin/com/r3corda/demos/TraderDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/TraderDemo.kt @@ -77,6 +77,7 @@ fun runTraderDemo(args: Array): Int { val roleArg = parser.accepts("role").withRequiredArg().ofType(Role::class.java).required() val myNetworkAddress = parser.accepts("network-address").withRequiredArg().defaultsTo("localhost") val theirNetworkAddress = parser.accepts("other-network-address").withRequiredArg().defaultsTo("localhost") + val apiNetworkAddress = parser.accepts("api-address").withRequiredArg().defaultsTo("localhost") val options = try { parser.parse(*args) @@ -100,6 +101,7 @@ fun runTraderDemo(args: Array): Int { Role.SELLER -> 31337 } ) + val apiNetAddr = HostAndPort.fromString(options.valueOf(apiNetworkAddress)).withDefaultPort(myNetAddr.port + 1) // Suppress the Artemis MQ noise, and activate the demo logging. // @@ -143,7 +145,7 @@ fun runTraderDemo(args: Array): Int { // And now construct then start the node object. It takes a little while. val node = logElapsedTime("Node startup") { - Node(directory, myNetAddr, config, networkMapId, advertisedServices).setup().start() + Node(directory, myNetAddr, apiNetAddr, config, networkMapId, advertisedServices).setup().start() } // TODO: Replace with a separate trusted cash issuer From f2505fb5045f7695176e7f8405db927b9ebb07fb Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Mon, 27 Jun 2016 14:14:12 +0100 Subject: [PATCH 049/114] integtest: Put delay in status polling --- .../com/r3corda/core/testing/IRSDemoTest.kt | 2 +- .../r3corda/core/testing/TraderDemoTest.kt | 4 +- .../core/testing/utilities/JVMSpawner.kt | 2 +- .../r3corda/core/testing/utilities/NodeApi.kt | 87 ++++++++++--------- 4 files changed, 51 insertions(+), 44 deletions(-) diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt b/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt index d8f4016078..a0e653525d 100644 --- a/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt +++ b/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt @@ -54,7 +54,7 @@ private fun startNode(dir: Path, "--network-map-address", networkMapAddr.toString(), "--api-address", apiAddr.toString()) val proc = spawn("com.r3corda.demos.IRSDemoKt", args, "IRSDemo$nodeType") - ensureNodeStartsOrKill(proc, apiAddr) + NodeApi.ensureNodeStartsOrKill(proc, apiAddr) return proc } diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt b/src/integration-test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt index 7c1cd52ec2..5a48ff5a28 100644 --- a/src/integration-test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt +++ b/src/integration-test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt @@ -1,8 +1,8 @@ package com.r3corda.core.testing import com.google.common.net.HostAndPort +import com.r3corda.core.testing.utilities.NodeApi import com.r3corda.core.testing.utilities.assertExitOrKill -import com.r3corda.core.testing.utilities.ensureNodeStartsOrKill import com.r3corda.core.testing.utilities.spawn import org.junit.Test import java.nio.file.Paths @@ -32,7 +32,7 @@ private fun runBuyer(buyerAddr: HostAndPort, buyerApiAddr: HostAndPort): Process "--api-address", buyerApiAddr.toString() ) val proc = spawn("com.r3corda.demos.TraderDemoKt", args, "TradeDemoBuyer") - ensureNodeStartsOrKill(proc, buyerAddr) + NodeApi.ensureNodeStartsOrKill(proc, buyerApiAddr) return proc } diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/utilities/JVMSpawner.kt b/src/integration-test/kotlin/com/r3corda/core/testing/utilities/JVMSpawner.kt index 5d7a063c1b..2bd06445ca 100644 --- a/src/integration-test/kotlin/com/r3corda/core/testing/utilities/JVMSpawner.kt +++ b/src/integration-test/kotlin/com/r3corda/core/testing/utilities/JVMSpawner.kt @@ -31,4 +31,4 @@ fun assertAliveAndKill(proc: Process) { } finally { proc.destroyForcibly() } -} \ No newline at end of file +} diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/utilities/NodeApi.kt b/src/integration-test/kotlin/com/r3corda/core/testing/utilities/NodeApi.kt index 0f6d6239e7..867c1d26a5 100644 --- a/src/integration-test/kotlin/com/r3corda/core/testing/utilities/NodeApi.kt +++ b/src/integration-test/kotlin/com/r3corda/core/testing/utilities/NodeApi.kt @@ -9,46 +9,53 @@ import java.net.HttpURLConnection import java.net.URL import kotlin.test.assertEquals -class NodeDidNotStartException: Exception { - constructor(message: String): super(message) {} -} +class NodeApi { + class NodeDidNotStartException(message: String): Exception(message) -fun ensureNodeStartsOrKill(proc: Process, nodeAddr: HostAndPort) { - try { - assertEquals(proc.isAlive, true) - waitForNodeStartup(nodeAddr) - } catch (e: Throwable) { - println("Forcibly killing node process") - proc.destroyForcibly() - throw e + companion object { + val NODE_WAIT_RETRY_COUNT: Int = 50 + val NODE_WAIT_RETRY_DELAY_MS: Long = 200 + + fun ensureNodeStartsOrKill(proc: Process, nodeWebserverAddr: HostAndPort) { + try { + assertEquals(proc.isAlive, true) + waitForNodeStartup(nodeWebserverAddr) + } catch (e: Throwable) { + println("Forcibly killing node process") + proc.destroyForcibly() + throw e + } + } + + private fun waitForNodeStartup(nodeWebserverAddr: HostAndPort) { + val url = URL("http://${nodeWebserverAddr.toString()}/api/status") + var retries = 0 + var respCode: Int + do { + retries++ + val err = try { + val conn = url.openConnection() as HttpURLConnection + conn.requestMethod = "GET" + respCode = conn.responseCode + InputStreamReader(conn.inputStream).readLines().joinToString { it } + } catch(e: ConnectException) { + // This is to be expected while it loads up + respCode = 404 + "Node hasn't started" + } catch(e: SocketException) { + respCode = -1 + "Could not connect: ${e.toString()}" + } catch (e: IOException) { + respCode = -1 + "IOException: ${e.toString()}" + } + + if (retries > NODE_WAIT_RETRY_COUNT) { + throw NodeDidNotStartException("The node did not start: " + err) + } + + Thread.sleep(NODE_WAIT_RETRY_DELAY_MS) + } while (respCode != 200) + } } } - -private fun waitForNodeStartup(nodeAddr: HostAndPort) { - val url = URL("http://${nodeAddr.toString()}/api/status") - var retries = 0 - var respCode: Int - do { - retries++ - val err = try { - val conn = url.openConnection() as HttpURLConnection - conn.requestMethod = "GET" - respCode = conn.responseCode - InputStreamReader(conn.inputStream).readLines().joinToString { it } - } catch(e: ConnectException) { - // This is to be expected while it loads up - respCode = 404 - "Node hasn't started" - } catch(e: SocketException) { - respCode = -1 - "Could not connect: ${e.toString()}" - } catch (e: IOException) { - respCode = -1 - "IOException: ${e.toString()}" - } - - if (retries > 25) { - throw NodeDidNotStartException("The node did not start: " + err) - } - } while (respCode != 200) -} From 1e15e7a206ada50ad2b53fdad7d2b0011d765ee6 Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Tue, 28 Jun 2016 13:56:55 +0100 Subject: [PATCH 050/114] trader-demo: Put demo directory under build/, add corresponding cli option --- src/main/kotlin/com/r3corda/demos/TraderDemo.kt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/com/r3corda/demos/TraderDemo.kt b/src/main/kotlin/com/r3corda/demos/TraderDemo.kt index 83ecc5c418..8178309c4b 100644 --- a/src/main/kotlin/com/r3corda/demos/TraderDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/TraderDemo.kt @@ -64,7 +64,7 @@ enum class Role { // And this is the directory under the current working directory where each node will create its own server directory, // which holds things like checkpoints, keys, databases, message logs etc. -val DIRNAME = "trader-demo" +val DEFAULT_BASE_DIRECTORY = "./build/trader-demo" fun main(args: Array) { exitProcess(runTraderDemo(args)) @@ -78,6 +78,7 @@ fun runTraderDemo(args: Array): Int { val myNetworkAddress = parser.accepts("network-address").withRequiredArg().defaultsTo("localhost") val theirNetworkAddress = parser.accepts("other-network-address").withRequiredArg().defaultsTo("localhost") val apiNetworkAddress = parser.accepts("api-address").withRequiredArg().defaultsTo("localhost") + val baseDirectoryArg = parser.accepts("base-directory").withRequiredArg().defaultsTo(DEFAULT_BASE_DIRECTORY) val options = try { parser.parse(*args) @@ -103,13 +104,16 @@ fun runTraderDemo(args: Array): Int { ) val apiNetAddr = HostAndPort.fromString(options.valueOf(apiNetworkAddress)).withDefaultPort(myNetAddr.port + 1) + val baseDirectory = options.valueOf(baseDirectoryArg)!! + // Suppress the Artemis MQ noise, and activate the demo logging. // // The first two strings correspond to the first argument to StateMachineManager.add() but the way we handle logging // for protocols will change in future. BriefLogFormatter.initVerbose("+demo.buyer", "+demo.seller", "-org.apache.activemq") - val directory = Paths.get(DIRNAME, role.name.toLowerCase()) + val directory = Paths.get(baseDirectory, role.name.toLowerCase()) + println("Using base demo directory $directory") // Override the default config file (which you can find in the file "reference.conf") to give each node a name. val config = run { @@ -136,7 +140,7 @@ fun runTraderDemo(args: Array): Int { // be a single shared map service (this is analagous to the DNS seeds in Bitcoin). // // TODO: AbstractNode should write out the full NodeInfo object and we should just load it here. - val path = Paths.get(DIRNAME, Role.BUYER.name.toLowerCase(), "identity-public") + val path = Paths.get(baseDirectory, Role.BUYER.name.toLowerCase(), "identity-public") val party = Files.readAllBytes(path).deserialize() advertisedServices = emptySet() cashIssuer = party From 54967afb788c88ea1b6562dc1f7f9ae5f88a68ac Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Tue, 28 Jun 2016 13:59:48 +0100 Subject: [PATCH 051/114] irs-demo: Rework CLI parsing, add api-address --- src/main/kotlin/com/r3corda/demos/IRSDemo.kt | 491 ++++++++++--------- 1 file changed, 258 insertions(+), 233 deletions(-) diff --git a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt index 48022c022a..8c3914be50 100644 --- a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt @@ -24,7 +24,6 @@ import com.r3corda.node.internal.testing.MockNetwork import com.r3corda.node.services.transactions.SimpleNotaryService import joptsimple.OptionParser import joptsimple.OptionSet -import joptsimple.OptionSpec import java.io.DataOutputStream import java.io.File import java.net.HttpURLConnection @@ -41,11 +40,14 @@ import java.net.SocketTimeoutException // IRS DEMO // // Please see docs/build/html/running-the-trading-demo.html -// -// TODO: TBD -// -// The different roles in the scenario this program can adopt are: +/** + * Roles. There are 4 modes this demo can be run: + * - SetupNodeA/SetupNodeB: Creates and sets up the necessary directories for nodes + * - NodeA/NodeB: Starts the nodes themselves + * - Trade: Uploads an example trade + * - DateChange: Changes the demo's date + */ enum class IRSDemoRole { SetupNodeA, SetupNodeB, @@ -55,28 +57,185 @@ enum class IRSDemoRole { Date } -private class NodeParams() { - var dir : Path = Paths.get("") - var address : HostAndPort = HostAndPort.fromString("localhost").withDefaultPort(Node.DEFAULT_PORT) - var mapAddress: String = "" - var apiAddress: HostAndPort = HostAndPort.fromString("localhost").withDefaultPort(Node.DEFAULT_PORT + 1) - var identityFile: Path = Paths.get("") - var tradeWithAddrs: List = listOf() - var tradeWithIdentities: List = listOf() - var uploadRates: Boolean = false - var defaultLegalName: String = "" +/** + * Parsed command line parameters. + */ +sealed class CliParams { + + /** + * Corresponds to roles 'SetupNodeA' and 'SetupNodeB' + */ + class SetupNode( + val node: IRSDemoNode, + val dir: Path, + val defaultLegalName: String + ) : CliParams() + + /** + * Corresponds to roles 'NodeA' and 'NodeB' + */ + class RunNode( + val node: IRSDemoNode, + val dir: Path, + val networkAddress : HostAndPort, + val apiAddress: HostAndPort, + val mapAddress: String, + val identityFile: Path, + val tradeWithAddrs: List, + val tradeWithIdentities: List, + val uploadRates: Boolean, + val defaultLegalName: String, + val autoSetup: Boolean // Run Setup for both nodes automatically with default arguments + ) : CliParams() + + /** + * Corresponds to role 'Trade' + */ + class Trade( + val apiAddress: HostAndPort, + val tradeId: String + ) : CliParams() + + /** + * Corresponds to role 'Date' + */ + class DateChange( + val apiAddress: HostAndPort, + val dateString: String + ) : CliParams() + + companion object { + + val defaultBaseDirectory = "./build/irs-demo" + + fun legalName(node: IRSDemoNode) = + when (node) { + IRSDemoNode.NodeA -> "Bank A" + IRSDemoNode.NodeB -> "Bank B" + } + + private fun nodeDirectory(options: OptionSet, node: IRSDemoNode) = + Paths.get(options.valueOf(CliParamsSpec.baseDirectoryArg), node.name.decapitalize()) + + private fun parseSetupNode(options: OptionSet, node: IRSDemoNode): SetupNode { + return SetupNode( + node = node, + dir = nodeDirectory(options, node), + defaultLegalName = legalName(node) + ) + } + + private fun defaultNetworkPort(node: IRSDemoNode) = + when (node) { + IRSDemoNode.NodeA -> Node.DEFAULT_PORT + IRSDemoNode.NodeB -> Node.DEFAULT_PORT + 2 + } + + private fun defaultApiPort(node: IRSDemoNode) = + when (node) { + IRSDemoNode.NodeA -> Node.DEFAULT_PORT + 1 + IRSDemoNode.NodeB -> Node.DEFAULT_PORT + 3 + } + + private fun parseRunNode(options: OptionSet, node: IRSDemoNode): RunNode { + val dir = nodeDirectory(options, node) + + return RunNode( + node = node, + dir = dir, + networkAddress = HostAndPort.fromString(options.valueOf( + CliParamsSpec.networkAddressArg.defaultsTo("localhost:${defaultNetworkPort(node)}") + )), + apiAddress = HostAndPort.fromString(options.valueOf( + CliParamsSpec.apiAddressArg.defaultsTo("localhost:${defaultApiPort(node)}") + )), + mapAddress = options.valueOf(CliParamsSpec.networkMapNetAddr), + identityFile = if (options.has(CliParamsSpec.networkMapIdentityFile)) { + Paths.get(options.valueOf(CliParamsSpec.networkMapIdentityFile)) + } else { + dir.resolve(AbstractNode.PUBLIC_IDENTITY_FILE_NAME) + }, + tradeWithAddrs = if (options.has(CliParamsSpec.fakeTradeWithAddr)) { + options.valuesOf(CliParamsSpec.fakeTradeWithAddr) + } else { + listOf("localhost:${defaultNetworkPort(node.other)}") + }, + tradeWithIdentities = if (options.has(CliParamsSpec.fakeTradeWithIdentityFile)) { + options.valuesOf(CliParamsSpec.fakeTradeWithIdentityFile).map { Paths.get(it) } + } else { + listOf(nodeDirectory(options, node.other).resolve(AbstractNode.PUBLIC_IDENTITY_FILE_NAME)) + }, + uploadRates = node == IRSDemoNode.NodeB, + defaultLegalName = legalName(node), + autoSetup = !options.has(CliParamsSpec.baseDirectoryArg) && !options.has(CliParamsSpec.fakeTradeWithIdentityFile) + ) + } + + private fun parseTrade(options: OptionSet): Trade { + return Trade( + apiAddress = HostAndPort.fromString(options.valueOf( + CliParamsSpec.apiAddressArg.defaultsTo("localhost:${defaultApiPort(IRSDemoNode.NodeA)}") + )), + tradeId = options.valuesOf(CliParamsSpec.nonOptions).let { + if (it.size > 0) { + it[0] + } else { + throw IllegalArgumentException("Please provide a trade ID") + } + } + ) + } + + private fun parseDateChange(options: OptionSet): DateChange { + return DateChange( + apiAddress = HostAndPort.fromString(options.valueOf(CliParamsSpec.apiAddressArg)), + dateString = options.valuesOf(CliParamsSpec.nonOptions).let { + if (it.size > 0) { + it[0] + } else { + throw IllegalArgumentException("Please provide a date string") + } + } + ) + } + + fun parse(options: OptionSet): CliParams { + val role = options.valueOf(CliParamsSpec.roleArg)!! + return when (role) { + IRSDemoRole.SetupNodeA -> parseSetupNode(options, IRSDemoNode.NodeA) + IRSDemoRole.SetupNodeB -> parseSetupNode(options, IRSDemoNode.NodeB) + IRSDemoRole.NodeA -> parseRunNode(options, IRSDemoNode.NodeA) + IRSDemoRole.NodeB -> parseRunNode(options, IRSDemoNode.NodeB) + IRSDemoRole.Trade -> parseTrade(options) + IRSDemoRole.Date -> parseDateChange(options) + } + } + } } -private class DemoArgs() { - lateinit var roleArg: OptionSpec - lateinit var networkAddressArg: OptionSpec - lateinit var apiAddressArg: OptionSpec - lateinit var dirArg: OptionSpec - lateinit var networkMapIdentityFile: OptionSpec - lateinit var networkMapNetAddr: OptionSpec - lateinit var fakeTradeWithAddr: OptionSpec - lateinit var fakeTradeWithIdentityFile: OptionSpec - lateinit var nonOptions: OptionSpec +enum class IRSDemoNode { + NodeA, + NodeB; + + val other: IRSDemoNode get() { + return when (this) { + NodeA -> NodeB + NodeB -> NodeA + } + } +} + +object CliParamsSpec { + val parser = OptionParser() + val roleArg = parser.accepts("role").withRequiredArg().ofType(IRSDemoRole::class.java) + val networkAddressArg = parser.accepts("network-address").withOptionalArg().ofType(String::class.java) + val apiAddressArg = parser.accepts("api-address").withOptionalArg().ofType(String::class.java) + val baseDirectoryArg = parser.accepts("base-directory").withOptionalArg().defaultsTo(CliParams.defaultBaseDirectory) + val networkMapIdentityFile = parser.accepts("network-map-identity-file").withOptionalArg() + val networkMapNetAddr = parser.accepts("network-map-address").withRequiredArg().defaultsTo("localhost") + val fakeTradeWithAddr = parser.accepts("fake-trade-with-address").withOptionalArg() + val fakeTradeWithIdentityFile = parser.accepts("fake-trade-with-identity-file").withOptionalArg() + val nonOptions = parser.nonOptions() } private class NotSetupException: Throwable { @@ -88,12 +247,10 @@ fun main(args: Array) { } fun runIRSDemo(args: Array): Int { - val parser = OptionParser() - val demoArgs = setupArgs(parser) - val options = try { - parser.parse(*args) + val cliParams = try { + CliParams.parse(CliParamsSpec.parser.parse(*args)) } catch (e: Exception) { - println(e.message) + println(e) printHelp() return 1 } @@ -101,69 +258,62 @@ fun runIRSDemo(args: Array): Int { // Suppress the Artemis MQ noise, and activate the demo logging. BriefLogFormatter.initVerbose("+demo.irsdemo", "+api-call", "+platform.deal", "-org.apache.activemq") - val role = options.valueOf(demoArgs.roleArg)!! - return when (role) { - IRSDemoRole.SetupNodeA -> setup(configureNodeParams(IRSDemoRole.NodeA, demoArgs, options)) - IRSDemoRole.SetupNodeB -> setup(configureNodeParams(IRSDemoRole.NodeB, demoArgs, options)) - IRSDemoRole.NodeA -> runNode(role, demoArgs, options) - IRSDemoRole.NodeB -> runNode(role, demoArgs, options) - IRSDemoRole.Trade -> runTrade(demoArgs, options) - IRSDemoRole.Date -> runDateChange(demoArgs, options) + return when (cliParams) { + is CliParams.SetupNode -> setup(cliParams) + is CliParams.RunNode -> runNode(cliParams) + is CliParams.Trade -> runTrade(cliParams) + is CliParams.DateChange -> runDateChange(cliParams) } } -private fun runTrade(demoArgs: DemoArgs, options: OptionSet): Int { - val tradeIdArgs = options.valuesOf(demoArgs.nonOptions) - if (tradeIdArgs.size > 0) { - val tradeId = tradeIdArgs[0] - val host = if (options.has(demoArgs.networkAddressArg)) { - options.valueOf(demoArgs.networkAddressArg) - } else { - "http://localhost:" + (Node.DEFAULT_PORT + 1) - } - - if (!uploadTrade(tradeId, host)) { - return 1 - } - } else { - println("Please provide a trade ID") - return 1 +private fun setup(params: CliParams.SetupNode): Int { + val dirFile = params.dir.toFile() + if (!dirFile.exists()) { + dirFile.mkdirs() } + val configFile = params.dir.resolve("config").toFile() + val config = loadConfigFile(configFile, params.defaultLegalName) + if (!Files.exists(params.dir.resolve(AbstractNode.PUBLIC_IDENTITY_FILE_NAME))) { + createIdentities(params, config) + } return 0 } -private fun runDateChange(demoArgs: DemoArgs, options: OptionSet): Int { - val dateStrArgs = options.valuesOf(demoArgs.nonOptions) - if (dateStrArgs.size > 0) { - val dateStr = dateStrArgs[0] - val host = if (options.has(demoArgs.networkAddressArg)) { - options.valueOf(demoArgs.networkAddressArg) - } else { - "http://localhost:" + (Node.DEFAULT_PORT + 1) - } +private fun defaultNodeSetupParams(node: IRSDemoNode): CliParams.SetupNode = + CliParams.SetupNode( + node = node, + dir = Paths.get(CliParams.defaultBaseDirectory, node.name.decapitalize()), + defaultLegalName = CliParams.legalName(node) + ) - if (!changeDate(dateStr, host)) { - return 1 - } - } else { - println("Please provide a date") - return 1 - } - - return 0 -} - -private fun runNode(role: IRSDemoRole, demoArgs: DemoArgs, options: OptionSet): Int { - // If these directory and identity file arguments aren't specified then we can assume a default setup and - // create everything that is needed without needing to run setup. - if (!options.has(demoArgs.dirArg) && !options.has(demoArgs.fakeTradeWithIdentityFile)) { - createNodeConfig(createNodeAParams()); - createNodeConfig(createNodeBParams()); +private fun runNode(cliParams: CliParams.RunNode): Int { + if (cliParams.autoSetup) { + setup(defaultNodeSetupParams(IRSDemoNode.NodeA)) + setup(defaultNodeSetupParams(IRSDemoNode.NodeB)) } try { - runNode(configureNodeParams(role, demoArgs, options)) + val networkMap = createRecipient(cliParams.mapAddress) + val destinations = cliParams.tradeWithAddrs.map({ + createRecipient(it) + }) + + val node = startNode(cliParams, networkMap, destinations) + // Register handlers for the demo + AutoOfferProtocol.Handler.register(node) + UpdateBusinessDayProtocol.Handler.register(node) + ExitServerProtocol.Handler.register(node) + + if (cliParams.uploadRates) { + runUploadRates(cliParams.apiAddress) + } + + try { + while (true) Thread.sleep(Long.MAX_VALUE) + } catch(e: InterruptedException) { + node.stop() + } } catch (e: NotSetupException) { println(e.message) return 1 @@ -172,109 +322,30 @@ private fun runNode(role: IRSDemoRole, demoArgs: DemoArgs, options: OptionSet): return 0 } -private fun setupArgs(parser: OptionParser): DemoArgs { - val args = DemoArgs() - - args.roleArg = parser.accepts("role").withRequiredArg().ofType(IRSDemoRole::class.java).required() - args.networkAddressArg = parser.accepts("network-address").withOptionalArg() - args.apiAddressArg = parser.accepts("api-address").withOptionalArg() - args.dirArg = parser.accepts("directory").withOptionalArg() - args.networkMapIdentityFile = parser.accepts("network-map-identity-file").withOptionalArg() - args.networkMapNetAddr = parser.accepts("network-map-address").withRequiredArg().defaultsTo("localhost") - // Use these to list one or more peers (again, will be superseded by discovery implementation) - args.fakeTradeWithAddr = parser.accepts("fake-trade-with-address").withOptionalArg() - args.fakeTradeWithIdentityFile = parser.accepts("fake-trade-with-identity-file").withOptionalArg() - args.nonOptions = parser.nonOptions().ofType(String::class.java) - - return args -} - -private fun setup(params: NodeParams): Int { - createNodeConfig(params) - return 0 -} - -private fun changeDate(date: String, host: String) : Boolean { - println("Changing date to " + date) - val url = URL(host + "/api/irs/demodate") - if (putJson(url, "\"" + date + "\"")) { +private fun runDateChange(cliParams: CliParams.DateChange): Int { + println("Changing date to " + cliParams.dateString) + val url = URL("http://${cliParams.apiAddress}/api/irs/demodate") + if (putJson(url, "\"" + cliParams.dateString + "\"")) { println("Date changed") - return true + return 0 } else { println("Date failed to change") - return false + return 1 } } -private fun uploadTrade(tradeId: String, host: String) : Boolean { - println("Uploading tradeID " + tradeId) - val fileContents = IOUtils.toString(NodeParams::class.java.getResourceAsStream("example-irs-trade.json")) - val tradeFile = fileContents.replace("tradeXXX", tradeId) - val url = URL(host + "/api/irs/deals") +private fun runTrade(cliParams: CliParams.Trade): Int { + println("Uploading tradeID " + cliParams.tradeId) + // Note: the getResourceAsStream is an ugly hack to get the jvm to search in the right location + val fileContents = IOUtils.toString(CliParams::class.java.getResourceAsStream("example-irs-trade.json")) + val tradeFile = fileContents.replace("tradeXXX", cliParams.tradeId) + val url = URL("http://${cliParams.apiAddress}/api/irs/deals") if (postJson(url, tradeFile)) { println("Trade sent") - return true + return 0 } else { println("Trade failed to send") - return false - } -} - -private fun configureNodeParams(role: IRSDemoRole, args: DemoArgs, options: OptionSet): NodeParams { - val nodeParams = when (role) { - IRSDemoRole.NodeA -> createNodeAParams() - IRSDemoRole.NodeB -> createNodeBParams() - else -> { - throw IllegalArgumentException() - } - } - - nodeParams.mapAddress = options.valueOf(args.networkMapNetAddr) - if (options.has(args.dirArg)) { - nodeParams.dir = Paths.get(options.valueOf(args.dirArg)) - } - if (options.has(args.networkAddressArg)) { - nodeParams.address = HostAndPort.fromString(options.valueOf(args.networkAddressArg)).withDefaultPort(Node.DEFAULT_PORT) - } - if (options.has(args.apiAddressArg)) { - nodeParams.apiAddress = HostAndPort.fromString(options.valueOf(args.apiAddressArg)).withDefaultPort(Node.DEFAULT_PORT + 1) - } - - nodeParams.identityFile = if (options.has(args.networkMapIdentityFile)) { - Paths.get(options.valueOf(args.networkMapIdentityFile)) - } else { - nodeParams.dir.resolve(AbstractNode.PUBLIC_IDENTITY_FILE_NAME) - } - if (options.has(args.fakeTradeWithIdentityFile)) { - nodeParams.tradeWithIdentities = options.valuesOf(args.fakeTradeWithIdentityFile).map { Paths.get(it) } - } - if (options.has(args.fakeTradeWithAddr)) { - nodeParams.tradeWithAddrs = options.valuesOf(args.fakeTradeWithAddr) - } - - return nodeParams -} - -private fun runNode(nodeParams: NodeParams): Unit { - val networkMap = createRecipient(nodeParams.mapAddress) - val destinations = nodeParams.tradeWithAddrs.map({ - createRecipient(it) - }) - - val node = startNode(nodeParams, networkMap, destinations) - // Register handlers for the demo - AutoOfferProtocol.Handler.register(node) - UpdateBusinessDayProtocol.Handler.register(node) - ExitServerProtocol.Handler.register(node) - - if (nodeParams.uploadRates) { - runUploadRates(nodeParams.apiAddress) - } - - try { - while (true) Thread.sleep(Long.MAX_VALUE) - } catch(e: InterruptedException) { - node.stop() + return 1 } } @@ -283,7 +354,7 @@ private fun createRecipient(addr: String) : SingleMessageRecipient { return ArtemisMessagingService.makeRecipient(hostAndPort) } -private fun startNode(params : NodeParams, networkMap: SingleMessageRecipient, recipients: List) : Node { +private fun startNode(params: CliParams.RunNode, networkMap: SingleMessageRecipient, recipients: List) : Node { val config = getNodeConfig(params) val advertisedServices: Set val networkMapId = if (params.mapAddress.equals(params.address.toString())) { @@ -296,7 +367,7 @@ private fun startNode(params : NodeParams, networkMap: SingleMessageRecipient, r } val node = logElapsedTime("Node startup") { - Node(params.dir, params.address, params.apiAddress, config, networkMapId, advertisedServices, DemoClock(), + Node(params.dir, params.networkAddress, params.apiAddress, config, networkMapId, advertisedServices, DemoClock(), listOf(InterestRateSwapAPI::class.java)).start() } @@ -325,7 +396,8 @@ private fun nodeInfo(recipient: SingleMessageRecipient, identityFile: Path, adve } private fun runUploadRates(host: HostAndPort) { - val fileContents = IOUtils.toString(NodeParams::class.java.getResource("example.rates.txt")) + // Note: the getResourceAsStream is an ugly hack to get the jvm to search in the right location + val fileContents = IOUtils.toString(CliParams::class.java.getResourceAsStream("example.rates.txt")) var timer : Timer? = null timer = fixedRateTimer("upload-rates", false, 0, 5000, { try { @@ -364,7 +436,7 @@ private fun sendJson(url: URL, data: String, method: String) : Boolean { 200 -> true 201 -> true else -> { - println("Failed to " + method + " data. Status Code: " + connection.responseCode + ". Mesage: " + connection.responseMessage) + println("Failed to " + method + " data. Status Code: " + connection.responseCode + ". Message: " + connection.responseMessage) false } } @@ -401,7 +473,7 @@ private fun uploadFile(url: URL, file: String) : Boolean { val request = DataOutputStream(connection.outputStream) request.writeBytes(hyphens + boundary + clrf) - request.writeBytes("Content-Disposition: form-data; name=\"rates\" filename=\"example.rates.txt\"" + clrf) + request.writeBytes("Content-Disposition: form-data; name=\"rates\" filename=\"example.rates.txt\"$clrf") request.writeBytes(clrf) request.writeBytes(file) request.writeBytes(clrf) @@ -410,69 +482,22 @@ private fun uploadFile(url: URL, file: String) : Boolean { if (connection.responseCode == 200) { return true } else { - println("Could not upload file. Status Code: " + connection + ". Mesage: " + connection.responseMessage) + println("Could not upload file. Status Code: " + connection + ". Message: " + connection.responseMessage) return false } } -private fun createNodeAParams() : NodeParams { - val params = NodeParams() - params.dir = Paths.get("nodeA") - params.address = HostAndPort.fromString("localhost").withDefaultPort(Node.DEFAULT_PORT) - params.apiAddress = HostAndPort.fromString("localhost").withDefaultPort(Node.DEFAULT_PORT + 1) - params.tradeWithAddrs = listOf("localhost:31340") - params.tradeWithIdentities = listOf(getRoleDir(IRSDemoRole.NodeB).resolve(AbstractNode.PUBLIC_IDENTITY_FILE_NAME)) - params.defaultLegalName = "Bank A" - return params -} - -private fun createNodeBParams() : NodeParams { - val params = NodeParams() - params.dir = Paths.get("nodeB") - params.address = HostAndPort.fromString("localhost:31340") - params.apiAddress = HostAndPort.fromString("localhost:31341") - params.tradeWithAddrs = listOf("localhost") - params.tradeWithIdentities = listOf(getRoleDir(IRSDemoRole.NodeA).resolve(AbstractNode.PUBLIC_IDENTITY_FILE_NAME)) - params.defaultLegalName = "Bank B" - params.uploadRates = true - return params -} - -private fun createNodeConfig(params: NodeParams) : NodeConfiguration { - if (!Files.exists(params.dir)) { - Files.createDirectory(params.dir) - } - - val configFile = params.dir.resolve("config").toFile() - val config = loadConfigFile(configFile, params.defaultLegalName) - if (!Files.exists(params.dir.resolve(AbstractNode.PUBLIC_IDENTITY_FILE_NAME))) { - createIdentities(params, config) - } - - return config -} - -private fun getNodeConfig(params: NodeParams): NodeConfiguration { - if (!Files.exists(params.dir)) { +private fun getNodeConfig(cliParams: CliParams.RunNode): NodeConfiguration { + if (!Files.exists(cliParams.dir)) { throw NotSetupException("Missing config directory. Please run node setup before running the node") } - if (!Files.exists(params.dir.resolve(AbstractNode.PUBLIC_IDENTITY_FILE_NAME))) { + if (!Files.exists(cliParams.dir.resolve(AbstractNode.PUBLIC_IDENTITY_FILE_NAME))) { throw NotSetupException("Missing identity file. Please run node setup before running the node") } - val configFile = params.dir.resolve("config").toFile() - return loadConfigFile(configFile, params.defaultLegalName) -} - -private fun getRoleDir(role: IRSDemoRole) : Path { - when (role) { - IRSDemoRole.NodeA -> return Paths.get("nodeA") - IRSDemoRole.NodeB -> return Paths.get("nodeB") - else -> { - throw IllegalArgumentException() - } - } + val configFile = cliParams.dir.resolve("config").toFile() + return loadConfigFile(configFile, cliParams.defaultLegalName) } private fun loadConfigFile(configFile: File, defaultLegalName: String): NodeConfiguration { @@ -485,7 +510,7 @@ private fun loadConfigFile(configFile: File, defaultLegalName: String): NodeConf return NodeConfigurationFromConfig(config) } -private fun createIdentities(params: NodeParams, nodeConf: NodeConfiguration) { +private fun createIdentities(params: CliParams.SetupNode, nodeConf: NodeConfiguration) { val mockNetwork = MockNetwork(false) val node = MockNetwork.MockNode(params.dir, nodeConf, mockNetwork, null, setOf(NetworkMapService.Type, SimpleNotaryService.Type), 0, null) node.start() From aa82d4441e378566a50ced7c15d4f3be59aefc17 Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Tue, 28 Jun 2016 14:00:49 +0100 Subject: [PATCH 052/114] irs-demo: Fix advertised services --- src/main/kotlin/com/r3corda/demos/IRSDemo.kt | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt index 8c3914be50..e1d18d390a 100644 --- a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt @@ -357,14 +357,17 @@ private fun createRecipient(addr: String) : SingleMessageRecipient { private fun startNode(params: CliParams.RunNode, networkMap: SingleMessageRecipient, recipients: List) : Node { val config = getNodeConfig(params) val advertisedServices: Set - val networkMapId = if (params.mapAddress.equals(params.address.toString())) { - // This node provides network map and notary services - advertisedServices = setOf(NetworkMapService.Type, SimpleNotaryService.Type) - null - } else { - advertisedServices = setOf(NodeInterestRates.Type) - nodeInfo(networkMap, params.identityFile, setOf(NetworkMapService.Type, SimpleNotaryService.Type)) - } + val networkMapId = + when (params.node) { + IRSDemoNode.NodeA -> { + advertisedServices = setOf(NetworkMapService.Type, SimpleNotaryService.Type) + null + } + IRSDemoNode.NodeB -> { + advertisedServices = setOf(NodeInterestRates.Type) + nodeInfo(networkMap, params.identityFile, setOf(NetworkMapService.Type, SimpleNotaryService.Type)) + } + } val node = logElapsedTime("Node startup") { Node(params.dir, params.networkAddress, params.apiAddress, config, networkMapId, advertisedServices, DemoClock(), From 9e5bf7c32c2e9127238409256ef507569a09bb19 Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Tue, 28 Jun 2016 14:03:10 +0100 Subject: [PATCH 053/114] integtest: Use separate folder for each integtest run, provide api address --- .../com/r3corda/core/testing/IRSDemoTest.kt | 47 +++++++------ .../r3corda/core/testing/TraderDemoTest.kt | 70 +++++++++---------- .../core/testing/utilities/TestTimestamp.kt | 19 +++++ 3 files changed, 81 insertions(+), 55 deletions(-) create mode 100644 src/integration-test/kotlin/com/r3corda/core/testing/utilities/TestTimestamp.kt diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt b/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt index a0e653525d..31cc7f9f22 100644 --- a/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt +++ b/src/integration-test/kotlin/com/r3corda/core/testing/IRSDemoTest.kt @@ -12,44 +12,56 @@ class IRSDemoTest { val nodeAddrA = freeLocalHostAndPort() val apiAddrA = freeLocalHostAndPort() val apiAddrB = freeLocalHostAndPort() - val dirA = Paths.get("./nodeA") - val dirB = Paths.get("./nodeB") + + val baseDirectory = Paths.get("./build/integration-test/${TestTimestamp.timestamp}/irs-demo") var procA: Process? = null var procB: Process? = null try { - setupNode(dirA, "NodeA") - setupNode(dirB, "NodeB") - procA = startNode(dirA, "NodeA", nodeAddrA, nodeAddrA, apiAddrA) - procB = startNode(dirB, "NodeB", freeLocalHostAndPort(), nodeAddrA, apiAddrB) + setupNode(baseDirectory, "NodeA") + setupNode(baseDirectory, "NodeB") + procA = startNode( + baseDirectory = baseDirectory, + nodeType = "NodeA", + nodeAddr = nodeAddrA, + networkMapAddr = apiAddrA, + apiAddr = apiAddrA + ) + procB = startNode( + baseDirectory = baseDirectory, + nodeType = "NodeB", + nodeAddr = freeLocalHostAndPort(), + networkMapAddr = nodeAddrA, + apiAddr = apiAddrB + ) runTrade(apiAddrA) runDateChange(apiAddrA) } finally { stopNode(procA) stopNode(procB) - cleanup(dirA) - cleanup(dirB) } } } -private fun setupNode(dir: Path, nodeType: String) { +private fun setupNode(baseDirectory: Path, nodeType: String) { println("Running setup for $nodeType") - val args = listOf("--role", "Setup" + nodeType, "--dir", dir.toString()) + val args = listOf("--role", "Setup" + nodeType, "--base-directory", baseDirectory.toString()) val proc = spawn("com.r3corda.demos.IRSDemoKt", args, "IRSDemoSetup$nodeType") assertExitOrKill(proc) assertEquals(proc.exitValue(), 0) } -private fun startNode(dir: Path, +private fun startNode(baseDirectory: Path, nodeType: String, nodeAddr: HostAndPort, networkMapAddr: HostAndPort, apiAddr: HostAndPort): Process { println("Running node $nodeType") - println("Node addr: ${nodeAddr.toString()}") + println("Node addr: $nodeAddr") + println("Network map addr: $networkMapAddr") + println("API addr: $apiAddr") val args = listOf( "--role", nodeType, - "--dir", dir.toString(), + "--base-directory", baseDirectory.toString(), "--network-address", nodeAddr.toString(), "--network-map-address", networkMapAddr.toString(), "--api-address", apiAddr.toString()) @@ -60,7 +72,7 @@ private fun startNode(dir: Path, private fun runTrade(nodeAddr: HostAndPort) { println("Running trade") - val args = listOf("--role", "Trade", "trade1", "--network-address", "http://" + nodeAddr.toString()) + val args = listOf("--role", "Trade", "trade1", "--api-address", nodeAddr.toString()) val proc = spawn("com.r3corda.demos.IRSDemoKt", args, "IRSDemoTrade") assertExitOrKill(proc) assertEquals(proc.exitValue(), 0) @@ -68,7 +80,7 @@ private fun runTrade(nodeAddr: HostAndPort) { private fun runDateChange(nodeAddr: HostAndPort) { println("Running date change") - val args = listOf("--role", "Date", "2017-01-02", "--network-address", "http://" + nodeAddr.toString()) + val args = listOf("--role", "Date", "2017-01-02", "--api-address", nodeAddr.toString()) val proc = spawn("com.r3corda.demos.IRSDemoKt", args, "IRSDemoDate") assertExitOrKill(proc) assertEquals(proc.exitValue(), 0) @@ -80,8 +92,3 @@ private fun stopNode(nodeProc: Process?) { assertAliveAndKill(nodeProc) } } - -private fun cleanup(dir: Path) { - println("Erasing: " + dir.toString()) - dir.toFile().deleteRecursively() -} diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt b/src/integration-test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt index 5a48ff5a28..57d8d49ad2 100644 --- a/src/integration-test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt +++ b/src/integration-test/kotlin/com/r3corda/core/testing/TraderDemoTest.kt @@ -2,58 +2,58 @@ package com.r3corda.core.testing import com.google.common.net.HostAndPort import com.r3corda.core.testing.utilities.NodeApi +import com.r3corda.core.testing.utilities.TestTimestamp import com.r3corda.core.testing.utilities.assertExitOrKill import com.r3corda.core.testing.utilities.spawn import org.junit.Test import java.nio.file.Paths +import java.text.SimpleDateFormat +import java.util.* import kotlin.test.assertEquals class TraderDemoTest { @Test fun `runs trader demo`() { val buyerAddr = freeLocalHostAndPort() val buyerApiAddr = freeLocalHostAndPort() + val directory = "./build/integration-test/${TestTimestamp.timestamp}/trader-demo" var nodeProc: Process? = null try { - cleanupFiles() - nodeProc = runBuyer(buyerAddr, buyerApiAddr) - runSeller(buyerAddr) + nodeProc = runBuyer(directory, buyerAddr, buyerApiAddr) + runSeller(directory, buyerAddr) } finally { nodeProc?.destroy() - cleanupFiles() } } -} -private fun runBuyer(buyerAddr: HostAndPort, buyerApiAddr: HostAndPort): Process { - println("Running Buyer") - val args = listOf( - "--role", "BUYER", - "--network-address", buyerAddr.toString(), - "--api-address", buyerApiAddr.toString() - ) - val proc = spawn("com.r3corda.demos.TraderDemoKt", args, "TradeDemoBuyer") - NodeApi.ensureNodeStartsOrKill(proc, buyerApiAddr) - return proc -} + companion object { + private fun runBuyer(baseDirectory: String, buyerAddr: HostAndPort, buyerApiAddr: HostAndPort): Process { + println("Running Buyer") + val args = listOf( + "--role", "BUYER", + "--network-address", buyerAddr.toString(), + "--api-address", buyerApiAddr.toString(), + "--base-directory", baseDirectory + ) + val proc = spawn("com.r3corda.demos.TraderDemoKt", args, "TradeDemoBuyer") + NodeApi.ensureNodeStartsOrKill(proc, buyerApiAddr) + return proc + } -private fun runSeller(buyerAddr: HostAndPort) { - println("Running Seller") - val sellerAddr = freeLocalHostAndPort() - val sellerApiAddr = freeLocalHostAndPort() - val args = listOf( - "--role", "SELLER", - "--network-address", sellerAddr.toString(), - "--api-address", sellerApiAddr.toString(), - "--other-network-address", buyerAddr.toString() - ) - val proc = spawn("com.r3corda.demos.TraderDemoKt", args, "TradeDemoSeller") - assertExitOrKill(proc); - assertEquals(proc.exitValue(), 0) -} + private fun runSeller(baseDirectory: String, buyerAddr: HostAndPort) { + println("Running Seller") + val sellerAddr = freeLocalHostAndPort() + val sellerApiAddr = freeLocalHostAndPort() + val args = listOf( + "--role", "SELLER", + "--network-address", sellerAddr.toString(), + "--api-address", sellerApiAddr.toString(), + "--other-network-address", buyerAddr.toString(), + "--base-directory", baseDirectory + ) + val proc = spawn("com.r3corda.demos.TraderDemoKt", args, "TradeDemoSeller") + assertExitOrKill(proc); + assertEquals(proc.exitValue(), 0) + } -private fun cleanupFiles() { - println("Cleaning up TraderDemoTest files") - val dir = Paths.get("trader-demo") - println("Erasing " + dir) - dir.toFile().deleteRecursively() + } } diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/utilities/TestTimestamp.kt b/src/integration-test/kotlin/com/r3corda/core/testing/utilities/TestTimestamp.kt new file mode 100644 index 0000000000..43bde8be70 --- /dev/null +++ b/src/integration-test/kotlin/com/r3corda/core/testing/utilities/TestTimestamp.kt @@ -0,0 +1,19 @@ +package com.r3corda.core.testing.utilities + +import java.text.SimpleDateFormat +import java.util.* + +/** + * [timestamp] holds a formatted (UTC) timestamp that's set the first time it is queried. This is used to + * provide a uniform timestamp for tests + */ +class TestTimestamp { + companion object { + val timestamp: String = { + val tz = TimeZone.getTimeZone("UTC") + val df = SimpleDateFormat("yyyy-MM-dd-HH:mm:ss") + df.timeZone = tz + df.format(Date()) + }() + } +} From 2daa8098c9fd1e7e191f83276768e1177735a876 Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Tue, 28 Jun 2016 16:46:45 +0100 Subject: [PATCH 054/114] build: add integrationTest as a test dependency --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index 99ee6ad948..69f11733df 100644 --- a/build.gradle +++ b/build.gradle @@ -129,6 +129,7 @@ task integrationTest(type: Test) { testClassesDir = sourceSets.integrationTest.output.classesDir classpath = sourceSets.integrationTest.runtimeClasspath } +test.dependsOn(integrationTest) tasks.withType(Test) { reports.html.destination = file("${reporting.baseDir}/${name}") From d17e649137737ccefa869157278d338f1f5043dd Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Tue, 28 Jun 2016 17:55:04 +0100 Subject: [PATCH 055/114] integtest: Double polling retry count --- .../kotlin/com/r3corda/core/testing/utilities/NodeApi.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/utilities/NodeApi.kt b/src/integration-test/kotlin/com/r3corda/core/testing/utilities/NodeApi.kt index 867c1d26a5..d29bb04035 100644 --- a/src/integration-test/kotlin/com/r3corda/core/testing/utilities/NodeApi.kt +++ b/src/integration-test/kotlin/com/r3corda/core/testing/utilities/NodeApi.kt @@ -13,7 +13,7 @@ class NodeApi { class NodeDidNotStartException(message: String): Exception(message) companion object { - val NODE_WAIT_RETRY_COUNT: Int = 50 + val NODE_WAIT_RETRY_COUNT: Int = 100 val NODE_WAIT_RETRY_DELAY_MS: Long = 200 fun ensureNodeStartsOrKill(proc: Process, nodeWebserverAddr: HostAndPort) { From cfe54c5f218cdd09fc408f5c2f874e25f899cba1 Mon Sep 17 00:00:00 2001 From: "rick.parker" Date: Wed, 29 Jun 2016 09:10:18 +0100 Subject: [PATCH 056/114] Fix up bug in attachment Zip file processing when path might not be normalised to start with --- core/src/main/kotlin/com/r3corda/core/Utils.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/src/main/kotlin/com/r3corda/core/Utils.kt b/core/src/main/kotlin/com/r3corda/core/Utils.kt index e453006ec3..73b7f87599 100644 --- a/core/src/main/kotlin/com/r3corda/core/Utils.kt +++ b/core/src/main/kotlin/com/r3corda/core/Utils.kt @@ -11,7 +11,6 @@ import java.io.InputStream import java.math.BigDecimal import java.nio.file.Files import java.nio.file.Path -import java.security.SecureRandom import java.time.Duration import java.time.temporal.Temporal import java.util.concurrent.Executor @@ -177,16 +176,17 @@ class TransientProperty(private val initializer: () -> T) { * Given a path to a zip file, extracts it to the given directory. */ fun extractZipFile(zipPath: Path, toPath: Path) { - if (!Files.exists(toPath)) - Files.createDirectories(toPath) + val normalisedToPath = toPath.normalize() + if (!Files.exists(normalisedToPath)) + Files.createDirectories(normalisedToPath) ZipInputStream(BufferedInputStream(Files.newInputStream(zipPath))).use { zip -> while (true) { val e = zip.nextEntry ?: break - val outPath = toPath.resolve(e.name) + val outPath = normalisedToPath.resolve(e.name) // Security checks: we should reject a zip that contains tricksy paths that try to escape toPath. - if (!outPath.normalize().startsWith(toPath)) + if (!outPath.normalize().startsWith(normalisedToPath)) throw IllegalStateException("ZIP contained a path that resolved incorrectly: ${e.name}") if (e.isDirectory) { From dc304199c8192d4f808b755f382e0da093f320ee Mon Sep 17 00:00:00 2001 From: Ross Nicoll Date: Tue, 28 Jun 2016 11:12:52 +0100 Subject: [PATCH 057/114] Remove warnings from Obligation contract --- .../main/kotlin/com/r3corda/contracts/Obligation.kt | 12 +++++------- .../com/r3corda/contracts/cash/FungibleAssetState.kt | 2 +- .../kotlin/com/r3corda/contracts/ObligationTests.kt | 11 +++++++---- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/contracts/src/main/kotlin/com/r3corda/contracts/Obligation.kt b/contracts/src/main/kotlin/com/r3corda/contracts/Obligation.kt index cb1504a428..e5c25dcb14 100644 --- a/contracts/src/main/kotlin/com/r3corda/contracts/Obligation.kt +++ b/contracts/src/main/kotlin/com/r3corda/contracts/Obligation.kt @@ -153,8 +153,8 @@ class Obligation

: Contract { override val owner: PublicKey get() = beneficiary - override fun move(amount: Amount

, beneficiary: PublicKey): Obligation.State

- = copy(quantity = amount.quantity, beneficiary = beneficiary) + override fun move(newAmount: Amount

, newOwner: PublicKey): Obligation.State

+ = copy(quantity = newAmount.quantity, beneficiary = newOwner) override fun toString() = when (lifecycle) { Lifecycle.NORMAL -> "${Emoji.bagOfCash}Debt($amount due $dueBefore to ${beneficiary.toStringShort()})" @@ -272,13 +272,12 @@ class Obligation

: Contract { for ((inputs, outputs, key) in groups) { // Either inputs or outputs could be empty. val obligor = key.obligor - val commands = commandGroups[key] ?: emptyList() requireThat { "there are no zero sized outputs" by outputs.none { it.amount.quantity == 0L } } - verifyCommandGroup(tx, commands, inputs, outputs, obligor, key) + verifyCommandGroup(tx, commandGroups[key] ?: emptyList(), inputs, outputs, obligor, key) } } } @@ -318,7 +317,7 @@ class Obligation

: Contract { "all outputs are in the normal state " by outputs.all { it.lifecycle == Lifecycle.NORMAL } } if (issueCommand != null) { - verifyIssueCommand(inputs, outputs, tx, issueCommand, issued, obligor) + verifyIssueCommand(inputs, outputs, issueCommand, issued, obligor) } else if (settleCommand != null) { // Perhaps through an abundance of caution, settlement is enforced as its own command. // This could perhaps be merged into verifyBalanceChange() later, however doing so introduces a lot @@ -414,7 +413,6 @@ class Obligation

: Contract { @VisibleForTesting protected fun verifyIssueCommand(inputs: List>, outputs: List>, - tx: TransactionForContract, issueCommand: AuthenticatedObject>, issued: Issued

, obligor: Party) { @@ -794,7 +792,7 @@ fun

sumAmountsDue(balances: Map, Amount

>): Map // Strip zero balances val iterator = sum.iterator() while (iterator.hasNext()) { - val (key, amount) = iterator.next() + val amount = iterator.next().value if (amount == 0L) { iterator.remove() } diff --git a/contracts/src/main/kotlin/com/r3corda/contracts/cash/FungibleAssetState.kt b/contracts/src/main/kotlin/com/r3corda/contracts/cash/FungibleAssetState.kt index b2641d5d99..28a85c173e 100644 --- a/contracts/src/main/kotlin/com/r3corda/contracts/cash/FungibleAssetState.kt +++ b/contracts/src/main/kotlin/com/r3corda/contracts/cash/FungibleAssetState.kt @@ -11,5 +11,5 @@ import java.security.PublicKey interface FungibleAssetState : OwnableState { val issuanceDef: I val productAmount: Amount - fun move(amount: Amount, owner: PublicKey): FungibleAssetState + fun move(newAmount: Amount, newOwner: PublicKey): FungibleAssetState } \ No newline at end of file diff --git a/contracts/src/test/kotlin/com/r3corda/contracts/ObligationTests.kt b/contracts/src/test/kotlin/com/r3corda/contracts/ObligationTests.kt index 6f264bc5df..3a9f9e1fdd 100644 --- a/contracts/src/test/kotlin/com/r3corda/contracts/ObligationTests.kt +++ b/contracts/src/test/kotlin/com/r3corda/contracts/ObligationTests.kt @@ -116,10 +116,13 @@ class ObligationTests { Obligation().generateIssue(ptx, MINI_CORP, megaCorpDollarSettlement, 100.DOLLARS.quantity, beneficiary = DUMMY_PUBKEY_1, notary = DUMMY_NOTARY) assertTrue(ptx.inputStates().isEmpty()) - val s = ptx.outputStates()[0].data as Obligation.State - assertEquals(100.DOLLARS, s.amount) - assertEquals(MINI_CORP, s.obligor) - assertEquals(DUMMY_PUBKEY_1, s.beneficiary) + val expected = Obligation.State( + obligor = MINI_CORP, + quantity = 100.DOLLARS.quantity, + beneficiary = DUMMY_PUBKEY_1, + template = megaCorpDollarSettlement + ) + assertEquals(ptx.outputStates()[0].data, expected) assertTrue(ptx.commands()[0].value is Obligation.Commands.Issue<*>) assertEquals(MINI_CORP_PUBKEY, ptx.commands()[0].signers[0]) From d29dd121ffa2cb31fab6bd96c28391c2e2340f0d Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Wed, 29 Jun 2016 13:58:19 +0100 Subject: [PATCH 058/114] integtest: Change timestamp format to be compatible with Windows --- .../kotlin/com/r3corda/core/testing/utilities/TestTimestamp.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/integration-test/kotlin/com/r3corda/core/testing/utilities/TestTimestamp.kt b/src/integration-test/kotlin/com/r3corda/core/testing/utilities/TestTimestamp.kt index 43bde8be70..b620d54524 100644 --- a/src/integration-test/kotlin/com/r3corda/core/testing/utilities/TestTimestamp.kt +++ b/src/integration-test/kotlin/com/r3corda/core/testing/utilities/TestTimestamp.kt @@ -11,7 +11,7 @@ class TestTimestamp { companion object { val timestamp: String = { val tz = TimeZone.getTimeZone("UTC") - val df = SimpleDateFormat("yyyy-MM-dd-HH:mm:ss") + val df = SimpleDateFormat("yyyyMMddHHmmss") df.timeZone = tz df.format(Date()) }() From dd9a653ab48ca18e552bb3f387a5be9c0a5a5ffd Mon Sep 17 00:00:00 2001 From: Andrius Dagys Date: Wed, 29 Jun 2016 16:32:29 +0100 Subject: [PATCH 059/114] TransactionBuilder: added a comment explaining the default notary parameter purpose --- .../kotlin/com/r3corda/core/contracts/TransactionBuilder.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/src/main/kotlin/com/r3corda/core/contracts/TransactionBuilder.kt b/core/src/main/kotlin/com/r3corda/core/contracts/TransactionBuilder.kt index b66803898f..0d80a1cc92 100644 --- a/core/src/main/kotlin/com/r3corda/core/contracts/TransactionBuilder.kt +++ b/core/src/main/kotlin/com/r3corda/core/contracts/TransactionBuilder.kt @@ -15,6 +15,10 @@ import java.util.* * * The builder can be customised for specific transaction types, e.g. where additional processing is needed * before adding a state/command. + * + * @param notary The default notary that will be used for outputs that don't have a notary specified. When this is set, + * an output state can be added by just passing in a [ContractState] – a [TransactionState] with the + * default notary will be generated automatically. */ abstract class TransactionBuilder(protected val type: TransactionType = TransactionType.General(), protected val notary: Party? = null) { @@ -129,6 +133,7 @@ abstract class TransactionBuilder(protected val type: TransactionType = Transact fun addOutputState(state: ContractState, notary: Party) = addOutputState(TransactionState(state, notary)) + /** A default notary must be specified during builder construction to use this method */ fun addOutputState(state: ContractState) { checkNotNull(notary) { "Need to specify a Notary for the state, or set a default one on TransactionBuilder initialisation" } addOutputState(state, notary!!) From 779034691e8045f8d802459d072427771a751f1d Mon Sep 17 00:00:00 2001 From: Ross Nicoll Date: Wed, 29 Jun 2016 13:07:28 +0100 Subject: [PATCH 060/114] Add AbstractTransactionSubstitutionProtocol Abstracts the NotaryChangeProtocol to be extensible for other use-cases. --- .../AbstractStateReplacementProtocol.kt | 244 ++++++++++++++++++ .../kotlin/protocols/NotaryChangeProtocol.kt | 222 ++-------------- .../node/services/NotaryChangeService.kt | 5 +- .../kotlin/node/services/NotaryChangeTests.kt | 8 +- 4 files changed, 278 insertions(+), 201 deletions(-) create mode 100644 core/src/main/kotlin/protocols/AbstractStateReplacementProtocol.kt diff --git a/core/src/main/kotlin/protocols/AbstractStateReplacementProtocol.kt b/core/src/main/kotlin/protocols/AbstractStateReplacementProtocol.kt new file mode 100644 index 0000000000..d1dbd6b7be --- /dev/null +++ b/core/src/main/kotlin/protocols/AbstractStateReplacementProtocol.kt @@ -0,0 +1,244 @@ +package protocols + +import co.paralleluniverse.fibers.Suspendable +import com.r3corda.core.contracts.* +import com.r3corda.core.crypto.DigitalSignature +import com.r3corda.core.crypto.Party +import com.r3corda.core.crypto.signWithECDSA +import com.r3corda.core.messaging.Ack +import com.r3corda.core.messaging.SingleMessageRecipient +import com.r3corda.core.node.NodeInfo +import com.r3corda.core.protocols.ProtocolLogic +import com.r3corda.core.random63BitValue +import com.r3corda.core.utilities.ProgressTracker +import com.r3corda.protocols.AbstractRequestMessage +import com.r3corda.protocols.NotaryProtocol +import com.r3corda.protocols.ResolveTransactionsProtocol +import java.security.PublicKey + +/** + * Abstract protocol to be used for replacing one state with another, for example when changing the notary of a state. + * Notably this requires a one to one replacement of states, states cannot be split, merged or issued as part of these + * protocols. + * + * The [Instigator] assembles the transaction for state replacement and sends out change proposals to all participants + * ([Acceptor]) of that state. If participants agree to the proposed change, they each sign the transaction. + * 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 AbstractStateReplacementProtocol { + interface Proposal { + val stateRef: StateRef + val modification: T + val stx: SignedTransaction + } + + class Handshake(val sessionIdForSend: Long, + replyTo: SingleMessageRecipient, + replySessionId: Long) : AbstractRequestMessage(replyTo, replySessionId) + + abstract class Instigator(val originalState: StateAndRef, + val modification: T, + override val progressTracker: ProgressTracker = tracker()) : ProtocolLogic>() { + companion object { + + object SIGNING : ProgressTracker.Step("Requesting signatures from other parties") + + object NOTARY : ProgressTracker.Step("Requesting notary signature") + + fun tracker() = ProgressTracker(SIGNING, NOTARY) + } + + abstract val TOPIC_CHANGE: String + abstract val TOPIC_INITIATE: String + + @Suspendable + override fun call(): StateAndRef { + val (stx, participants) = assembleTx() + + progressTracker.currentStep = SIGNING + + val myKey = serviceHub.storageService.myLegalIdentity.owningKey + val me = listOf(myKey) + + val signatures = if (participants == me) { + listOf(getNotarySignature(stx)) + } else { + collectSignatures(participants - me, stx) + } + + val finalTx = stx + signatures + serviceHub.recordTransactions(listOf(finalTx)) + return finalTx.tx.outRef(0) + } + + abstract internal fun assembleProposal(stateRef: StateRef, modification: T, stx: SignedTransaction): Proposal + abstract internal fun assembleTx(): Pair> + + @Suspendable + private fun collectSignatures(participants: List, stx: SignedTransaction): List { + val sessions = mutableMapOf() + + val participantSignatures = participants.map { + val participantNode = serviceHub.networkMapCache.getNodeByPublicKey(it) ?: + throw IllegalStateException("Participant $it to state $originalState not found on the network") + val sessionIdForSend = random63BitValue() + sessions[participantNode] = sessionIdForSend + + getParticipantSignature(participantNode, stx, sessionIdForSend) + } + + val allSignatures = participantSignatures + getNotarySignature(stx) + sessions.forEach { send(TOPIC_CHANGE, it.key.address, it.value, allSignatures) } + + return allSignatures + } + + @Suspendable + private fun getParticipantSignature(node: NodeInfo, stx: SignedTransaction, sessionIdForSend: Long): DigitalSignature.WithKey { + val sessionIdForReceive = random63BitValue() + val proposal = assembleProposal(originalState.ref, modification, stx) + + val handshake = Handshake(sessionIdForSend, serviceHub.networkService.myAddress, sessionIdForReceive) + sendAndReceive(TOPIC_INITIATE, node.address, 0, sessionIdForReceive, handshake) + + val response = sendAndReceive(TOPIC_CHANGE, node.address, sessionIdForSend, sessionIdForReceive, proposal) + val participantSignature = response.validate { + if (it.sig == null) throw StateReplacementException(it.error!!) + else { + check(it.sig.by == node.identity.owningKey) { "Not signed by the required participant" } + it.sig.verifyWithECDSA(stx.txBits) + it.sig + } + } + + return participantSignature + } + + @Suspendable + private fun getNotarySignature(stx: SignedTransaction): DigitalSignature.LegallyIdentifiable { + progressTracker.currentStep = NOTARY + return subProtocol(NotaryProtocol.Client(stx)) + } + } + + abstract class Acceptor(val otherSide: SingleMessageRecipient, + val sessionIdForSend: Long, + val sessionIdForReceive: Long, + override val progressTracker: ProgressTracker = tracker()) : ProtocolLogic() { + + 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) + } + + abstract val TOPIC_CHANGE: String + abstract val TOPIC_INITIATE: String + + @Suspendable + override fun call() { + progressTracker.currentStep = VERIFYING + val proposal = receive>(TOPIC_CHANGE, sessionIdForReceive).validate { it } + + try { + verifyProposal(proposal) + verifyTx(proposal.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.storageService.myLegalIdentity + val state = proposal.stateRef + val reason = StateReplacementRefused(myIdentity, state, e.message) + + reject(reason) + return + } + + approve(proposal.stx) + } + + @Suspendable + private fun approve(stx: SignedTransaction) { + progressTracker.currentStep = APPROVING + + val mySignature = sign(stx) + val response = Result.noError(mySignature) + val swapSignatures = sendAndReceive>(TOPIC_CHANGE, otherSide, sessionIdForSend, sessionIdForReceive, response) + + val allSignatures = swapSignatures.validate { signatures -> + signatures.forEach { it.verifyWithECDSA(stx.txBits) } + signatures + } + + val finalTx = stx + allSignatures + finalTx.verify() + serviceHub.recordTransactions(listOf(finalTx)) + } + + @Suspendable + private fun reject(e: StateReplacementRefused) { + progressTracker.currentStep = REJECTING + val response = Result.withError(e) + send(TOPIC_CHANGE, otherSide, sessionIdForSend, 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). + */ + abstract internal fun verifyProposal(proposal: Proposal) + + @Suspendable + private fun verifyTx(stx: SignedTransaction) { + checkMySignatureRequired(stx.tx) + checkDependenciesValid(stx) + checkValid(stx) + } + + private fun checkMySignatureRequired(tx: WireTransaction) { + // TODO: use keys from the keyManagementService instead + val myKey = serviceHub.storageService.myLegalIdentity.owningKey + require(tx.signers.contains(myKey)) { "Party is not a participant for any of the input states of transaction ${tx.id}" } + } + + @Suspendable + private fun checkDependenciesValid(stx: SignedTransaction) { + val dependencyTxIDs = stx.tx.inputs.map { it.txhash }.toSet() + subProtocol(ResolveTransactionsProtocol(dependencyTxIDs, otherSide)) + } + + private fun checkValid(stx: SignedTransaction) { + val ltx = stx.tx.toLedgerTransaction(serviceHub.identityService, serviceHub.storageService.attachments) + serviceHub.verifyTransaction(ltx) + } + + private fun sign(stx: SignedTransaction): DigitalSignature.WithKey { + val myKeyPair = serviceHub.storageService.myLegalIdentityKey + return myKeyPair.signWithECDSA(stx.txBits) + } + } + + // TODO: similar classes occur in other places (NotaryProtocol), 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 proposed the state replacement */ +class StateReplacementRefused(val identity: Party, val state: StateRef, val detail: String?) { + override fun toString(): String + = "A participant $identity refused to change state $state" +} + +class StateReplacementException(val error: StateReplacementRefused) +: Exception("State change failed - ${error}") \ No newline at end of file diff --git a/core/src/main/kotlin/protocols/NotaryChangeProtocol.kt b/core/src/main/kotlin/protocols/NotaryChangeProtocol.kt index b820b45abd..2caf6069c2 100644 --- a/core/src/main/kotlin/protocols/NotaryChangeProtocol.kt +++ b/core/src/main/kotlin/protocols/NotaryChangeProtocol.kt @@ -25,53 +25,30 @@ import java.security.PublicKey * 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 NotaryChangeProtocol { +object NotaryChangeProtocol: AbstractStateReplacementProtocol() { val TOPIC_INITIATE = "platform.notary.change.initiate" val TOPIC_CHANGE = "platform.notary.change.execute" - data class Proposal(val stateRef: StateRef, - val newNotary: Party, - val stx: SignedTransaction) + data class Proposal(override val stateRef: StateRef, + override val modification: Party, + override val stx: SignedTransaction) : AbstractStateReplacementProtocol.Proposal - class Handshake(val sessionIdForSend: Long, - replyTo: SingleMessageRecipient, - replySessionId: Long) : AbstractRequestMessage(replyTo, replySessionId) + class Instigator(originalState: StateAndRef, + newNotary: Party, + progressTracker: ProgressTracker = tracker()) + : AbstractStateReplacementProtocol.Instigator(originalState, newNotary, progressTracker) { - class Instigator(val originalState: StateAndRef, - val newNotary: Party, - override val progressTracker: ProgressTracker = tracker()) : ProtocolLogic>() { - companion object { + override val TOPIC_CHANGE: String + get() = NotaryChangeProtocol.TOPIC_CHANGE + override val TOPIC_INITIATE: String + get() = NotaryChangeProtocol.TOPIC_INITIATE - object SIGNING : ProgressTracker.Step("Requesting signatures from other parties") + override fun assembleProposal(stateRef: StateRef, modification: Party, stx: SignedTransaction): AbstractStateReplacementProtocol.Proposal + = NotaryChangeProtocol.Proposal(stateRef, modification, stx) - object NOTARY : ProgressTracker.Step("Requesting current Notary signature") - - fun tracker() = ProgressTracker(SIGNING, NOTARY) - } - - @Suspendable - override fun call(): StateAndRef { - val (stx, participants) = assembleTx() - - progressTracker.currentStep = SIGNING - - val myKey = serviceHub.storageService.myLegalIdentity.owningKey - val me = listOf(myKey) - - val signatures = if (participants == me) { - listOf(getNotarySignature(stx)) - } else { - collectSignatures(participants - me, stx) - } - - val finalTx = stx + signatures - serviceHub.recordTransactions(listOf(finalTx)) - return finalTx.tx.outRef(0) - } - - private fun assembleTx(): Pair> { + override fun assembleTx(): Pair> { val state = originalState.state - val newState = state.withNewNotary(newNotary) + val newState = state.withNewNotary(modification) val participants = state.data.participants val tx = TransactionType.NotaryChange.Builder().withItems(originalState, newState) tx.signWith(serviceHub.storageService.myLegalIdentityKey) @@ -79,116 +56,17 @@ object NotaryChangeProtocol { val stx = tx.toSignedTransaction(false) return Pair(stx, participants) } - - @Suspendable - private fun collectSignatures(participants: List, stx: SignedTransaction): List { - val sessions = mutableMapOf() - - val participantSignatures = participants.map { - val participantNode = serviceHub.networkMapCache.getNodeByPublicKey(it) ?: - throw IllegalStateException("Participant $it to state $originalState not found on the network") - val sessionIdForSend = random63BitValue() - sessions[participantNode] = sessionIdForSend - - getParticipantSignature(participantNode, stx, sessionIdForSend) - } - - val allSignatures = participantSignatures + getNotarySignature(stx) - sessions.forEach { send(TOPIC_CHANGE, it.key.address, it.value, allSignatures) } - - return allSignatures - } - - @Suspendable - private fun getParticipantSignature(node: NodeInfo, stx: SignedTransaction, sessionIdForSend: Long): DigitalSignature.WithKey { - val sessionIdForReceive = random63BitValue() - val proposal = Proposal(originalState.ref, newNotary, stx) - - val handshake = Handshake(sessionIdForSend, serviceHub.networkService.myAddress, sessionIdForReceive) - sendAndReceive(TOPIC_INITIATE, node.address, 0, sessionIdForReceive, handshake) - - val response = sendAndReceive(TOPIC_CHANGE, node.address, sessionIdForSend, sessionIdForReceive, proposal) - val participantSignature = response.validate { - if (it.sig == null) throw NotaryChangeException(it.error!!) - else { - check(it.sig.by == node.identity.owningKey) { "Not signed by the required participant" } - it.sig.verifyWithECDSA(stx.txBits) - it.sig - } - } - - return participantSignature - } - - @Suspendable - private fun getNotarySignature(stx: SignedTransaction): DigitalSignature.LegallyIdentifiable { - progressTracker.currentStep = NOTARY - return subProtocol(NotaryProtocol.Client(stx)) - } } - class Acceptor(val otherSide: SingleMessageRecipient, - val sessionIdForSend: Long, - val sessionIdForReceive: Long, - override val progressTracker: ProgressTracker = tracker()) : ProtocolLogic() { - - companion object { - object VERIFYING : ProgressTracker.Step("Verifying Notary change proposal") - - object APPROVING : ProgressTracker.Step("Notary change approved") - - object REJECTING : ProgressTracker.Step("Notary change rejected") - - fun tracker() = ProgressTracker(VERIFYING, APPROVING, REJECTING) - } - - @Suspendable - override fun call() { - progressTracker.currentStep = VERIFYING - val proposal = receive(TOPIC_CHANGE, sessionIdForReceive).validate { it } - - try { - verifyProposal(proposal) - verifyTx(proposal.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.storageService.myLegalIdentity - val state = proposal.stateRef - val reason = NotaryChangeRefused(myIdentity, state, e.message) - - reject(reason) - return - } - - approve(proposal.stx) - } - - @Suspendable - private fun approve(stx: SignedTransaction) { - progressTracker.currentStep = APPROVING - - val mySignature = sign(stx) - val response = Result.noError(mySignature) - val swapSignatures = sendAndReceive>(TOPIC_CHANGE, otherSide, sessionIdForSend, sessionIdForReceive, response) - - val allSignatures = swapSignatures.validate { signatures -> - signatures.forEach { it.verifyWithECDSA(stx.txBits) } - signatures - } - - val finalTx = stx + allSignatures - finalTx.verify() - serviceHub.recordTransactions(listOf(finalTx)) - } - - @Suspendable - private fun reject(e: NotaryChangeRefused) { - progressTracker.currentStep = REJECTING - val response = Result.withError(e) - send(TOPIC_CHANGE, otherSide, sessionIdForSend, response) - } + class Acceptor(otherSide: SingleMessageRecipient, + sessionIdForSend: Long, + sessionIdForReceive: Long, + override val progressTracker: ProgressTracker = tracker()) + : AbstractStateReplacementProtocol.Acceptor(otherSide, sessionIdForSend, sessionIdForReceive) { + override val TOPIC_CHANGE: String + get() = NotaryChangeProtocol.TOPIC_CHANGE + override val TOPIC_INITIATE: String + get() = NotaryChangeProtocol.TOPIC_INITIATE /** * Check the notary change proposal. @@ -198,8 +76,8 @@ object NotaryChangeProtocol { * TODO: In more difficult cases this should call for human attention to manually verify and approve the proposal */ @Suspendable - private fun verifyProposal(proposal: NotaryChangeProtocol.Proposal) { - val newNotary = proposal.newNotary + override fun verifyProposal(proposal: AbstractStateReplacementProtocol.Proposal) { + val newNotary = proposal.modification val isNotary = serviceHub.networkMapCache.notaryNodes.any { it.identity == newNotary } require(isNotary) { "The proposed node $newNotary does not run a Notary service " } @@ -211,51 +89,5 @@ object NotaryChangeProtocol { val blacklist = listOf("Evil Notary") require(!blacklist.contains(newNotary.name)) { "The proposed new notary $newNotary is not trusted by the party" } } - - @Suspendable - private fun verifyTx(stx: SignedTransaction) { - checkMySignatureRequired(stx.tx) - checkDependenciesValid(stx) - checkValid(stx) - } - - private fun checkMySignatureRequired(tx: WireTransaction) { - // TODO: use keys from the keyManagementService instead - val myKey = serviceHub.storageService.myLegalIdentity.owningKey - require(tx.signers.contains(myKey)) { "Party is not a participant for any of the input states of transaction ${tx.id}" } - } - - @Suspendable - private fun checkDependenciesValid(stx: SignedTransaction) { - val dependencyTxIDs = stx.tx.inputs.map { it.txhash }.toSet() - subProtocol(ResolveTransactionsProtocol(dependencyTxIDs, otherSide)) - } - - private fun checkValid(stx: SignedTransaction) { - val ltx = stx.tx.toLedgerTransaction(serviceHub.identityService, serviceHub.storageService.attachments) - serviceHub.verifyTransaction(ltx) - } - - private fun sign(stx: SignedTransaction): DigitalSignature.WithKey { - val myKeyPair = serviceHub.storageService.myLegalIdentityKey - return myKeyPair.signWithECDSA(stx.txBits) - } } - - // TODO: similar classes occur in other places (NotaryProtocol), need to consolidate - data class Result private constructor(val sig: DigitalSignature.WithKey?, val error: NotaryChangeRefused?) { - companion object { - fun withError(error: NotaryChangeRefused) = Result(null, error) - fun noError(sig: DigitalSignature.WithKey) = Result(sig, null) - } - } -} - -/** Thrown when a participant refuses to change the notary of the state */ -class NotaryChangeRefused(val identity: Party, val state: StateRef, val cause: String?) { - override fun toString() = "A participant $identity refused to change the notary of state $state" -} - -class NotaryChangeException(val error: NotaryChangeRefused) : Exception() { - override fun toString() = "${super.toString()}: Notary change failed - ${error.toString()}" } \ No newline at end of file diff --git a/node/src/main/kotlin/com/r3corda/node/services/NotaryChangeService.kt b/node/src/main/kotlin/com/r3corda/node/services/NotaryChangeService.kt index ab0b6581aa..6e0378c52f 100644 --- a/node/src/main/kotlin/com/r3corda/node/services/NotaryChangeService.kt +++ b/node/src/main/kotlin/com/r3corda/node/services/NotaryChangeService.kt @@ -5,6 +5,7 @@ import com.r3corda.core.messaging.MessagingService import com.r3corda.core.messaging.SingleMessageRecipient import com.r3corda.node.services.api.AbstractNodeService import com.r3corda.node.services.statemachine.StateMachineManager +import protocols.AbstractStateReplacementProtocol import protocols.NotaryChangeProtocol /** @@ -14,11 +15,11 @@ import protocols.NotaryChangeProtocol class NotaryChangeService(net: MessagingService, val smm: StateMachineManager) : AbstractNodeService(net) { init { addMessageHandler(NotaryChangeProtocol.TOPIC_INITIATE, - { req: NotaryChangeProtocol.Handshake -> handleChangeNotaryRequest(req) } + { req: AbstractStateReplacementProtocol.Handshake -> handleChangeNotaryRequest(req) } ) } - private fun handleChangeNotaryRequest(req: NotaryChangeProtocol.Handshake): Ack { + private fun handleChangeNotaryRequest(req: AbstractStateReplacementProtocol.Handshake): Ack { val protocol = NotaryChangeProtocol.Acceptor( req.replyTo as SingleMessageRecipient, req.sessionID!!, diff --git a/node/src/test/kotlin/node/services/NotaryChangeTests.kt b/node/src/test/kotlin/node/services/NotaryChangeTests.kt index 4059a1dcd9..d89eae2ad5 100644 --- a/node/src/test/kotlin/node/services/NotaryChangeTests.kt +++ b/node/src/test/kotlin/node/services/NotaryChangeTests.kt @@ -11,10 +11,10 @@ import com.r3corda.node.services.network.NetworkMapService import com.r3corda.node.services.transactions.SimpleNotaryService import org.junit.Before import org.junit.Test -import protocols.NotaryChangeException +import protocols.StateReplacementException +import protocols.StateReplacementRefused import protocols.NotaryChangeProtocol import protocols.NotaryChangeProtocol.Instigator -import protocols.NotaryChangeRefused import java.util.concurrent.ExecutionException import kotlin.test.assertEquals import kotlin.test.assertFailsWith @@ -80,8 +80,8 @@ class NotaryChangeTests { net.runNetwork() val ex = assertFailsWith(ExecutionException::class) { future.get() } - val error = (ex.cause as NotaryChangeException).error - assertTrue(error is NotaryChangeRefused) + val error = (ex.cause as StateReplacementException).error + assertTrue(error is StateReplacementRefused) } // TODO: Add more test cases once we have a general protocol/service exception handling mechanism: From c767638127d497fb726cc4aa67731394e37dd432 Mon Sep 17 00:00:00 2001 From: Ross Nicoll Date: Wed, 29 Jun 2016 14:51:35 +0100 Subject: [PATCH 061/114] Move DummyContract.State into its own file DummyContract.State isn't actually used by the DummyContract any more, so shouldn't be part of that contract class. --- .../com/r3corda/contracts/testing/TestUtils.kt | 5 +++-- .../com/r3corda/contracts/ObligationTests.kt | 2 +- .../com/r3corda/contracts/cash/CashTests.kt | 2 +- .../r3corda/core/contracts/DummyContract.kt | 18 +++++++++++------- .../com/r3corda/core/contracts/DummyState.kt | 12 ++++++++++++ .../contracts/TransactionGraphSearchTests.kt | 4 ++-- 6 files changed, 30 insertions(+), 13 deletions(-) create mode 100644 core/src/main/kotlin/com/r3corda/core/contracts/DummyState.kt diff --git a/contracts/src/main/kotlin/com/r3corda/contracts/testing/TestUtils.kt b/contracts/src/main/kotlin/com/r3corda/contracts/testing/TestUtils.kt index f0f0ef36f0..f3bc5eab21 100644 --- a/contracts/src/main/kotlin/com/r3corda/contracts/testing/TestUtils.kt +++ b/contracts/src/main/kotlin/com/r3corda/contracts/testing/TestUtils.kt @@ -5,11 +5,12 @@ import com.r3corda.contracts.cash.CASH_PROGRAM_ID import com.r3corda.contracts.cash.Cash import com.r3corda.core.contracts.Amount import com.r3corda.core.contracts.Contract +import com.r3corda.core.contracts.ContractState import com.r3corda.core.contracts.DUMMY_PROGRAM_ID import com.r3corda.core.contracts.DummyContract +import com.r3corda.core.contracts.DummyState import com.r3corda.core.contracts.PartyAndReference import com.r3corda.core.contracts.Issued -import com.r3corda.core.contracts.ContractState import com.r3corda.core.contracts.TransactionState import com.r3corda.core.crypto.NullPublicKey import com.r3corda.core.crypto.Party @@ -31,7 +32,7 @@ val TEST_PROGRAM_MAP: Map> = mapOf( IRS_PROGRAM_ID to InterestRateSwap::class.java ) -fun generateState() = DummyContract.State(Random().nextInt()) +fun generateState() = DummyState(Random().nextInt()) //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // diff --git a/contracts/src/test/kotlin/com/r3corda/contracts/ObligationTests.kt b/contracts/src/test/kotlin/com/r3corda/contracts/ObligationTests.kt index 3a9f9e1fdd..c9ba546142 100644 --- a/contracts/src/test/kotlin/com/r3corda/contracts/ObligationTests.kt +++ b/contracts/src/test/kotlin/com/r3corda/contracts/ObligationTests.kt @@ -80,7 +80,7 @@ class ObligationTests { fun `issue debt`() { // Check we can't "move" debt into existence. transaction { - input { DummyContract.State() } + input { DummyState() } output { outState } arg(MINI_CORP_PUBKEY) { Obligation.Commands.Move(outState.issuanceDef) } diff --git a/contracts/src/test/kotlin/com/r3corda/contracts/cash/CashTests.kt b/contracts/src/test/kotlin/com/r3corda/contracts/cash/CashTests.kt index 0b0e355720..000a7bb959 100644 --- a/contracts/src/test/kotlin/com/r3corda/contracts/cash/CashTests.kt +++ b/contracts/src/test/kotlin/com/r3corda/contracts/cash/CashTests.kt @@ -66,7 +66,7 @@ class CashTests { fun issueMoney() { // Check we can't "move" money into existence. transaction { - input { DummyContract.State() } + input { DummyState() } output { outState } arg(MINI_CORP_PUBKEY) { Cash.Commands.Move() } diff --git a/core/src/main/kotlin/com/r3corda/core/contracts/DummyContract.kt b/core/src/main/kotlin/com/r3corda/core/contracts/DummyContract.kt index 41038e128b..66358cebd5 100644 --- a/core/src/main/kotlin/com/r3corda/core/contracts/DummyContract.kt +++ b/core/src/main/kotlin/com/r3corda/core/contracts/DummyContract.kt @@ -9,13 +9,12 @@ import java.security.PublicKey val DUMMY_PROGRAM_ID = DummyContract() class DummyContract : Contract { - data class State(val magicNumber: Int = 0) : ContractState { - override val contract = DUMMY_PROGRAM_ID - override val participants: List - get() = emptyList() + + interface State : ContractState { + val magicNumber: Int } - data class SingleOwnerState(val magicNumber: Int = 0, override val owner: PublicKey) : OwnableState { + data class SingleOwnerState(override val magicNumber: Int = 0, override val owner: PublicKey) : OwnableState, State { override val contract = DUMMY_PROGRAM_ID override val participants: List get() = listOf(owner) @@ -23,8 +22,13 @@ class DummyContract : Contract { override fun withNewOwner(newOwner: PublicKey) = Pair(Commands.Move(), copy(owner = newOwner)) } - data class MultiOwnerState(val magicNumber: Int = 0, - val owners: List) : ContractState { + /** + * Alternative state with multiple owners. This exists primarily to provide a dummy state with multiple + * participants, and could in theory be merged with [SingleOwnerState] by putting the additional participants + * in a different field, however this is a good example of a contract with multiple states. + */ + data class MultiOwnerState(override val magicNumber: Int = 0, + val owners: List) : ContractState, State { override val contract = DUMMY_PROGRAM_ID override val participants: List get() = owners diff --git a/core/src/main/kotlin/com/r3corda/core/contracts/DummyState.kt b/core/src/main/kotlin/com/r3corda/core/contracts/DummyState.kt new file mode 100644 index 0000000000..1f6fb6df2c --- /dev/null +++ b/core/src/main/kotlin/com/r3corda/core/contracts/DummyState.kt @@ -0,0 +1,12 @@ +package com.r3corda.core.contracts + +import java.security.PublicKey + +/** + * Dummy state for use in testing. Not part of any real contract. + */ +data class DummyState(val magicNumber: Int = 0) : ContractState { + override val contract = DUMMY_PROGRAM_ID + override val participants: List + get() = emptyList() +} \ No newline at end of file diff --git a/core/src/test/kotlin/com/r3corda/core/contracts/TransactionGraphSearchTests.kt b/core/src/test/kotlin/com/r3corda/core/contracts/TransactionGraphSearchTests.kt index 195fde036f..a6630302f3 100644 --- a/core/src/test/kotlin/com/r3corda/core/contracts/TransactionGraphSearchTests.kt +++ b/core/src/test/kotlin/com/r3corda/core/contracts/TransactionGraphSearchTests.kt @@ -28,12 +28,12 @@ class TransactionGraphSearchTests { */ fun buildTransactions(command: CommandData, signer: KeyPair): GraphTransactionStorage { val originTx = TransactionType.General.Builder().apply { - addOutputState(DummyContract.State(random31BitValue()), DUMMY_NOTARY) + addOutputState(DummyState(random31BitValue()), DUMMY_NOTARY) addCommand(command, signer.public) signWith(signer) }.toSignedTransaction(false) val inputTx = TransactionType.General.Builder().apply { - addInputState(originTx.tx.outRef(0)) + addInputState(originTx.tx.outRef(0)) signWith(signer) }.toSignedTransaction(false) return GraphTransactionStorage(originTx, inputTx) From 11eff398a03879a954c4ddc65d5bb1a1fd8b96cb Mon Sep 17 00:00:00 2001 From: Ross Nicoll Date: Wed, 29 Jun 2016 16:58:09 +0100 Subject: [PATCH 062/114] Minor: Typo (classfiles -> class files) --- core/src/main/kotlin/com/r3corda/core/contracts/Structures.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/kotlin/com/r3corda/core/contracts/Structures.kt b/core/src/main/kotlin/com/r3corda/core/contracts/Structures.kt index 66ffcb817c..c68e0012d4 100644 --- a/core/src/main/kotlin/com/r3corda/core/contracts/Structures.kt +++ b/core/src/main/kotlin/com/r3corda/core/contracts/Structures.kt @@ -57,7 +57,7 @@ interface ContractState { * is a miniature file system in which each file can be precisely mapped to the defining attachment. * * Attachments may contain many things (data files, legal documents, etc) but mostly they contain JVM bytecode. - * The classfiles inside define not only [Contract] implementations but also the classes that define the states. + * The class files inside define not only [Contract] implementations but also the classes that define the states. * Within the rest of a transaction, user-providable components are referenced by name only. * * This means that a smart contract in Corda does two things: From 5271882dcdfdf1e1eadc66d20e2acf8555c2f9c7 Mon Sep 17 00:00:00 2001 From: "rick.parker" Date: Tue, 24 May 2016 10:03:29 +0100 Subject: [PATCH 063/114] Event scheduling and docs for event scheduling --- .../main/kotlin/com/r3corda/contracts/IRS.kt | 13 +- .../src/main/kotlin/com/r3corda/core/Utils.kt | 7 +- .../com/r3corda/core/contracts/Structures.kt | 45 +++- .../com/r3corda/core/node/ServiceHub.kt | 1 + .../r3corda/core/node/services/Services.kt | 33 +++ .../r3corda/core/protocols/ProtocolLogic.kt | 8 +- .../core/protocols/ProtocolLogicRef.kt | 163 ++++++++++++ .../com/r3corda/core/utilities/OracleUtils.kt | 19 ++ .../com/r3corda/protocols/RatesFixProtocol.kt | 12 +- .../r3corda/protocols/TwoPartyDealProtocol.kt | 217 +++++++++------ .../ProtocolLogicRefFromJavaTest.java | 42 +++ .../core/protocols/ProtocolLogicRefTest.kt | 80 ++++++ docs/source/event-scheduling.rst | 102 ++++++++ docs/source/index.rst | 1 + .../com/r3corda/node/internal/AbstractNode.kt | 27 +- .../node/internal/testing/IRSSimulation.kt | 54 ++-- .../node/internal/testing/Simulation.kt | 39 ++- .../node/internal/testing/TestClock.kt | 6 + .../node/internal/testing/TradeSimulation.kt | 5 +- .../FixingSessionInitiationHandler.kt | 22 ++ .../node/services/api/ServiceHubInternal.kt | 11 + .../services/clientapi/NodeInterestRates.kt | 96 +++++-- .../services/events/NodeSchedulerService.kt | 177 +++++++++++++ .../events/ScheduledActivityObserver.kt | 35 +++ .../com/r3corda/node/services/MockServices.kt | 20 +- .../node/services/NodeInterestRatesTest.kt | 19 +- .../node/services/NodeSchedulerServiceTest.kt | 247 ++++++++++++++++++ src/main/kotlin/com/r3corda/demos/IRSDemo.kt | 20 +- .../kotlin/com/r3corda/demos/RateFixDemo.kt | 3 +- .../demos/protocols/AutoOfferProtocol.kt | 11 +- .../protocols/UpdateBusinessDayProtocol.kt | 148 +---------- 31 files changed, 1375 insertions(+), 308 deletions(-) create mode 100644 core/src/main/kotlin/com/r3corda/core/protocols/ProtocolLogicRef.kt create mode 100644 core/src/main/kotlin/com/r3corda/core/utilities/OracleUtils.kt create mode 100644 core/src/test/java/com/r3corda/core/protocols/ProtocolLogicRefFromJavaTest.java create mode 100644 core/src/test/kotlin/com/r3corda/core/protocols/ProtocolLogicRefTest.kt create mode 100644 docs/source/event-scheduling.rst create mode 100644 node/src/main/kotlin/com/r3corda/node/services/FixingSessionInitiationHandler.kt create mode 100644 node/src/main/kotlin/com/r3corda/node/services/events/NodeSchedulerService.kt create mode 100644 node/src/main/kotlin/com/r3corda/node/services/events/ScheduledActivityObserver.kt create mode 100644 node/src/test/kotlin/com/r3corda/node/services/NodeSchedulerServiceTest.kt diff --git a/contracts/src/main/kotlin/com/r3corda/contracts/IRS.kt b/contracts/src/main/kotlin/com/r3corda/contracts/IRS.kt index cc09c7d657..33c2c0bb2d 100644 --- a/contracts/src/main/kotlin/com/r3corda/contracts/IRS.kt +++ b/contracts/src/main/kotlin/com/r3corda/contracts/IRS.kt @@ -3,6 +3,9 @@ package com.r3corda.contracts import com.r3corda.core.contracts.* import com.r3corda.core.crypto.Party import com.r3corda.core.crypto.SecureHash +import com.r3corda.core.protocols.ProtocolLogicRefFactory +import com.r3corda.core.utilities.suggestInterestRateAnnouncementTimeWindow +import com.r3corda.protocols.TwoPartyDealProtocol import org.apache.commons.jexl3.JexlBuilder import org.apache.commons.jexl3.MapContext import java.math.BigDecimal @@ -588,7 +591,7 @@ class InterestRateSwap() : Contract { val floatingLeg: FloatingLeg, val calculation: Calculation, val common: Common - ) : FixableDealState { + ) : FixableDealState, SchedulableState { override val contract = IRS_PROGRAM_ID override val thread = SecureHash.sha256(common.tradeID) @@ -604,6 +607,14 @@ class InterestRateSwap() : Contract { override val parties: Array get() = arrayOf(fixedLeg.fixedRatePayer, floatingLeg.floatingRatePayer) + override fun nextScheduledActivity(thisStateRef: StateRef, protocolLogicRefFactory: ProtocolLogicRefFactory): ScheduledActivity? { + val nextFixingOf = nextFixingOf() ?: return null + + // This is perhaps not how we should determine the time point in the business day, but instead expect the schedule to detail some of these aspects + val (instant, duration) = suggestInterestRateAnnouncementTimeWindow(index = nextFixingOf.name, source = floatingLeg.indexSource, date = nextFixingOf.forDay) + return ScheduledActivity(protocolLogicRefFactory.create(TwoPartyDealProtocol.FixingRoleDecider::class.java, thisStateRef, duration), instant) + } + // TODO: This changing of the public key violates the assumption that Party is a fixed identity key. override fun withPublicKey(before: Party, after: PublicKey): DealState { val newParty = Party(before.name, after) diff --git a/core/src/main/kotlin/com/r3corda/core/Utils.kt b/core/src/main/kotlin/com/r3corda/core/Utils.kt index 73b7f87599..4598e15a2a 100644 --- a/core/src/main/kotlin/com/r3corda/core/Utils.kt +++ b/core/src/main/kotlin/com/r3corda/core/Utils.kt @@ -14,7 +14,6 @@ import java.nio.file.Path import java.time.Duration import java.time.temporal.Temporal import java.util.concurrent.Executor -import java.util.concurrent.locks.Lock import java.util.concurrent.locks.ReentrantLock import java.util.zip.ZipInputStream import kotlin.concurrent.withLock @@ -143,9 +142,13 @@ inline fun logElapsedTime(label: String, logger: Logger? = null, body: () -> * * val ii = state.locked { i } */ -class ThreadBox(content: T, val lock: Lock = ReentrantLock()) { +class ThreadBox(content: T, val lock: ReentrantLock = ReentrantLock()) { val content = content inline fun locked(body: T.() -> R): R = lock.withLock { body(content) } + inline fun alreadyLocked(body: T.() -> R): R { + check(lock.isHeldByCurrentThread, { "Expected $lock to already be locked." }) + return body(content) + } } /** diff --git a/core/src/main/kotlin/com/r3corda/core/contracts/Structures.kt b/core/src/main/kotlin/com/r3corda/core/contracts/Structures.kt index c68e0012d4..2048474434 100644 --- a/core/src/main/kotlin/com/r3corda/core/contracts/Structures.kt +++ b/core/src/main/kotlin/com/r3corda/core/contracts/Structures.kt @@ -3,6 +3,8 @@ package com.r3corda.core.contracts import com.r3corda.core.crypto.Party import com.r3corda.core.crypto.SecureHash import com.r3corda.core.crypto.toStringShort +import com.r3corda.core.protocols.ProtocolLogicRef +import com.r3corda.core.protocols.ProtocolLogicRefFactory import com.r3corda.core.serialization.OpaqueBytes import com.r3corda.core.serialization.serialize import java.io.FileNotFoundException @@ -141,6 +143,33 @@ interface OwnableState : ContractState { fun withNewOwner(newOwner: PublicKey): Pair } +/** Something which is scheduled to happen at a point in time */ +interface Scheduled { + val scheduledAt: Instant +} + +/** + * Represents a contract state (unconsumed output) of type [LinearState] and a point in time that a lifecycle event is expected to take place + * for that contract state. + * + * This is effectively the input to a scheduler, which wakes up at that point in time and asks the contract state what + * lifecycle processing needs to take place. e.g. a fixing or a late payment etc. + */ +data class ScheduledStateRef(val ref: StateRef, override val scheduledAt: Instant) : Scheduled + +/** + * This class represents the lifecycle activity that a contract state of type [LinearState] would like to perform at a given point in time. + * e.g. run a fixing protocol + * + * Note the use of [ProtocolLogicRef] to represent a safe way to transport a [ProtocolLogic] out of the contract sandbox. + * + * Currently we support only protocol based activities as we expect there to be a transaction generated off the back of + * the activity, otherwise we have to start tracking secondary state on the platform of which scheduled activities + * for a particular [ContractState] have been processed/fired etc. If the activity is not "on ledger" then the + * scheduled activity shouldn't be either. + */ +data class ScheduledActivity(val logicRef: ProtocolLogicRef, override val scheduledAt: Instant) : Scheduled + /** * A state that evolves by superseding itself, all of which share the common "thread" * @@ -154,12 +183,24 @@ interface LinearState : ContractState { fun isRelevant(ourKeys: Set): Boolean } +interface SchedulableState : ContractState { + /** + * Indicate whether there is some activity to be performed at some future point in time with respect to this + * [ContractState], what that activity is and at what point in time it should be initiated. + * This can be used to implement deadlines for payment or processing of financial instruments according to a schedule. + * + * The state has no reference to it's own StateRef, so supply that for use as input to any ProtocolLogic constructed. + * + * @return null if there is no activity to schedule + */ + fun nextScheduledActivity(thisStateRef: StateRef, protocolLogicRefFactory: ProtocolLogicRefFactory): ScheduledActivity? +} + /** * Interface representing an agreement that exposes various attributes that are common. Implementing it simplifies * implementation of general protocols that manipulate many agreement types. */ interface DealState : LinearState { - /** Human readable well known reference (e.g. trade reference) */ val ref: String @@ -187,8 +228,6 @@ interface DealState : LinearState { interface FixableDealState : DealState { /** * When is the next fixing and what is the fixing for? - * - * TODO: In future we would use this to register for an event to trigger a/the fixing protocol */ fun nextFixingOf(): FixOf? diff --git a/core/src/main/kotlin/com/r3corda/core/node/ServiceHub.kt b/core/src/main/kotlin/com/r3corda/core/node/ServiceHub.kt index 3e80aa0644..893f83a868 100644 --- a/core/src/main/kotlin/com/r3corda/core/node/ServiceHub.kt +++ b/core/src/main/kotlin/com/r3corda/core/node/ServiceHub.kt @@ -20,6 +20,7 @@ interface ServiceHub { val storageService: StorageService val networkService: MessagingService val networkMapCache: NetworkMapCache + val schedulerService: SchedulerService val clock: Clock /** diff --git a/core/src/main/kotlin/com/r3corda/core/node/services/Services.kt b/core/src/main/kotlin/com/r3corda/core/node/services/Services.kt index 8bb335b309..7596967949 100644 --- a/core/src/main/kotlin/com/r3corda/core/node/services/Services.kt +++ b/core/src/main/kotlin/com/r3corda/core/node/services/Services.kt @@ -1,5 +1,7 @@ package com.r3corda.core.node.services +import com.google.common.util.concurrent.ListenableFuture +import com.google.common.util.concurrent.SettableFuture import com.r3corda.core.contracts.* import com.r3corda.core.crypto.Party import com.r3corda.core.crypto.SecureHash @@ -113,6 +115,17 @@ interface WalletService { * the update. */ val updates: rx.Observable + + /** + * Provide a [Future] for when a [StateRef] is consumed, which can be very useful in building tests. + */ + fun whenConsumed(ref: StateRef): ListenableFuture { + val future = SettableFuture.create() + updates.filter { ref in it.consumed }.first().subscribe { + future.set(it) + } + return future + } } inline fun WalletService.linearHeadsOfType() = linearHeadsOfType_(T::class.java) @@ -172,4 +185,24 @@ interface TxWritableStorageService : StorageService { override val validatedTransactions: TransactionStorage } +/** + * Provides access to schedule activity at some point in time. This interface might well be expanded to + * increase the feature set in the future. + * + * If the point in time is in the past, the expectation is that the activity will happen shortly after it is scheduled. + * + * The main consumer initially is an observer of the wallet to schedule activities based on transactions as they are + * recorded. + */ +interface SchedulerService { + /** + * Schedule a new activity for a TX output, probably because it was just produced. + * + * Only one activity can be scheduled for a particular [StateRef] at any one time. Scheduling a [ScheduledStateRef] + * replaces any previously scheduled [ScheduledStateRef] for any one [StateRef]. + */ + fun scheduleStateActivity(action: ScheduledStateRef) + /** Unschedule all activity for a TX output, probably because it was consumed. */ + fun unscheduleStateActivity(ref: StateRef) +} \ No newline at end of file diff --git a/core/src/main/kotlin/com/r3corda/core/protocols/ProtocolLogic.kt b/core/src/main/kotlin/com/r3corda/core/protocols/ProtocolLogic.kt index d602e040ef..0ab15a3be2 100644 --- a/core/src/main/kotlin/com/r3corda/core/protocols/ProtocolLogic.kt +++ b/core/src/main/kotlin/com/r3corda/core/protocols/ProtocolLogic.kt @@ -71,9 +71,15 @@ abstract class ProtocolLogic { private fun maybeWireUpProgressTracking(subLogic: ProtocolLogic<*>) { val ours = progressTracker + val theirs = subLogic.progressTracker - if (ours != null && theirs != null) + if (ours != null && theirs != null) { + if (ours.currentStep == ProgressTracker.UNSTARTED) { + logger.warn("ProgressTracker has not been started for $this") + ours.nextStep() + } ours.setChildProgressTracker(ours.currentStep, theirs) + } } /** diff --git a/core/src/main/kotlin/com/r3corda/core/protocols/ProtocolLogicRef.kt b/core/src/main/kotlin/com/r3corda/core/protocols/ProtocolLogicRef.kt new file mode 100644 index 0000000000..2e8bffb531 --- /dev/null +++ b/core/src/main/kotlin/com/r3corda/core/protocols/ProtocolLogicRef.kt @@ -0,0 +1,163 @@ +package com.r3corda.core.protocols + +import com.google.common.primitives.Primitives +import com.r3corda.core.contracts.StateRef +import com.r3corda.core.crypto.SecureHash +import com.r3corda.core.serialization.SingletonSerializeAsToken +import com.r3corda.protocols.TwoPartyDealProtocol +import java.lang.reflect.ParameterizedType +import java.lang.reflect.Type +import java.time.Duration +import java.util.* +import kotlin.reflect.KFunction +import kotlin.reflect.KParameter +import kotlin.reflect.jvm.javaType +import kotlin.reflect.primaryConstructor + +/** + * A class for conversion to and from [ProtocolLogic] and [ProtocolLogicRef] instances + * + * Validation of types is performed on the way in and way out in case this object is passed between JVMs which might have differing + * whitelists. + * + * TODO: Ways to populate whitelist of "blessed" protocols per node/party + * TODO: Ways to populate argument types whitelist. Per node/party or global? + * TODO: Align with API related logic for passing in ProtocolLogic references (ProtocolRef) + * TODO: Actual support for AppContext / AttachmentsClassLoader + */ +class ProtocolLogicRefFactory(private val protocolLogicClassNameWhitelist: Set, private val argsClassNameWhitelist: Set) : SingletonSerializeAsToken() { + + constructor() : this(setOf(TwoPartyDealProtocol.FixingRoleDecider::class.java.name), setOf(StateRef::class.java.name, Duration::class.java.name)) + + // Pending real dependence on AppContext for class loading etc + @Suppress("UNUSED_PARAMETER") + private fun validateProtocolClassName(className: String, appContext: AppContext) { + // TODO: make this specific to the attachments in the [AppContext] by including [SecureHash] in whitelist check + require(className in protocolLogicClassNameWhitelist) { "${ProtocolLogic::class.java.simpleName} of ${ProtocolLogicRef::class.java.simpleName} must have type on the whitelist: $className" } + } + + // Pending real dependence on AppContext for class loading etc + @Suppress("UNUSED_PARAMETER") + private fun validateArgClassName(className: String, appContext: AppContext) { + // TODO: make this specific to the attachments in the [AppContext] by including [SecureHash] in whitelist check + require(className in argsClassNameWhitelist) { "Args to ${ProtocolLogicRef::class.java.simpleName} must have types on the args whitelist: $className" } + } + + /** + * Create a [ProtocolLogicRef] for the Kotlin primary constructor or Java constructor and the given args. + */ + fun create(type: Class>, vararg args: Any?): ProtocolLogicRef { + val constructor = type.kotlin.primaryConstructor ?: return createJava(type, *args) + if (constructor.parameters.size < args.size) { + throw IllegalProtocolLogicException(type, "due to too many arguments supplied to kotlin primary constructor") + } + // Build map of args from array + val argsMap = args.zip(constructor.parameters).map { Pair(it.second.name!!, it.first) }.toMap() + return createKotlin(type, argsMap) + } + + /** + * Create a [ProtocolLogicRef] by trying to find a Kotlin constructor that matches the given args. + * + * TODO: Rethink language specific naming. + */ + fun createKotlin(type: Class>, args: Map): ProtocolLogicRef { + // TODO: we need to capture something about the class loader or "application context" into the ref, + // perhaps as some sort of ThreadLocal style object. For now, just create an empty one. + val appContext = AppContext(emptyList()) + validateProtocolClassName(type.name, appContext) + // Check we can find a constructor and populate the args to it, but don't call it + createConstructor(appContext, type, args) + return ProtocolLogicRef(type.name, appContext, args) + } + + /** + * Create a [ProtocolLogicRef] by trying to find a Java constructor that matches the given args. + */ + private fun createJava(type: Class>, vararg args: Any?): ProtocolLogicRef { + // Build map for each + val argsMap = HashMap(args.size) + var index = 0 + args.forEach { argsMap["arg${index++}"] = it } + return createKotlin(type, argsMap) + } + + fun toProtocolLogic(ref: ProtocolLogicRef): ProtocolLogic<*> { + validateProtocolClassName(ref.protocolLogicClassName, ref.appContext) + val klass = Class.forName(ref.protocolLogicClassName, true, ref.appContext.classLoader).asSubclass(ProtocolLogic::class.java) + return createConstructor(ref.appContext, klass, ref.args)() + } + + private fun createConstructor(appContext: AppContext, clazz: Class>, args: Map): () -> ProtocolLogic<*> { + for (constructor in clazz.kotlin.constructors) { + val params = buildParams(appContext, constructor, args) ?: continue + // If we get here then we matched every parameter + return { constructor.callBy(params) } + } + throw IllegalProtocolLogicException(clazz, "as could not find matching constructor for: $args") + } + + private fun buildParams(appContext: AppContext, constructor: KFunction>, args: Map): HashMap? { + val params = hashMapOf() + val usedKeys = hashSetOf() + for (parameter in constructor.parameters) { + if (!tryBuildParam(args, parameter, params)) { + return null + } else { + usedKeys += parameter.name!! + } + } + if ((args.keys - usedKeys).isNotEmpty()) { + // Not all args were used + return null + } + params.values.forEach { if (it is Any) validateArgClassName(it.javaClass.name, appContext) } + return params + } + + private fun tryBuildParam(args: Map, parameter: KParameter, params: HashMap): Boolean { + val containsKey = parameter.name in args + // OK to be missing if optional + return (parameter.isOptional && !containsKey) || (containsKey && paramCanBeBuilt(args, parameter, params)) + } + + private fun paramCanBeBuilt(args: Map, parameter: KParameter, params: HashMap): Boolean { + val value = args[parameter.name] + params[parameter] = value + return (value is Any && parameterAssignableFrom(parameter.type.javaType, value)) || parameter.type.isMarkedNullable + } + + private fun parameterAssignableFrom(type: Type, value: Any): Boolean { + if (type is Class<*>) { + if (type.isPrimitive) { + return Primitives.unwrap(value.javaClass) == type + } else { + return type.isAssignableFrom(value.javaClass) + } + } else if (type is ParameterizedType) { + return parameterAssignableFrom(type.rawType, value) + } else { + return false + } + } +} + +class IllegalProtocolLogicException(type: Class<*>, msg: String) : IllegalArgumentException("${ProtocolLogicRef::class.java.simpleName} cannot be constructed for ${ProtocolLogic::class.java.simpleName} of type ${type.name} $msg") + +/** + * A class representing a [ProtocolLogic] instance which would be possible to safely pass out of the contract sandbox + * + * Only allows a String reference to the ProtocolLogic class, and only allows restricted argument types as per [ProtocolLogicRefFactory] + */ +// TODO: align this with the existing [ProtocolRef] in the bank-side API (probably replace some of the API classes) +data class ProtocolLogicRef internal constructor(val protocolLogicClassName: String, val appContext: AppContext, val args: Map) + +/** + * This is just some way to track what attachments need to be in the class loader, but may later include some app + * properties loaded from the attachments. And perhaps the authenticated user for an API call? + */ +data class AppContext(val attachments: List) { + // TODO: build a real [AttachmentsClassLoader] etc + val classLoader: ClassLoader + get() = this.javaClass.classLoader +} \ No newline at end of file diff --git a/core/src/main/kotlin/com/r3corda/core/utilities/OracleUtils.kt b/core/src/main/kotlin/com/r3corda/core/utilities/OracleUtils.kt new file mode 100644 index 0000000000..6414b29272 --- /dev/null +++ b/core/src/main/kotlin/com/r3corda/core/utilities/OracleUtils.kt @@ -0,0 +1,19 @@ +package com.r3corda.core.utilities + +import java.time.* + +/** + * This whole file exists as short cuts to get demos working. In reality we'd have static data and/or rules engine + * defining things like this. It currently resides in the core module because it needs to be visible to the IRS + * contract. + */ +// We at some future point may implement more than just this constant announcement window and thus use the params. +@Suppress("UNUSED_PARAMETER") +fun suggestInterestRateAnnouncementTimeWindow(index: String, source: String, date: LocalDate): TimeWindow { + // TODO: we would ordinarily convert clock to same time zone as the index/source would announce in + // and suggest an announcement time for the interest rate + // Here we apply a blanket announcement time of 11:45 London irrespective of source or index + val time = LocalTime.of(11, 45) + val zoneId = ZoneId.of("Europe/London") + return TimeWindow(ZonedDateTime.of(date, time, zoneId).toInstant(), Duration.ofHours(24)) +} diff --git a/core/src/main/kotlin/com/r3corda/protocols/RatesFixProtocol.kt b/core/src/main/kotlin/com/r3corda/protocols/RatesFixProtocol.kt index 62f0e020cc..1b910c8698 100644 --- a/core/src/main/kotlin/com/r3corda/protocols/RatesFixProtocol.kt +++ b/core/src/main/kotlin/com/r3corda/protocols/RatesFixProtocol.kt @@ -1,7 +1,6 @@ package com.r3corda.protocols import co.paralleluniverse.fibers.Suspendable -import com.r3corda.core.* import com.r3corda.core.contracts.Fix import com.r3corda.core.contracts.FixOf import com.r3corda.core.contracts.TransactionBuilder @@ -10,8 +9,12 @@ import com.r3corda.core.crypto.DigitalSignature import com.r3corda.core.messaging.SingleMessageRecipient import com.r3corda.core.node.NodeInfo import com.r3corda.core.protocols.ProtocolLogic +import com.r3corda.core.random63BitValue import com.r3corda.core.utilities.ProgressTracker +import com.r3corda.core.utilities.suggestInterestRateAnnouncementTimeWindow import java.math.BigDecimal +import java.time.Duration +import java.time.Instant import java.util.* // This code is unit tested in NodeInterestRates.kt @@ -29,6 +32,7 @@ open class RatesFixProtocol(protected val tx: TransactionBuilder, private val fixOf: FixOf, private val expectedRate: BigDecimal, private val rateTolerance: BigDecimal, + private val timeOut: Duration, override val progressTracker: ProgressTracker = RatesFixProtocol.tracker(fixOf.name)) : ProtocolLogic() { companion object { val TOPIC = "platform.rates.interest.fix" @@ -44,7 +48,7 @@ open class RatesFixProtocol(protected val tx: TransactionBuilder, class FixOutOfRange(val byAmount: BigDecimal) : Exception() - class QueryRequest(val queries: List, replyTo: SingleMessageRecipient, sessionID: Long) : AbstractRequestMessage(replyTo, sessionID) + class QueryRequest(val queries: List, replyTo: SingleMessageRecipient, sessionID: Long, val deadline: Instant) : AbstractRequestMessage(replyTo, sessionID) class SignRequest(val tx: WireTransaction, replyTo: SingleMessageRecipient, sessionID: Long) : AbstractRequestMessage(replyTo, sessionID) @Suspendable @@ -92,7 +96,9 @@ open class RatesFixProtocol(protected val tx: TransactionBuilder, @Suspendable fun query(): Fix { val sessionID = random63BitValue() - val req = QueryRequest(listOf(fixOf), serviceHub.networkService.myAddress, sessionID) + val deadline = suggestInterestRateAnnouncementTimeWindow(fixOf.name, oracle.identity.name, fixOf.forDay).end + val req = QueryRequest(listOf(fixOf), serviceHub.networkService.myAddress, sessionID, deadline) + // TODO: add deadline to receive val resp = sendAndReceive>(TOPIC_QUERY, oracle.address, 0, sessionID, req) return resp.validate { diff --git a/core/src/main/kotlin/com/r3corda/protocols/TwoPartyDealProtocol.kt b/core/src/main/kotlin/com/r3corda/protocols/TwoPartyDealProtocol.kt index 8e0bf8ecd9..d78fe77fef 100644 --- a/core/src/main/kotlin/com/r3corda/protocols/TwoPartyDealProtocol.kt +++ b/core/src/main/kotlin/com/r3corda/protocols/TwoPartyDealProtocol.kt @@ -1,6 +1,7 @@ package com.r3corda.protocols import co.paralleluniverse.fibers.Suspendable +import com.r3corda.core.TransientProperty import com.r3corda.core.contracts.* import com.r3corda.core.crypto.DigitalSignature import com.r3corda.core.crypto.Party @@ -17,6 +18,7 @@ import java.math.BigDecimal import java.security.KeyPair import java.security.PublicKey import java.security.SignatureException +import java.time.Duration /** * Classes for manipulating a two party deal or agreement. @@ -25,6 +27,8 @@ import java.security.SignatureException * * TODO: Also, the term Deal is used here where we might prefer Agreement. * + * TODO: Consider whether we can merge this with [TwoPartyTradeProtocol] + * */ object TwoPartyDealProtocol { val DEAL_TOPIC = "platform.deal" @@ -52,12 +56,7 @@ object TwoPartyDealProtocol { * There's a good chance we can push at least some of this logic down into core protocol logic * and helper methods etc. */ - abstract class Primary(val payload: U, - val otherSide: SingleMessageRecipient, - val otherSessionID: Long, - val myKeyPair: KeyPair, - val notaryNode: NodeInfo, - override val progressTracker: ProgressTracker = Primary.tracker()) : ProtocolLogic() { + abstract class Primary(override val progressTracker: ProgressTracker = Primary.tracker()) : ProtocolLogic() { companion object { object AWAITING_PROPOSAL : ProgressTracker.Step("Handshaking and awaiting transaction proposal") @@ -71,6 +70,12 @@ object TwoPartyDealProtocol { fun tracker() = ProgressTracker(AWAITING_PROPOSAL, VERIFYING, SIGNING, NOTARY, SENDING_SIGS, RECORDING, COPYING_TO_REGULATOR) } + abstract val payload: U + abstract val notaryNode: NodeInfo + abstract val otherSide: SingleMessageRecipient + abstract val otherSessionID: Long + abstract val myKeyPair: KeyPair + @Suspendable fun getPartialTransaction(): UntrustworthyData { progressTracker.currentStep = AWAITING_PROPOSAL @@ -79,7 +84,6 @@ object TwoPartyDealProtocol { // Make the first message we'll send to kick off the protocol. val hello = Handshake(payload, myKeyPair.public, sessionID) - val maybeSTX = sendAndReceive(DEAL_TOPIC, otherSide, otherSessionID, sessionID, hello) return maybeSTX @@ -143,6 +147,7 @@ object TwoPartyDealProtocol { logger.trace { "Deal stored" } + progressTracker.currentStep = COPYING_TO_REGULATOR val regulators = serviceHub.networkMapCache.regulators if (regulators.isNotEmpty()) { // Copy the transaction to every regulator in the network. This is obviously completely bogus, it's @@ -186,10 +191,7 @@ object TwoPartyDealProtocol { * There's a good chance we can push at least some of this logic down into core protocol logic * and helper methods etc. */ - abstract class Secondary(val otherSide: SingleMessageRecipient, - val notary: Party, - val sessionID: Long, - override val progressTracker: ProgressTracker = Secondary.tracker()) : ProtocolLogic() { + abstract class Secondary(override val progressTracker: ProgressTracker = Secondary.tracker()) : ProtocolLogic() { companion object { object RECEIVING : ProgressTracker.Step("Waiting for deal info") @@ -201,6 +203,9 @@ object TwoPartyDealProtocol { fun tracker() = ProgressTracker(RECEIVING, VERIFYING, SIGNING, SWAPPING_SIGNATURES, RECORDING) } + abstract val otherSide: SingleMessageRecipient + abstract val sessionID: Long + @Suspendable override fun call(): SignedTransaction { val handshake = receiveAndValidateHandshake() @@ -241,7 +246,7 @@ object TwoPartyDealProtocol { @Suspendable private fun swapSignaturesWithPrimary(stx: SignedTransaction, theirSessionID: Long): SignaturesFromPrimary { progressTracker.currentStep = SWAPPING_SIGNATURES - logger.trace { "Sending partially signed transaction to seller" } + logger.trace { "Sending partially signed transaction to other party" } // TODO: Protect against the seller terminating here and leaving us in the lurch without the final tx. @@ -271,45 +276,47 @@ object TwoPartyDealProtocol { /** * One side of the protocol for inserting a pre-agreed deal. */ - open class Instigator(otherSide: SingleMessageRecipient, - notaryNode: NodeInfo, - dealBeingOffered: T, - myKeyPair: KeyPair, - buyerSessionID: Long, - override val progressTracker: ProgressTracker = Primary.tracker()) : Primary(dealBeingOffered, otherSide, buyerSessionID, myKeyPair, notaryNode) + open class Instigator(override val otherSide: SingleMessageRecipient, + val notary: Party, + override val payload: T, + override val myKeyPair: KeyPair, + override val otherSessionID: Long, + override val progressTracker: ProgressTracker = Primary.tracker()) : Primary() { + + override val notaryNode: NodeInfo get() = + serviceHub.networkMapCache.notaryNodes.filter { it.identity == notary }.single() + } /** * One side of the protocol for inserting a pre-agreed deal. */ - open class Acceptor(otherSide: SingleMessageRecipient, - notary: Party, + open class Acceptor(override val otherSide: SingleMessageRecipient, + val notary: Party, val dealToBuy: T, - sessionID: Long, - override val progressTracker: ProgressTracker = Secondary.tracker()) : Secondary(otherSide, notary, sessionID) { + override val sessionID: Long, + override val progressTracker: ProgressTracker = Secondary.tracker()) : Secondary() { + override fun validateHandshake(handshake: Handshake): Handshake { - with(handshake) { - // What is the seller trying to sell us? - val deal: T = handshake.payload - val otherKey = handshake.publicKey - logger.trace { "Got deal request for: ${handshake.payload}" } + // What is the seller trying to sell us? + val deal: T = handshake.payload + val otherKey = handshake.publicKey + logger.trace { "Got deal request for: ${handshake.payload.ref}" } - // Check the start message for acceptability. - check(handshake.sessionID > 0) - if (dealToBuy != deal) - throw DealMismatchException(dealToBuy, deal) + // Check the start message for acceptability. + check(handshake.sessionID > 0) + check(dealToBuy == deal) - // We need to substitute in the new public keys for the Parties - val myName = serviceHub.storageService.myLegalIdentity.name - val myOldParty = deal.parties.single { it.name == myName } - val theirOldParty = deal.parties.single { it.name != myName } + // We need to substitute in the new public keys for the Parties + val myName = serviceHub.storageService.myLegalIdentity.name + val myOldParty = deal.parties.single { it.name == myName } + val theirOldParty = deal.parties.single { it.name != myName } - @Suppress("UNCHECKED_CAST") - val newDeal = deal. - withPublicKey(myOldParty, serviceHub.keyManagementService.freshKey().public). - withPublicKey(theirOldParty, otherKey) as T + @Suppress("UNCHECKED_CAST") + val newDeal = deal. + withPublicKey(myOldParty, serviceHub.keyManagementService.freshKey().public). + withPublicKey(theirOldParty, otherKey) as T - return handshake.copy(payload = newDeal) - } + return handshake.copy(payload = newDeal) } @@ -328,59 +335,62 @@ object TwoPartyDealProtocol { * One side of the fixing protocol for an interest rate swap, but could easily be generalised further. * * Do not infer too much from the name of the class. This is just to indicate that it is the "side" - * of the protocol that is run by the party with the fixed leg of swap deal, which is the basis for decided + * of the protocol that is run by the party with the fixed leg of swap deal, which is the basis for deciding * who does what in the protocol. */ - open class Fixer(otherSide: SingleMessageRecipient, - notary: Party, - val dealToFix: StateAndRef, - sessionID: Long, - val replacementProgressTracker: ProgressTracker? = null) : Secondary(otherSide, notary, sessionID) { - private val ratesFixTracker = RatesFixProtocol.tracker(dealToFix.state.data.nextFixingOf()!!.name) + class Fixer(val initiation: FixingSessionInitiation, override val progressTracker: ProgressTracker = Secondary.tracker()) : Secondary() { - override val progressTracker: ProgressTracker = replacementProgressTracker ?: createTracker() + override val sessionID: Long get() = initiation.sessionID - fun createTracker(): ProgressTracker = Secondary.tracker().apply { - setChildProgressTracker(SIGNING, ratesFixTracker) - } + override val otherSide: SingleMessageRecipient get() = initiation.sender + + private lateinit var txState: TransactionState<*> + private lateinit var deal: FixableDealState override fun validateHandshake(handshake: Handshake): Handshake { - with(handshake) { - logger.trace { "Got fixing request for: ${dealToFix.state}" } + logger.trace { "Got fixing request for: ${handshake.payload}" } - // Check the start message for acceptability. - if (dealToFix.ref != handshake.payload) - throw DealRefMismatchException(dealToFix.ref, handshake.payload) + // Check the handshake and initiation for acceptability. + check(handshake.sessionID > 0) + txState = serviceHub.loadState(handshake.payload) + deal = txState.data as FixableDealState - return handshake - } + // 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.storageService.myLegalIdentity.name + val otherParty = deal.parties.filter { it.name != myName }.single() + check(otherParty == initiation.party) + val otherPartyAddress = serviceHub.networkMapCache.getNodeByLegalName(otherParty.name)!!.address + check(otherPartyAddress == otherSide) + // Also check we are one of the parties + deal.parties.filter { it.name == myName }.single() + + return handshake } @Suspendable override fun assembleSharedTX(handshake: Handshake): Pair> { - val fixOf = dealToFix.state.data.nextFixingOf()!! + @Suppress("UNCHECKED_CAST") + val fixOf = deal.nextFixingOf()!! // TODO Do we need/want to substitute in new public keys for the Parties? val myName = serviceHub.storageService.myLegalIdentity.name - val deal: T = dealToFix.state.data val myOldParty = deal.parties.single { it.name == myName } - @Suppress("UNCHECKED_CAST") val newDeal = deal val ptx = TransactionType.General.Builder() - val addFixing = object : RatesFixProtocol(ptx, serviceHub.networkMapCache.ratesOracleNodes[0], fixOf, BigDecimal.ZERO, BigDecimal.ONE) { + val addFixing = object : RatesFixProtocol(ptx, serviceHub.networkMapCache.ratesOracleNodes[0], fixOf, BigDecimal.ZERO, BigDecimal.ONE, initiation.timeout) { @Suspendable override fun beforeSigning(fix: Fix) { - newDeal.generateFix(ptx, dealToFix, fix) + newDeal.generateFix(ptx, StateAndRef(txState, handshake.payload), fix) // And add a request for timestamping: it may be that none of the contracts need this! But it can't hurt // to have one. - ptx.setTime(serviceHub.clock.instant(), notary, 30.seconds) + ptx.setTime(serviceHub.clock.instant(), txState.notary, 30.seconds) } } subProtocol(addFixing) - return Pair(ptx, arrayListOf(myOldParty.owningKey)) } } @@ -392,11 +402,72 @@ object TwoPartyDealProtocol { * is just the "side" of the protocol run by the party with the floating leg as a way of deciding who * does what in the protocol. */ - open class Floater(otherSide: SingleMessageRecipient, - otherSessionID: Long, - notary: NodeInfo, - dealToFix: StateAndRef, - myKeyPair: KeyPair, - val sessionID: Long, - override val progressTracker: ProgressTracker = Primary.tracker()) : Primary(dealToFix.ref, otherSide, otherSessionID, myKeyPair, notary) + class Floater(override val payload: StateRef, + override val otherSessionID: Long, + override val progressTracker: ProgressTracker = Primary.tracker()) : Primary() { + @Suppress("UNCHECKED_CAST") + internal val dealToFix: StateAndRef by TransientProperty { + val state = serviceHub.loadState(payload) as TransactionState + StateAndRef(state, payload) + } + + override val myKeyPair: KeyPair get() { + val myName = serviceHub.storageService.myLegalIdentity.name + val publicKey = dealToFix.state.data.parties.filter { it.name == myName }.single().owningKey + return serviceHub.keyManagementService.toKeyPair(publicKey) + } + + override val otherSide: SingleMessageRecipient get() { + // TODO: what happens if there's no node? Move to messaging taking Party and then handled in messaging layer + val myName = serviceHub.storageService.myLegalIdentity.name + val otherParty = dealToFix.state.data.parties.filter { it.name != myName }.single() + return serviceHub.networkMapCache.getNodeByLegalName(otherParty.name)!!.address + } + + override val notaryNode: NodeInfo get() = + serviceHub.networkMapCache.notaryNodes.filter { it.identity == dealToFix.state.notary }.single() + } + + /** This topic exists purely for [FixingSessionInitiation] to be sent from [FixingRoleDecider] to [FixingSessionInitiationHandler] */ + val FIX_INITIATE_TOPIC = "platform.fix.initiate" + + /** Used to set up the session between [Floater] and [Fixer] */ + data class FixingSessionInitiation(val sessionID: Long, val party: Party, val sender: SingleMessageRecipient, val timeout: Duration) + + /** + * This protocol looks at the deal and decides whether to be the Fixer or Floater role in agreeing a fixing. + * + * It is kicked off as an activity on both participant nodes by the scheduler when it's time for a fixing. If the + * Fixer role is chosen, then that will be initiated by the [FixingSessionInitiation] message sent from the other party and + * handled by the [FixingSessionInitiationHandler]. + * + * TODO: Replace [FixingSessionInitiation] and [FixingSessionInitiationHandler] with generic session initiation logic once it exists. + */ + class FixingRoleDecider(val ref: StateRef, val timeout: Duration, override val progressTracker: ProgressTracker = tracker(ref.toString())) : ProtocolLogic() { + companion object { + class LOADING(ref: String) : ProgressTracker.Step("Loading state $ref to decide fixing role") + + fun tracker(ref: String) = ProgressTracker(LOADING(ref)) + } + + @Suspendable + override fun call(): Unit { + progressTracker.nextStep() + val dealToFix = serviceHub.loadState(ref) + // TODO: this is not the eventual mechanism for identifying the parties + val sortedParties = (dealToFix.data as FixableDealState).parties.sortedBy { it.name } + if (sortedParties[0].name == serviceHub.storageService.myLegalIdentity.name) { + // Generate sessionID + val sessionID = random63BitValue() + val initation = FixingSessionInitiation(sessionID, sortedParties[0], serviceHub.networkService.myAddress, timeout) + + // Send initiation to other side to launch one side of the fixing protocol (the Fixer). + send(FIX_INITIATE_TOPIC, serviceHub.networkMapCache.getNodeByLegalName(sortedParties[1].name)!!.address, 0, initation) + + // Then start the other side of the fixing protocol. + val protocol = Floater(ref, sessionID) + subProtocol(protocol) + } + } + } } \ No newline at end of file diff --git a/core/src/test/java/com/r3corda/core/protocols/ProtocolLogicRefFromJavaTest.java b/core/src/test/java/com/r3corda/core/protocols/ProtocolLogicRefFromJavaTest.java new file mode 100644 index 0000000000..4e7a3a707f --- /dev/null +++ b/core/src/test/java/com/r3corda/core/protocols/ProtocolLogicRefFromJavaTest.java @@ -0,0 +1,42 @@ +package com.r3corda.core.protocols; + + +import com.google.common.collect.Sets; +import org.junit.Test; + +public class ProtocolLogicRefFromJavaTest { + + public static class JavaProtocolLogic extends ProtocolLogic { + + public JavaProtocolLogic(int A, String b) { + } + + @Override + public Void call() { + return null; + } + } + + public static class JavaNoArgProtocolLogic extends ProtocolLogic { + + public JavaNoArgProtocolLogic() { + } + + @Override + public Void call() { + return null; + } + } + + @Test + public void test() { + ProtocolLogicRefFactory factory = new ProtocolLogicRefFactory(Sets.newHashSet(JavaProtocolLogic.class.getName()), Sets.newHashSet(Integer.class.getName(), String.class.getName())); + factory.create(JavaProtocolLogic.class, 1, "Hello Jack"); + } + + @Test + public void testNoArg() { + ProtocolLogicRefFactory factory = new ProtocolLogicRefFactory(Sets.newHashSet(JavaNoArgProtocolLogic.class.getName()), Sets.newHashSet(Integer.class.getName(), String.class.getName())); + factory.create(JavaNoArgProtocolLogic.class); + } +} diff --git a/core/src/test/kotlin/com/r3corda/core/protocols/ProtocolLogicRefTest.kt b/core/src/test/kotlin/com/r3corda/core/protocols/ProtocolLogicRefTest.kt new file mode 100644 index 0000000000..a3ad42d0de --- /dev/null +++ b/core/src/test/kotlin/com/r3corda/core/protocols/ProtocolLogicRefTest.kt @@ -0,0 +1,80 @@ +package com.r3corda.core.protocols + +import com.google.common.collect.Sets +import com.r3corda.core.days +import org.junit.Before +import org.junit.Test +import java.time.Duration + +class ProtocolLogicRefTest { + + @Suppress("UNUSED_PARAMETER") // We will never use A or b + class KotlinProtocolLogic(A: Int, b: String) : ProtocolLogic() { + constructor() : this(1, "2") + + constructor(C: String) : this(1, C) + + constructor(illegal: Duration) : this(1, illegal.toString()) + + override fun call(): Unit { + } + } + + class KotlinNoArgProtocolLogic : ProtocolLogic() { + override fun call(): Unit { + } + } + + @Suppress("UNUSED_PARAMETER") // We will never use A or b + class NotWhiteListedKotlinProtocolLogic(A: Int, b: String) : ProtocolLogic() { + override fun call(): Unit { + } + } + + lateinit var factory: ProtocolLogicRefFactory + + @Before + fun setup() { + // We have to allow Java boxed primitives but Kotlin warns we shouldn't be using them + factory = ProtocolLogicRefFactory(Sets.newHashSet(KotlinProtocolLogic::class.java.name, KotlinNoArgProtocolLogic::class.java.name), + Sets.newHashSet(@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") Integer::class.java.name, String::class.java.name)) + } + + @Test + fun testCreateKotlinNoArg() { + factory.create(KotlinNoArgProtocolLogic::class.java) + } + + @Test + fun testCreateKotlin() { + val args = mapOf(Pair("A", 1), Pair("b", "Hello Jack")) + factory.createKotlin(KotlinProtocolLogic::class.java, args) + } + + @Test + fun testCreatePrimary() { + factory.create(KotlinProtocolLogic::class.java, 1, "Hello Jack") + } + + @Test(expected = IllegalArgumentException::class) + fun testCreateNotWhiteListed() { + factory.create(NotWhiteListedKotlinProtocolLogic::class.java, 1, "Hello Jack") + } + + @Test + fun testCreateKotlinVoid() { + factory.createKotlin(KotlinProtocolLogic::class.java, emptyMap()) + } + + @Test + fun testCreateKotlinNonPrimary() { + val args = mapOf(Pair("C", "Hello Jack")) + factory.createKotlin(KotlinProtocolLogic::class.java, args) + } + + @Test(expected = IllegalArgumentException::class) + fun testCreateArgNotWhiteListed() { + val args = mapOf(Pair("illegal", 1.days)) + factory.createKotlin(KotlinProtocolLogic::class.java, args) + } +} diff --git a/docs/source/event-scheduling.rst b/docs/source/event-scheduling.rst new file mode 100644 index 0000000000..9c2cacfd92 --- /dev/null +++ b/docs/source/event-scheduling.rst @@ -0,0 +1,102 @@ +.. highlight:: kotlin +.. raw:: html + + + + +Event scheduling +================ + +This article explains our experimental approach to modelling time based events in code. It explains how a contract +state can expose an upcoming event and what action to take if the scheduled time for that event is reached. + +Introduction +------------ + +Many financial instruments have time sensitive components to them. For example, an Interest Rate Swap has a schedule +for when: + +* Interest rate fixings should take place for floating legs, so that the interest rate used as the basis for payments + can be agreed. +* Any payments between the parties are expected to take place. +* Any payments between the parties become overdue. + +Each of these is dependent on the current state of the financial instrument. What payments and interest rate fixings +have already happened should already be recorded in the state, for example. This means that the *next* time sensitive +event is thus a property of the current contract state. By next, we mean earliest in chronological terms, that is still +due. If a contract state is consumed in the UTXO model, then what *was* the next event becomes irrelevant and obsolete +and the next time sensitive event is determined by any successor contract state. + +Knowing when the next time sensitive event is due to occur is useful, but typically some *activity* is expected to take +place when this event occurs. We already have a model for business processes in the form of the protocol state machines, +so in the platform we have introduced the concept of *scheduled activities* that can invoke protocol state machines +at a scheduled time. A contract state can optionally described the next scheduled activity for itself. If it omits +to do so, then nothing will be scheduled. + +How to implement scheduled events +--------------------------------- + +There are two main steps to implementing scheduled events: + +* Have your ``ContractState`` implementation also implement ``SchedulableState``. This requires a method named + ``nextScheduledActivity`` to be implemented which returns an optional ``ScheduledActivity`` instance. + ``ScheduledActivity`` captures what ``ProtocolLogic`` instance each node will run, to perform the activity, and when it + will run is described by a ``java.time.Instant``. Once your state implements this interface and is tracked by the + wallet, it can expect to be queried for the next activity when recorded via the ``ServiceHub.recordTransactions`` + method during protocols execution. +* If nothing suitable exists, implement a ``ProtocolLogic`` to be executed by each node as the activity itself. + The important thing to remember is that each node that is party to the transaction, in the current implementation, + will execute the same ``ProtocolLogic`` so that needs to establish roles in the business process based on the contract + state and the node it is running on, and follow different but complementary paths through the business logic. + +.. note:: The scheduler's clock always operates in the UTC time zone for uniformity, so any time zone logic must be + performed by the contract, using ``ZonedDateTime``. + +In the short term, until we have automatic protocol session set up, you will also likely need to install a network +handler to help with obtaining a unqiue and secure random session. An example is described below. + +The production and consumption of ``ContractStates`` is observed by the scheduler and the activities associated with +any consumed states are unscheduled. Any newly produced states are then queried via the ``nextScheduledActivity`` +method and if they do not return ``null`` then that activity is scheduled based on the content of the +``ScheduledActivity`` object returned. + +An example +---------- + +Let's take an example of the Interest Rate Swap fixings for our scheduled events. The first task is to implement the +``nextScheduledActivity`` method on the ``State``. + + +.. container:: codeset + + .. sourcecode:: kotlin + + override fun nextScheduledActivity(thisStateRef: StateRef, + protocolLogicRefFactory: ProtocolLogicRefFactory): ScheduledActivity? { + val nextFixingOf = nextFixingOf() ?: return null + + // This is perhaps not how we should determine the time point in the business day, but instead expect the + // schedule to detail some of these aspects. + val (instant, duration) = suggestInterestRateAnnouncementTimeWindow(index = nextFixingOf.name, + source = floatingLeg.indexSource, + date = nextFixingOf.forDay) + return ScheduledActivity(protocolLogicRefFactory.create(TwoPartyDealProtocol.FixingRoleDecider::class.java, + thisStateRef, duration), instant) + } + +The first thing this does is establish if there are any remaining fixings. If there are none, then it returns ``null`` +to indicate that there is no activity to schedule. Otherwise it calculates the ``Instant`` at which the interest rate +should become available and schedules an activity at that time to work out what roles each node will take in the fixing +business process and to take on those roles. That ``ProtocolLogic`` will be handed the ``StateRef`` for the interest +rate swap ``State`` in question, as well as a tolerance ``Duration`` of how long to wait after the activity is triggered +for the interest rate before indicating an error. + +.. note:: The use of the factory to create a ``ProtocolLogicRef`` instance to embed in the ``ScheduledActivity``. This is a + way to create a reference to the ``ProtocolLogic`` class and it's constructor parameters to instantiate that can be + checked against a per node whitelist of approved and allowable types as part of our overall security sandboxing. + +As previously mentioned, we currently need a small network handler to assist with session setup until the work to +automate that is complete. See the interest rate swap specific implementation ``FixingSessionInitiationHandler`` which +is responsible for starting a ``ProtocolLogic`` to perform one role in the fixing protocol with the ``sessionID`` sent +by the ``FixingRoleDecider`` on the other node which then launches the other role in the fixing protocol. Currently +the handler needs to be manually installed in the node. diff --git a/docs/source/index.rst b/docs/source/index.rst index f18a72c5a4..df3e876da5 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -41,6 +41,7 @@ Read on to learn: tutorial-contract protocol-state-machines oracles + event-scheduling .. toctree:: :maxdepth: 2 diff --git a/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt index 7d5b00a219..06abdc96b1 100644 --- a/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt @@ -12,6 +12,8 @@ import com.r3corda.core.node.CityDatabase import com.r3corda.core.node.NodeInfo import com.r3corda.core.node.PhysicalLocation import com.r3corda.core.node.services.* +import com.r3corda.core.protocols.ProtocolLogic +import com.r3corda.core.protocols.ProtocolLogicRefFactory import com.r3corda.core.random63BitValue import com.r3corda.core.seconds import com.r3corda.core.serialization.deserialize @@ -24,6 +26,8 @@ import com.r3corda.node.services.api.MonitoringService import com.r3corda.node.services.api.ServiceHubInternal import com.r3corda.node.services.clientapi.NodeInterestRates import com.r3corda.node.services.config.NodeConfiguration +import com.r3corda.node.services.events.NodeSchedulerService +import com.r3corda.node.services.events.ScheduledActivityObserver import com.r3corda.node.services.identity.InMemoryIdentityService import com.r3corda.node.services.keys.E2ETestKeyManagementService import com.r3corda.node.services.network.InMemoryNetworkMapCache @@ -48,7 +52,6 @@ import java.nio.file.Path import java.security.KeyPair import java.security.Security import java.time.Clock -import java.time.Instant import java.util.* /** @@ -89,9 +92,17 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration, override val walletService: WalletService get() = wallet override val keyManagementService: KeyManagementService get() = keyManagement override val identityService: IdentityService get() = identity - override val monitoringService: MonitoringService = MonitoringService(MetricRegistry()) + override val schedulerService: SchedulerService get() = scheduler override val clock: Clock = platformClock + // Internal only + override val monitoringService: MonitoringService = MonitoringService(MetricRegistry()) + override val protocolLogicRefFactory = ProtocolLogicRefFactory() + + override fun startProtocol(loggerName: String, logic: ProtocolLogic): ListenableFuture { + return smm.add(loggerName, logic) + } + override fun recordTransactions(txs: Iterable) = recordTransactionsInternal(storage, txs) } @@ -112,6 +123,7 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration, lateinit var identity: IdentityService lateinit var net: MessagingService lateinit var api: APIServer + lateinit var scheduler: SchedulerService var isPreviousCheckpointsPresent = false private set @@ -140,7 +152,11 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration, // the identity key. But the infrastructure to make that easy isn't here yet. keyManagement = E2ETestKeyManagementService(setOf(storage.myLegalIdentityKey)) api = APIServerImpl(this) - smm = StateMachineManager(services, listOf(storage, net, wallet, keyManagement, identity, platformClock), checkpointStorage, serverThread) + scheduler = NodeSchedulerService(services) + smm = StateMachineManager(services, + listOf(storage, net, wallet, keyManagement, identity, platformClock, scheduler, interestRatesService), + checkpointStorage, + serverThread) // This object doesn't need to be referenced from this class because it registers handlers on the network // service and so that keeps it from being collected. @@ -154,6 +170,7 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration, ANSIProgressObserver(smm) // Add wallet observers CashBalanceAsMetricsObserver(services) + ScheduledActivityObserver(services) startMessagingService() _networkMapRegistrationFuture.setFuture(registerWithNetworkMap()) @@ -210,7 +227,7 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration, private fun updateRegistration(serviceInfo: NodeInfo, type: AddOrRemove): ListenableFuture { // Register this node against the network - val expires = Instant.now() + NetworkMapService.DEFAULT_EXPIRATION_PERIOD + val expires = platformClock.instant() + NetworkMapService.DEFAULT_EXPIRATION_PERIOD val reg = NodeRegistration(info, networkMapSeq++, type, expires) val sessionID = random63BitValue() val request = NetworkMapService.RegistrationRequest(reg.toWire(storage.myLegalIdentityKey.private), net.myAddress, sessionID) @@ -227,7 +244,7 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration, } open protected fun makeNetworkMapService() { - val expires = Instant.now() + NetworkMapService.DEFAULT_EXPIRATION_PERIOD + val expires = platformClock.instant() + NetworkMapService.DEFAULT_EXPIRATION_PERIOD val reg = NodeRegistration(info, Long.MAX_VALUE, AddOrRemove.ADD, expires) inNodeNetworkMapService = InMemoryNetworkMapService(net, reg, services.networkMapCache) } diff --git a/node/src/main/kotlin/com/r3corda/node/internal/testing/IRSSimulation.kt b/node/src/main/kotlin/com/r3corda/node/internal/testing/IRSSimulation.kt index 6c25d57130..d3bf112590 100644 --- a/node/src/main/kotlin/com/r3corda/node/internal/testing/IRSSimulation.kt +++ b/node/src/main/kotlin/com/r3corda/node/internal/testing/IRSSimulation.kt @@ -15,6 +15,7 @@ import com.r3corda.core.node.services.linearHeadsOfType import com.r3corda.core.node.services.testing.MockIdentityService import com.r3corda.core.random63BitValue import com.r3corda.core.success +import com.r3corda.node.services.FixingSessionInitiationHandler import com.r3corda.node.services.network.InMemoryMessagingNetwork import com.r3corda.node.utilities.JsonSupport import com.r3corda.protocols.TwoPartyDealProtocol @@ -30,7 +31,7 @@ class IRSSimulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, laten val om = JsonSupport.createDefaultMapper(MockIdentityService(network.identities)) init { - currentDay = LocalDate.of(2016, 3, 10) // Should be 12th but the actual first fixing date gets rolled backwards. + currentDateAndTime = LocalDate.of(2016, 3, 8).atStartOfDay() } private var nodeAKey: KeyPair? = null @@ -39,6 +40,11 @@ class IRSSimulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, laten private val executeOnNextIteration = Collections.synchronizedList(LinkedList<() -> Unit>()) override fun startMainSimulation(): ListenableFuture { + + // TODO: until we have general session initiation + FixingSessionInitiationHandler.register(banks[0]) + FixingSessionInitiationHandler.register(banks[1]) + val future = SettableFuture.create() nodeAKey = banks[0].keyManagement.freshKey() @@ -80,7 +86,6 @@ class IRSSimulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, laten val node1: SimulatedNode = banks[i] val node2: SimulatedNode = banks[j] - val sessionID = random63BitValue() val swaps: Map> = node1.services.walletService.linearHeadsOfType() val theDealRef: StateAndRef = swaps.values.single() @@ -89,30 +94,23 @@ class IRSSimulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, laten extraNodeLabels[node1] = "Fixing event on $nextFixingDate" extraNodeLabels[node2] = "Fixing event on $nextFixingDate" - // For some reason the first fix is always before the effective date. - if (nextFixingDate > currentDay) - currentDay = nextFixingDate - - val sideA = TwoPartyDealProtocol.Floater(node2.net.myAddress, sessionID, notary.info, theDealRef, nodeAKey!!, sessionID) - val sideB = TwoPartyDealProtocol.Fixer(node1.net.myAddress, notary.info.identity, theDealRef, sessionID) - - linkConsensus(listOf(node1, node2, regulators[0]), sideB) - linkProtocolProgress(node1, sideA) - linkProtocolProgress(node2, sideB) - - // We have to start the protocols in separate iterations, as adding to the SMM effectively 'iterates' that node - // in the simulation, so if we don't do this then the two sides seem to act simultaneously. - val retFuture = SettableFuture.create() - val futA = node1.smm.add("floater", sideA) - val futB = node2.smm.add("fixer", sideB) - executeOnNextIteration += { - Futures.allAsList(futA, futB) success { - retFuture.set(null) - } failure { throwable -> - retFuture.setException(throwable) - } + // Complete the future when the state has been consumed on both nodes + val futA = node1.services.walletService.whenConsumed(theDealRef.ref) + val futB = node2.services.walletService.whenConsumed(theDealRef.ref) + Futures.allAsList(futA, futB) success { + retFuture.set(null) + } failure { throwable -> + retFuture.setException(throwable) } + + showProgressFor(listOf(node1, node2)) + showConsensusFor(listOf(node1, node2, regulators[0])) + + // For some reason the first fix is always before the effective date. + if (nextFixingDate > currentDateAndTime.toLocalDate()) + currentDateAndTime = nextFixingDate.atTime(15, 0) + return retFuture } @@ -132,13 +130,11 @@ class IRSSimulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, laten val sessionID = random63BitValue() - val instigator = TwoPartyDealProtocol.Instigator(node2.net.myAddress, notary.info, irs, nodeAKey!!, sessionID) + val instigator = TwoPartyDealProtocol.Instigator(node2.net.myAddress, notary.info.identity, irs, nodeAKey!!, sessionID) val acceptor = TwoPartyDealProtocol.Acceptor(node1.net.myAddress, notary.info.identity, irs, sessionID) - // TODO: Eliminate the need for linkProtocolProgress - linkConsensus(listOf(node1, node2, regulators[0]), acceptor) - linkProtocolProgress(node1, instigator) - linkProtocolProgress(node2, acceptor) + showProgressFor(listOf(node1, node2)) + showConsensusFor(listOf(node1, node2, regulators[0])) val instigatorFuture: ListenableFuture = node1.smm.add("instigator", instigator) diff --git a/node/src/main/kotlin/com/r3corda/node/internal/testing/Simulation.kt b/node/src/main/kotlin/com/r3corda/node/internal/testing/Simulation.kt index 2ab72e33b6..8227c1b885 100644 --- a/node/src/main/kotlin/com/r3corda/node/internal/testing/Simulation.kt +++ b/node/src/main/kotlin/com/r3corda/node/internal/testing/Simulation.kt @@ -1,6 +1,5 @@ package com.r3corda.node.internal.testing -import com.google.common.base.Function import com.google.common.util.concurrent.Futures import com.google.common.util.concurrent.ListenableFuture import com.r3corda.core.node.CityDatabase @@ -15,11 +14,14 @@ import com.r3corda.node.services.config.NodeConfiguration import com.r3corda.node.services.network.InMemoryMessagingNetwork import com.r3corda.node.services.network.NetworkMapService import com.r3corda.node.services.transactions.SimpleNotaryService +import com.r3corda.node.utilities.AddOrRemove import rx.Observable import rx.subjects.PublishSubject import java.nio.file.Path import java.security.KeyPair import java.time.LocalDate +import java.time.LocalDateTime +import java.time.ZoneOffset import java.util.* /** @@ -145,6 +147,8 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean, val serviceProviders: List = listOf(notary, ratesOracle, networkMap) val banks: List = bankFactory.createAll() + val clocks = (serviceProviders + regulators + banks).map { it.services.clock as TestClock } + private val _allProtocolSteps = PublishSubject.create>() private val _doneSteps = PublishSubject.create>() val allProtocolSteps: Observable> = _allProtocolSteps @@ -156,14 +160,21 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean, * The current simulated date. By default this never changes. If you want it to change, you should do so from * within your overridden [iterate] call. Changes in the current day surface in the [dateChanges] observable. */ - var currentDay: LocalDate = LocalDate.now() + var currentDateAndTime: LocalDateTime = LocalDate.now().atStartOfDay() protected set(value) { field = value _dateChanges.onNext(value) } - private val _dateChanges = PublishSubject.create() - val dateChanges: Observable = _dateChanges + private val _dateChanges = PublishSubject.create() + val dateChanges: Observable get() = _dateChanges + + init { + // Advance node clocks when current time is changed + dateChanges.subscribe { + clocks.setTo(currentDateAndTime.toInstant(ZoneOffset.UTC)) + } + } /** * A place for simulations to stash human meaningful text about what the node is "thinking", which might appear @@ -201,7 +212,15 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean, return null } - protected fun linkProtocolProgress(node: SimulatedNode, protocol: ProtocolLogic<*>) { + protected fun showProgressFor(nodes: List) { + nodes.forEach { node -> + node.smm.changes.filter { it.second == AddOrRemove.ADD }.first().subscribe { + linkProtocolProgress(node, it.first) + } + } + } + + private fun linkProtocolProgress(node: SimulatedNode, protocol: ProtocolLogic<*>) { val pt = protocol.progressTracker ?: return pt.changes.subscribe { change: ProgressTracker.Change -> // Runs on node thread. @@ -211,7 +230,15 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean, _allProtocolSteps.onNext(Pair(node, ProgressTracker.Change.Position(pt, pt.steps[1]))) } - protected fun linkConsensus(nodes: Collection, protocol: ProtocolLogic<*>) { + + protected fun showConsensusFor(nodes: List) { + val node = nodes.first() + node.smm.changes.filter { it.second == AddOrRemove.ADD }.first().subscribe { + linkConsensus(nodes, it.first) + } + } + + private fun linkConsensus(nodes: Collection, protocol: ProtocolLogic<*>) { protocol.progressTracker?.changes?.subscribe { change: ProgressTracker.Change -> // Runs on node thread. if (protocol.progressTracker!!.currentStep == ProgressTracker.DONE) { diff --git a/node/src/main/kotlin/com/r3corda/node/internal/testing/TestClock.kt b/node/src/main/kotlin/com/r3corda/node/internal/testing/TestClock.kt index 009c4f0d3c..baa7085c21 100644 --- a/node/src/main/kotlin/com/r3corda/node/internal/testing/TestClock.kt +++ b/node/src/main/kotlin/com/r3corda/node/internal/testing/TestClock.kt @@ -49,3 +49,9 @@ class TestClock(private var delegateClock: Clock = Clock.systemUTC()) : MutableC return delegateClock.zone } } + +/** + * A helper method to set several [TestClock]s to approximately the same time. The clocks may drift by the time it + * takes for each [TestClock] to have it's time set and any observers to execute. + */ +fun Iterable.setTo(instant: Instant) = this.forEach { it.setTo(instant) } diff --git a/node/src/main/kotlin/com/r3corda/node/internal/testing/TradeSimulation.kt b/node/src/main/kotlin/com/r3corda/node/internal/testing/TradeSimulation.kt index 571eb13252..1acf61bc08 100644 --- a/node/src/main/kotlin/com/r3corda/node/internal/testing/TradeSimulation.kt +++ b/node/src/main/kotlin/com/r3corda/node/internal/testing/TradeSimulation.kt @@ -49,9 +49,8 @@ class TradeSimulation(runAsync: Boolean, latencyInjector: InMemoryMessagingNetwo val sellerProtocol = TwoPartyTradeProtocol.Seller(buyer.net.myAddress, notary.info, issuance.tx.outRef(0), amount, seller.storage.myLegalIdentityKey, sessionID) - linkConsensus(listOf(buyer, seller, notary), sellerProtocol) - linkProtocolProgress(buyer, buyerProtocol) - linkProtocolProgress(seller, sellerProtocol) + showConsensusFor(listOf(buyer, seller, notary)) + showProgressFor(listOf(buyer, seller)) val buyerFuture = buyer.smm.add("bank.$buyerBankIndex.${TwoPartyTradeProtocol.TRADE_TOPIC}.buyer", buyerProtocol) val sellerFuture = seller.smm.add("bank.$sellerBankIndex.${TwoPartyTradeProtocol.TRADE_TOPIC}.seller", sellerProtocol) diff --git a/node/src/main/kotlin/com/r3corda/node/services/FixingSessionInitiationHandler.kt b/node/src/main/kotlin/com/r3corda/node/services/FixingSessionInitiationHandler.kt new file mode 100644 index 0000000000..102ded3db8 --- /dev/null +++ b/node/src/main/kotlin/com/r3corda/node/services/FixingSessionInitiationHandler.kt @@ -0,0 +1,22 @@ +package com.r3corda.node.services + +import com.r3corda.core.serialization.deserialize +import com.r3corda.node.internal.AbstractNode +import com.r3corda.protocols.TwoPartyDealProtocol + +/** + * This is a temporary handler required for establishing random sessionIDs for the [Fixer] and [Floater] as part of + * running scheduled fixings for the [InterestRateSwap] contract. + * + * TODO: This will be replaced with the automatic sessionID / session setup work. + */ +object FixingSessionInitiationHandler { + + fun register(node: AbstractNode) { + node.net.addMessageHandler("${TwoPartyDealProtocol.FIX_INITIATE_TOPIC}.0") { msg, registration -> + val initiation = msg.data.deserialize() + val protocol = TwoPartyDealProtocol.Fixer(initiation) + node.smm.add("fixings", protocol) + } + } +} diff --git a/node/src/main/kotlin/com/r3corda/node/services/api/ServiceHubInternal.kt b/node/src/main/kotlin/com/r3corda/node/services/api/ServiceHubInternal.kt index 8fc9ce4d8e..e206a28644 100644 --- a/node/src/main/kotlin/com/r3corda/node/services/api/ServiceHubInternal.kt +++ b/node/src/main/kotlin/com/r3corda/node/services/api/ServiceHubInternal.kt @@ -1,11 +1,15 @@ package com.r3corda.node.services.api +import com.google.common.util.concurrent.ListenableFuture import com.r3corda.core.contracts.SignedTransaction import com.r3corda.core.node.ServiceHub import com.r3corda.core.node.services.TxWritableStorageService +import com.r3corda.core.protocols.ProtocolLogic +import com.r3corda.core.protocols.ProtocolLogicRefFactory abstract class ServiceHubInternal : ServiceHub { abstract val monitoringService: MonitoringService + abstract val protocolLogicRefFactory: ProtocolLogicRefFactory /** * Given a list of [SignedTransaction]s, writes them to the given storage for validated transactions and then @@ -18,4 +22,11 @@ abstract class ServiceHubInternal : ServiceHub { txs.forEach { writableStorageService.validatedTransactions.addTransaction(it) } walletService.notifyAll(txs.map { it.tx }) } + + /** + * TODO: borrowing this method from service manager work in another branch. It's required to avoid circular dependency + * between SMM and the scheduler. That particular problem should also be resolved by the service manager work + * itself, at which point this method would not be needed (by the scheduler) + */ + abstract fun startProtocol(loggerName: String, logic: ProtocolLogic): ListenableFuture } \ No newline at end of file diff --git a/node/src/main/kotlin/com/r3corda/node/services/clientapi/NodeInterestRates.kt b/node/src/main/kotlin/com/r3corda/node/services/clientapi/NodeInterestRates.kt index 19f7b9449b..83102bd4ff 100644 --- a/node/src/main/kotlin/com/r3corda/node/services/clientapi/NodeInterestRates.kt +++ b/node/src/main/kotlin/com/r3corda/node/services/clientapi/NodeInterestRates.kt @@ -1,5 +1,7 @@ package com.r3corda.node.services.clientapi +import co.paralleluniverse.fibers.Suspendable +import com.r3corda.core.RetryableException import com.r3corda.core.contracts.* import com.r3corda.core.crypto.DigitalSignature import com.r3corda.core.crypto.Party @@ -8,14 +10,19 @@ import com.r3corda.core.math.CubicSplineInterpolator import com.r3corda.core.math.Interpolator import com.r3corda.core.math.InterpolatorFactory import com.r3corda.core.node.services.ServiceType +import com.r3corda.core.protocols.ProtocolLogic +import com.r3corda.core.utilities.ProgressTracker import com.r3corda.node.internal.AbstractNode import com.r3corda.node.services.api.AbstractNodeService import com.r3corda.node.services.api.AcceptsFileUpload -import org.slf4j.LoggerFactory +import com.r3corda.node.utilities.FiberBox import com.r3corda.protocols.RatesFixProtocol +import org.slf4j.LoggerFactory import java.io.InputStream import java.math.BigDecimal import java.security.KeyPair +import java.time.Clock +import java.time.Instant import java.time.LocalDate import java.util.* import javax.annotation.concurrent.ThreadSafe @@ -36,7 +43,7 @@ object NodeInterestRates { */ class Service(node: AbstractNode) : AcceptsFileUpload, AbstractNodeService(node.services.networkService) { val ss = node.services.storageService - val oracle = NodeInterestRates.Oracle(ss.myLegalIdentity, ss.myLegalIdentityKey) + val oracle = Oracle(ss.myLegalIdentity, ss.myLegalIdentityKey, node.services.clock) private val logger = LoggerFactory.getLogger(Service::class.java) @@ -46,11 +53,42 @@ object NodeInterestRates { { message, e -> logger.error("Exception during interest rate oracle request processing", e) } ) addMessageHandler(RatesFixProtocol.TOPIC_QUERY, - { req: RatesFixProtocol.QueryRequest -> oracle.query(req.queries) }, + { req: RatesFixProtocol.QueryRequest -> + /** + * We put this into a protocol so that if it blocks waiting for the interest rate to become + * available, we a) don't block this thread and b) allow the fact we are waiting + * to be persisted/checkpointed. + * Interest rates become available when they are uploaded via the web as per [DataUploadServlet], + * if they haven't already been uploaded that way. + */ + node.smm.add("fixing", FixQueryHandler(this, req)) + return@addMessageHandler + }, { message, e -> logger.error("Exception during interest rate oracle request processing", e) } ) } + private class FixQueryHandler(val service: Service, val request: RatesFixProtocol.QueryRequest) : ProtocolLogic() { + companion object { + object RECEIVED : ProgressTracker.Step("Received fix request") + + object SENDING : ProgressTracker.Step("Sending fix response") + } + override val progressTracker = ProgressTracker(RECEIVED, SENDING) + + init { + progressTracker.currentStep = RECEIVED + } + + @Suspendable + override fun call(): Unit { + val answers = service.oracle.query(request.queries, request.deadline) + progressTracker.currentStep = SENDING + send("${RatesFixProtocol.TOPIC}.query", request.replyTo, request.sessionID!!, answers) + } + + } + // File upload support override val dataTypePrefix = "interest-rates" override val acceptableFileExtensions = listOf(".rates", ".txt") @@ -73,25 +111,44 @@ object NodeInterestRates { * The oracle will try to interpolate the missing value of a tenor for the given fix name and date. */ @ThreadSafe - class Oracle(val identity: Party, private val signingKey: KeyPair) { + class Oracle(val identity: Party, private val signingKey: KeyPair, val clock: Clock) { + private class InnerState { + var container: FixContainer = FixContainer(emptyList()) + + } + private val mutex = FiberBox(InnerState()) + + var knownFixes: FixContainer + set(value) { + require(value.size > 0) + mutex.write { + container = value + } + } + get() = mutex.read { container } + + // Make this the last bit of initialisation logic so fully constructed when entered into instances map init { require(signingKey.public == identity.owningKey) } - @Volatile var knownFixes = FixContainer(emptyList()) - set(value) { - require(value.size > 0) - field = value - } - - fun query(queries: List): List { + /** + * This method will now wait until the given deadline if the fix for the given [FixOf] is not immediately + * available. To implement this, [readWithDeadline] will loop if the deadline is not reached and we throw + * [UnknownFix] as it implements [RetryableException] which has special meaning to this function. + */ + @Suspendable + fun query(queries: List, deadline: Instant): List { require(queries.isNotEmpty()) - val knownFixes = knownFixes // Snapshot - val answers: List = queries.map { knownFixes[it] } - val firstNull = answers.indexOf(null) - if (firstNull != -1) - throw UnknownFix(queries[firstNull]) - return answers.filterNotNull() + return mutex.readWithDeadline(clock, deadline) { + val answers: List = queries.map { container[it] } + val firstNull = answers.indexOf(null) + if (firstNull != -1) { + throw UnknownFix(queries[firstNull]) + } else { + answers.filterNotNull() + } + } } fun sign(wtx: WireTransaction): DigitalSignature.LegallyIdentifiable { @@ -120,9 +177,8 @@ object NodeInterestRates { } } - class UnknownFix(val fix: FixOf) : Exception() { - override fun toString() = "Unknown fix: $fix" - } + // TODO: can we split into two? Fix not available (retryable/transient) and unknown (permanent) + class UnknownFix(val fix: FixOf) : RetryableException("Unknown fix: $fix") /** Fix container, for every fix name & date pair stores a tenor to interest rate map - [InterpolatingRateMap] */ class FixContainer(val fixes: List, val factory: InterpolatorFactory = CubicSplineInterpolator) { diff --git a/node/src/main/kotlin/com/r3corda/node/services/events/NodeSchedulerService.kt b/node/src/main/kotlin/com/r3corda/node/services/events/NodeSchedulerService.kt new file mode 100644 index 0000000000..dd6849d942 --- /dev/null +++ b/node/src/main/kotlin/com/r3corda/node/services/events/NodeSchedulerService.kt @@ -0,0 +1,177 @@ +package com.r3corda.node.services.events + +import com.google.common.util.concurrent.SettableFuture +import com.r3corda.core.ThreadBox +import com.r3corda.core.contracts.SchedulableState +import com.r3corda.core.contracts.ScheduledStateRef +import com.r3corda.core.contracts.StateRef +import com.r3corda.core.node.services.SchedulerService +import com.r3corda.core.protocols.ProtocolLogicRefFactory +import com.r3corda.core.serialization.SingletonSerializeAsToken +import com.r3corda.core.utilities.loggerFor +import com.r3corda.core.utilities.trace +import com.r3corda.node.services.api.ServiceHubInternal +import com.r3corda.node.utilities.awaitWithDeadline +import java.time.Instant +import java.util.* +import java.util.concurrent.Executor +import java.util.concurrent.Executors +import javax.annotation.concurrent.ThreadSafe + +/** + * A first pass of a simple [SchedulerService] that works with [MutableClock]s for testing, demonstrations and simulations + * that also encompasses the [Wallet] observer for processing transactions. + * + * This will observe transactions as they are stored and schedule and unschedule activities based on the States consumed + * or produced. + * + * TODO: Needs extensive support from persistence and protocol frameworks to be truly reliable and atomic. + * + * Currently does not provide any system state other than the ContractState so the expectation is that a transaction + * is the outcome of the activity in order to schedule another activity. Once we have implemented more persistence + * in the nodes, maybe we can consider multiple activities and whether the activities have been completed or not, + * but that starts to sound a lot like off-ledger state. + * + * @param services Core node services. + * @param protocolLogicRefFactory Factory for restoring [ProtocolLogic] instances from references. + * @param schedulerTimerExecutor The executor the scheduler blocks on waiting for the clock to advance to the next + * activity. Only replace this for unit testing purposes. This is not the executor the [ProtocolLogic] is launched on. + */ +@ThreadSafe +class NodeSchedulerService(private val services: ServiceHubInternal, + private val protocolLogicRefFactory: ProtocolLogicRefFactory = ProtocolLogicRefFactory(), + private val schedulerTimerExecutor: Executor = Executors.newSingleThreadExecutor()) +: SchedulerService, SingletonSerializeAsToken() { + + private val log = loggerFor() + + // Variables inside InnerState are protected with a lock by the ThreadBox and aren't in scope unless you're + // inside mutex.locked {} code block. So we can't forget to take the lock unless we accidentally leak a reference + // to somewhere. + private class InnerState { + // TODO: This has no persistence, and we don't consider initialising from non-empty map if we add persistence. + // If we were to rebuild the wallet at start up by replaying transactions and re-calculating, then + // persistence here would be unnecessary. + var scheduledStates = HashMap() + var earliestState: ScheduledStateRef? = null + var rescheduled: SettableFuture? = null + + internal fun recomputeEarliest() { + earliestState = scheduledStates.map { it.value }.sortedBy { it.scheduledAt }.firstOrNull() + } + } + + private val mutex = ThreadBox(InnerState()) + + override fun scheduleStateActivity(action: ScheduledStateRef) { + log.trace { "Schedule $action" } + mutex.locked { + scheduledStates[action.ref] = action + if (action.scheduledAt.isBefore(earliestState?.scheduledAt ?: Instant.MAX)) { + // We are earliest + earliestState = action + rescheduleWakeUp() + } else if (earliestState?.ref == action.ref && earliestState!!.scheduledAt != action.scheduledAt) { + // We were earliest but might not be any more + recomputeEarliest() + rescheduleWakeUp() + } + } + } + + override fun unscheduleStateActivity(ref: StateRef) { + log.trace { "Unschedule $ref" } + mutex.locked { + val removedAction = scheduledStates.remove(ref) + if (removedAction == earliestState && removedAction != null) { + recomputeEarliest() + rescheduleWakeUp() + } + } + } + + /** + * This method first cancels the [Future] for any pending action so that the [awaitWithDeadline] used below + * drops through without running the action. We then create a new [Future] for the new action (so it too can be + * cancelled), and then await the arrival of the scheduled time. If we reach the scheduled time (the deadline) + * without the [Future] being cancelled then we run the scheduled action. Finally we remove that action from the + * scheduled actions and recompute the next scheduled action. + */ + private fun rescheduleWakeUp() { + // Note, we already have the mutex but we need the scope again here + val (scheduledState, ourRescheduledFuture) = mutex.alreadyLocked { + rescheduled?.cancel(false) + rescheduled = SettableFuture.create() + Pair(earliestState, rescheduled!!) + } + if (scheduledState != null) { + schedulerTimerExecutor.execute() { + log.trace { "Scheduling as next $scheduledState" } + // This will block the scheduler single thread until the scheduled time (returns false) OR + // the Future is cancelled due to rescheduling (returns true). + if (!services.clock.awaitWithDeadline(scheduledState.scheduledAt, ourRescheduledFuture)) { + log.trace { "Invoking as next $scheduledState" } + onTimeReached(scheduledState) + } else { + log.trace { "Recheduled $scheduledState" } + } + } + } + } + + private fun onTimeReached(scheduledState: ScheduledStateRef) { + try { + runScheduledActionForState(scheduledState) + } finally { + // Unschedule once complete (or checkpointed) + mutex.locked { + // need to remove us from those scheduled, but only if we are still next + scheduledStates.compute(scheduledState.ref) { ref, value -> + if (value === scheduledState) null else value + } + // and schedule the next one + recomputeEarliest() + rescheduleWakeUp() + } + } + } + + private fun runScheduledActionForState(scheduledState: ScheduledStateRef) { + val txState = services.loadState(scheduledState.ref) + // It's OK to return if it's null as there's nothing scheduled + // TODO: implement sandboxing as necessary + val scheduledActivity = sandbox { + val state = txState.data as SchedulableState + state.nextScheduledActivity(scheduledState.ref, protocolLogicRefFactory) + } ?: return + + if (scheduledActivity.scheduledAt.isAfter(services.clock.instant())) { + // I suppose it might turn out that the action is no longer due (a bug, maybe), so we need to defend against that and re-schedule + // TODO: warn etc + mutex.locked { + // Replace with updated instant + scheduledStates.compute(scheduledState.ref) { ref, value -> + if (value === scheduledState) ScheduledStateRef(scheduledState.ref, scheduledActivity.scheduledAt) else value + } + } + } else { + /** + * TODO: align with protocol invocation via API... make it the same code + * TODO: Persistence and durability issues: + * a) Need to consider potential to run activity twice if restart between here and removing from map if we add persistence + * b) But if remove from map first, there's potential to run zero times if restart + * c) Address by switch to 3rd party scheduler? Only benefit of this impl. is support for DemoClock or other MutableClocks (e.g. for testing) + * TODO: ProtocolLogicRefFactory needs to sort out the class loader etc + */ + val logic = protocolLogicRefFactory.toProtocolLogic(scheduledActivity.logicRef) + log.trace { "Firing ProtocolLogic $logic" } + // TODO: ProtocolLogic should be checkpointed by the time this returns + services.startProtocol("scheduled", logic) + } + } + + // TODO: Does nothing right now, but beware we are calling dynamically loaded code in the contract inside here. + private inline fun sandbox(code: () -> T?): T? { + return code() + } +} \ No newline at end of file diff --git a/node/src/main/kotlin/com/r3corda/node/services/events/ScheduledActivityObserver.kt b/node/src/main/kotlin/com/r3corda/node/services/events/ScheduledActivityObserver.kt new file mode 100644 index 0000000000..be75393bed --- /dev/null +++ b/node/src/main/kotlin/com/r3corda/node/services/events/ScheduledActivityObserver.kt @@ -0,0 +1,35 @@ +package com.r3corda.node.services.events + +import com.r3corda.core.contracts.ContractState +import com.r3corda.core.contracts.SchedulableState +import com.r3corda.core.contracts.ScheduledStateRef +import com.r3corda.core.contracts.StateAndRef +import com.r3corda.core.protocols.ProtocolLogicRefFactory +import com.r3corda.node.services.api.ServiceHubInternal + +/** + * This observes the wallet and schedules and unschedules activities appropriately based on state production and + * consumption. + */ +class ScheduledActivityObserver(val services: ServiceHubInternal) { + init { + // TODO: Need to consider failure scenarios. This needs to run if the TX is successfully recorded + services.walletService.updates.subscribe { update -> + update.consumed.forEach { services.schedulerService.unscheduleStateActivity(it) } + update.produced.forEach { scheduleStateActivity(it, services.protocolLogicRefFactory) } + } + } + + private fun scheduleStateActivity(produced: StateAndRef, protocolLogicRefFactory: ProtocolLogicRefFactory) { + val producedState = produced.state.data + if (producedState is SchedulableState) { + val scheduledAt = sandbox { producedState.nextScheduledActivity(produced.ref, protocolLogicRefFactory)?.scheduledAt } ?: return + services.schedulerService.scheduleStateActivity(ScheduledStateRef(produced.ref, scheduledAt)) + } + } + + // TODO: Beware we are calling dynamically loaded contract code inside here. + private inline fun sandbox(code: () -> T?): T? { + return code() + } +} \ No newline at end of file diff --git a/node/src/test/kotlin/com/r3corda/node/services/MockServices.kt b/node/src/test/kotlin/com/r3corda/node/services/MockServices.kt index b600350ad8..72bd57df44 100644 --- a/node/src/test/kotlin/com/r3corda/node/services/MockServices.kt +++ b/node/src/test/kotlin/com/r3corda/node/services/MockServices.kt @@ -2,9 +2,12 @@ package com.r3corda.node.services import com.codahale.metrics.MetricRegistry import com.r3corda.core.contracts.SignedTransaction +import com.google.common.util.concurrent.ListenableFuture import com.r3corda.core.messaging.MessagingService import com.r3corda.core.node.services.* import com.r3corda.core.node.services.testing.MockStorageService +import com.r3corda.core.protocols.ProtocolLogic +import com.r3corda.core.protocols.ProtocolLogicRefFactory import com.r3corda.core.testing.MOCK_IDENTITY_SERVICE import com.r3corda.node.serialization.NodeClock import com.r3corda.node.services.api.MonitoringService @@ -12,6 +15,7 @@ import com.r3corda.node.services.api.ServiceHubInternal import com.r3corda.node.services.network.MockNetworkMapCache import com.r3corda.node.services.network.NetworkMapService import com.r3corda.node.services.persistence.DataVendingService +import com.r3corda.node.services.statemachine.StateMachineManager import com.r3corda.node.services.wallet.NodeWalletService import java.time.Clock @@ -23,10 +27,11 @@ open class MockServices( val storage: TxWritableStorageService? = MockStorageService(), val mapCache: NetworkMapCache? = MockNetworkMapCache(), val mapService: NetworkMapService? = null, - val overrideClock: Clock? = NodeClock() + val scheduler: SchedulerService? = null, + val overrideClock: Clock? = NodeClock(), + val protocolFactory: ProtocolLogicRefFactory? = ProtocolLogicRefFactory() ) : ServiceHubInternal() { override val walletService: WalletService = customWallet ?: NodeWalletService(this) - override val keyManagementService: KeyManagementService get() = keyManagement ?: throw UnsupportedOperationException() override val identityService: IdentityService @@ -37,10 +42,15 @@ open class MockServices( get() = mapCache ?: throw UnsupportedOperationException() override val storageService: StorageService get() = storage ?: throw UnsupportedOperationException() + override val schedulerService: SchedulerService + get() = scheduler ?: throw UnsupportedOperationException() override val clock: Clock get() = overrideClock ?: throw UnsupportedOperationException() override val monitoringService: MonitoringService = MonitoringService(MetricRegistry()) + override val protocolLogicRefFactory: ProtocolLogicRefFactory + get() = protocolFactory ?: throw UnsupportedOperationException() + // We isolate the storage service with writable TXes so that it can't be accessed except via recordTransactions() private val txStorageService: TxWritableStorageService get() = storage ?: throw UnsupportedOperationException() @@ -48,6 +58,12 @@ open class MockServices( override fun recordTransactions(txs: Iterable) = recordTransactionsInternal(txStorageService, txs) + lateinit var smm: StateMachineManager + + override fun startProtocol(loggerName: String, logic: ProtocolLogic): ListenableFuture { + return smm.add(loggerName, logic) + } + init { if (net != null && storage != null) { // Creating this class is sufficient, we don't have to store it anywhere, because it registers a listener diff --git a/node/src/test/kotlin/com/r3corda/node/services/NodeInterestRatesTest.kt b/node/src/test/kotlin/com/r3corda/node/services/NodeInterestRatesTest.kt index 4062170da1..983db252d8 100644 --- a/node/src/test/kotlin/com/r3corda/node/services/NodeInterestRatesTest.kt +++ b/node/src/test/kotlin/com/r3corda/node/services/NodeInterestRatesTest.kt @@ -21,6 +21,8 @@ import com.r3corda.node.services.clientapi.NodeInterestRates import com.r3corda.protocols.RatesFixProtocol import org.junit.Assert import org.junit.Test +import java.time.Clock +import java.time.Duration import kotlin.test.assertEquals import kotlin.test.assertFailsWith @@ -37,11 +39,12 @@ class NodeInterestRatesTest { val DUMMY_CASH_ISSUER_KEY = generateKeyPair() val DUMMY_CASH_ISSUER = Party("Cash issuer", DUMMY_CASH_ISSUER_KEY.public) - val oracle = NodeInterestRates.Oracle(MEGA_CORP, MEGA_CORP_KEY).apply { knownFixes = TEST_DATA } + val clock = Clock.systemUTC() + val oracle = NodeInterestRates.Oracle(MEGA_CORP, MEGA_CORP_KEY, clock).apply { knownFixes = TEST_DATA } @Test fun `query successfully`() { val q = NodeInterestRates.parseFixOf("LIBOR 2016-03-16 1M") - val res = oracle.query(listOf(q)) + val res = oracle.query(listOf(q), clock.instant()) assertEquals(1, res.size) assertEquals("0.678".bd, res[0].value) assertEquals(q, res[0].of) @@ -50,13 +53,13 @@ class NodeInterestRatesTest { @Test fun `query with one success and one missing`() { val q1 = NodeInterestRates.parseFixOf("LIBOR 2016-03-16 1M") val q2 = NodeInterestRates.parseFixOf("LIBOR 2016-03-15 1M") - val e = assertFailsWith { oracle.query(listOf(q1, q2)) } + val e = assertFailsWith { oracle.query(listOf(q1, q2), clock.instant()) } assertEquals(e.fix, q2) } @Test fun `query successfully with interpolated rate`() { val q = NodeInterestRates.parseFixOf("LIBOR 2016-03-16 5M") - val res = oracle.query(listOf(q)) + val res = oracle.query(listOf(q), clock.instant()) assertEquals(1, res.size) Assert.assertEquals(0.7316228, res[0].value.toDouble(), 0.0000001) assertEquals(q, res[0].of) @@ -64,11 +67,11 @@ class NodeInterestRatesTest { @Test fun `rate missing and unable to interpolate`() { val q = NodeInterestRates.parseFixOf("EURIBOR 2016-03-15 3M") - assertFailsWith { oracle.query(listOf(q)) } + assertFailsWith { oracle.query(listOf(q), clock.instant()) } } @Test fun `empty query`() { - assertFailsWith { oracle.query(emptyList()) } + assertFailsWith { oracle.query(emptyList(), clock.instant()) } } @Test fun `refuse to sign with no relevant commands`() { @@ -80,7 +83,7 @@ class NodeInterestRatesTest { @Test fun `sign successfully`() { val tx = makeTX() - val fix = oracle.query(listOf(NodeInterestRates.parseFixOf("LIBOR 2016-03-16 1M"))).first() + val fix = oracle.query(listOf(NodeInterestRates.parseFixOf("LIBOR 2016-03-16 1M")), clock.instant()).first() tx.addCommand(fix, oracle.identity.owningKey) // Sign successfully. @@ -106,7 +109,7 @@ class NodeInterestRatesTest { val tx = TransactionType.General.Builder() val fixOf = NodeInterestRates.parseFixOf("LIBOR 2016-03-16 1M") - val protocol = RatesFixProtocol(tx, n2.info, fixOf, "0.675".bd, "0.1".bd) + val protocol = RatesFixProtocol(tx, n2.info, fixOf, "0.675".bd, "0.1".bd, Duration.ofNanos(1)) BriefLogFormatter.initVerbose("rates") val future = n1.smm.add("rates", protocol) diff --git a/node/src/test/kotlin/com/r3corda/node/services/NodeSchedulerServiceTest.kt b/node/src/test/kotlin/com/r3corda/node/services/NodeSchedulerServiceTest.kt new file mode 100644 index 0000000000..20a7d14edb --- /dev/null +++ b/node/src/test/kotlin/com/r3corda/node/services/NodeSchedulerServiceTest.kt @@ -0,0 +1,247 @@ +package com.r3corda.node.services + +import com.google.common.jimfs.Configuration +import com.google.common.jimfs.Jimfs +import com.r3corda.core.contracts.* +import com.r3corda.core.crypto.SecureHash +import com.r3corda.core.days +import com.r3corda.core.node.ServiceHub +import com.r3corda.core.node.services.testing.MockKeyManagementService +import com.r3corda.core.protocols.ProtocolLogic +import com.r3corda.core.protocols.ProtocolLogicRef +import com.r3corda.core.protocols.ProtocolLogicRefFactory +import com.r3corda.core.serialization.SingletonSerializeAsToken +import com.r3corda.core.testing.ALICE_KEY +import com.r3corda.core.testing.DUMMY_NOTARY +import com.r3corda.node.internal.testing.TestClock +import com.r3corda.node.services.events.NodeSchedulerService +import com.r3corda.node.services.network.InMemoryMessagingNetwork +import com.r3corda.node.services.persistence.PerFileCheckpointStorage +import com.r3corda.node.services.statemachine.StateMachineManager +import com.r3corda.node.utilities.AffinityExecutor +import org.assertj.core.api.Assertions.assertThat +import org.junit.Before +import org.junit.Test +import java.nio.file.FileSystem +import java.security.PublicKey +import java.time.Clock +import java.time.Instant +import java.util.concurrent.CountDownLatch +import java.util.concurrent.Executors +import java.util.concurrent.TimeUnit + +class NodeSchedulerServiceTest : SingletonSerializeAsToken() { + // Use an in memory file system for testing attachment storage. + val fs: FileSystem = Jimfs.newFileSystem(Configuration.unix()) + + val realClock: Clock = Clock.systemUTC() + val stoppedClock = Clock.fixed(realClock.instant(), realClock.zone) + val testClock = TestClock(stoppedClock) + + val smmExecutor = AffinityExecutor.ServiceAffinityExecutor("test", 1) + val schedulerGatedExecutor = AffinityExecutor.Gate(true) + + // We have to allow Java boxed primitives but Kotlin warns we shouldn't be using them + @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") + val factory = ProtocolLogicRefFactory(setOf(TestProtocolLogic::class.java.name), setOf(NodeSchedulerServiceTest::class.java.name, Integer::class.java.name)) + + val scheduler: NodeSchedulerService + val services: ServiceHub + + /** + * Have a reference to this test added to [ServiceHub] so that when the [ProtocolLogic] runs it can access the test instance. + * The [TestState] is serialized and deserialized so attempting to use a transient field won't work, as it just + * results in NPE. + */ + interface TestReference { + val testReference: NodeSchedulerServiceTest + } + + init { + val kms = MockKeyManagementService(ALICE_KEY) + val mockMessagingService = InMemoryMessagingNetwork(false).InMemoryMessaging(false, InMemoryMessagingNetwork.Handle(0, "None")) + val mockServices = object : MockServices(overrideClock = testClock, keyManagement = kms, net = mockMessagingService), TestReference { + override val testReference = this@NodeSchedulerServiceTest + } + services = mockServices + scheduler = NodeSchedulerService(mockServices, factory, schedulerGatedExecutor) + val mockSMM = StateMachineManager(mockServices, listOf(mockServices), PerFileCheckpointStorage(fs.getPath("checkpoints")), smmExecutor) + mockServices.smm = mockSMM + } + + lateinit var countDown: CountDownLatch + var calls: Int = 0 + + @Before + fun setup() { + countDown = CountDownLatch(1) + calls = 0 + } + + class TestState(val protocolLogicRef: ProtocolLogicRef, val instant: Instant) : LinearState, SchedulableState { + override val participants: List + get() = throw UnsupportedOperationException() + + override val thread = SecureHash.sha256("does not matter but we need it to be unique ${Math.random()}") + + override fun isRelevant(ourKeys: Set): Boolean = true + + override fun nextScheduledActivity(thisStateRef: StateRef, protocolLogicRefFactory: ProtocolLogicRefFactory): ScheduledActivity? = ScheduledActivity(protocolLogicRef, instant) + + override val contract: Contract + get() = throw UnsupportedOperationException() + } + + class TestProtocolLogic(val increment: Int = 1) : ProtocolLogic() { + override fun call() { + (serviceHub as TestReference).testReference.calls += increment + (serviceHub as TestReference).testReference.countDown.countDown() + } + } + + class Command : TypeOnlyCommandData() + + @Test + fun `test activity due now`() { + val time = stoppedClock.instant() + scheduleTX(time) + + assertThat(calls).isEqualTo(0) + schedulerGatedExecutor.waitAndRun() + countDown.await(60, TimeUnit.SECONDS) + assertThat(calls).isEqualTo(1) + } + + @Test + fun `test activity due in the past`() { + val time = stoppedClock.instant() - 1.days + scheduleTX(time) + + assertThat(calls).isEqualTo(0) + schedulerGatedExecutor.waitAndRun() + countDown.await(60, TimeUnit.SECONDS) + assertThat(calls).isEqualTo(1) + } + + @Test + fun `test activity due in the future`() { + val time = stoppedClock.instant() + 1.days + scheduleTX(time) + + val backgroundExecutor = Executors.newSingleThreadExecutor() + backgroundExecutor.execute { schedulerGatedExecutor.waitAndRun() } + assertThat(calls).isEqualTo(0) + testClock.advanceBy(1.days) + backgroundExecutor.shutdown() + backgroundExecutor.awaitTermination(60, TimeUnit.SECONDS) + countDown.await(60, TimeUnit.SECONDS) + assertThat(calls).isEqualTo(1) + } + + @Test + fun `test activity due in the future and schedule another earlier`() { + val time = stoppedClock.instant() + 1.days + scheduleTX(time + 1.days) + + val backgroundExecutor = Executors.newSingleThreadExecutor() + backgroundExecutor.execute { schedulerGatedExecutor.waitAndRun() } + assertThat(calls).isEqualTo(0) + scheduleTX(time, 3) + + backgroundExecutor.execute { schedulerGatedExecutor.waitAndRun() } + testClock.advanceBy(1.days) + countDown.await(60, TimeUnit.SECONDS) + assertThat(calls).isEqualTo(3) + backgroundExecutor.shutdown() + backgroundExecutor.awaitTermination(60, TimeUnit.SECONDS) + } + + @Test + fun `test activity due in the future and schedule another later`() { + val time = stoppedClock.instant() + 1.days + scheduleTX(time) + + val backgroundExecutor = Executors.newSingleThreadExecutor() + backgroundExecutor.execute { schedulerGatedExecutor.waitAndRun() } + assertThat(calls).isEqualTo(0) + scheduleTX(time + 1.days, 3) + + backgroundExecutor.execute { schedulerGatedExecutor.waitAndRun() } + testClock.advanceBy(1.days) + countDown.await(60, TimeUnit.SECONDS) + assertThat(calls).isEqualTo(1) + testClock.advanceBy(1.days) + backgroundExecutor.shutdown() + backgroundExecutor.awaitTermination(60, TimeUnit.SECONDS) + } + + @Test + fun `test activity due in the future and schedule another for same time`() { + val time = stoppedClock.instant() + 1.days + scheduleTX(time) + + val backgroundExecutor = Executors.newSingleThreadExecutor() + backgroundExecutor.execute { schedulerGatedExecutor.waitAndRun() } + assertThat(calls).isEqualTo(0) + scheduleTX(time, 3) + + testClock.advanceBy(1.days) + countDown.await(60, TimeUnit.SECONDS) + assertThat(calls).isEqualTo(1) + backgroundExecutor.shutdown() + backgroundExecutor.awaitTermination(60, TimeUnit.SECONDS) + } + + @Test + fun `test activity due in the future and schedule another for same time then unschedule original`() { + val time = stoppedClock.instant() + 1.days + var scheduledRef1 = scheduleTX(time) + + val backgroundExecutor = Executors.newSingleThreadExecutor() + backgroundExecutor.execute { schedulerGatedExecutor.waitAndRun() } + assertThat(calls).isEqualTo(0) + scheduleTX(time, 3) + + backgroundExecutor.execute { schedulerGatedExecutor.waitAndRun() } + scheduler.unscheduleStateActivity(scheduledRef1!!.ref) + testClock.advanceBy(1.days) + countDown.await(60, TimeUnit.SECONDS) + assertThat(calls).isEqualTo(3) + backgroundExecutor.shutdown() + backgroundExecutor.awaitTermination(60, TimeUnit.SECONDS) + } + + @Test + fun `test activity due in the future then unschedule`() { + var scheduledRef1 = scheduleTX(stoppedClock.instant() + 1.days) + + val backgroundExecutor = Executors.newSingleThreadExecutor() + backgroundExecutor.execute { schedulerGatedExecutor.waitAndRun() } + assertThat(calls).isEqualTo(0) + + scheduler.unscheduleStateActivity(scheduledRef1!!.ref) + testClock.advanceBy(1.days) + assertThat(calls).isEqualTo(0) + backgroundExecutor.shutdown() + backgroundExecutor.awaitTermination(60, TimeUnit.SECONDS) + } + + private fun scheduleTX(instant: Instant, increment: Int = 1): ScheduledStateRef? { + var scheduledRef: ScheduledStateRef? = null + apply { + val freshKey = services.keyManagementService.freshKey() + val state = TestState(factory.create(TestProtocolLogic::class.java, increment), instant) + val usefulTX = TransactionType.General.Builder(DUMMY_NOTARY).apply { + addOutputState(state) + addCommand(Command(), freshKey.public) + signWith(freshKey) + }.toSignedTransaction() + val txHash = usefulTX.id + + services.recordTransactions(usefulTX) + scheduledRef = ScheduledStateRef(StateRef(txHash, 0), state.instant) + scheduler.scheduleStateActivity(scheduledRef!!) + } + return scheduledRef + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt index e1d18d390a..57a9bc63cf 100644 --- a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt @@ -1,18 +1,11 @@ package com.r3corda.demos import com.google.common.net.HostAndPort -import com.typesafe.config.ConfigFactory import com.r3corda.core.crypto.Party import com.r3corda.core.logElapsedTime import com.r3corda.core.messaging.SingleMessageRecipient -import com.r3corda.node.internal.Node -import com.r3corda.node.services.config.NodeConfiguration -import com.r3corda.node.services.config.NodeConfigurationFromConfig import com.r3corda.core.node.NodeInfo -import com.r3corda.node.services.network.NetworkMapService -import com.r3corda.node.services.clientapi.NodeInterestRates import com.r3corda.core.node.services.ServiceType -import com.r3corda.node.services.messaging.ArtemisMessagingService import com.r3corda.core.serialization.deserialize import com.r3corda.core.utilities.BriefLogFormatter import com.r3corda.demos.api.InterestRateSwapAPI @@ -20,13 +13,23 @@ import com.r3corda.demos.protocols.AutoOfferProtocol import com.r3corda.demos.protocols.ExitServerProtocol import com.r3corda.demos.protocols.UpdateBusinessDayProtocol import com.r3corda.node.internal.AbstractNode +import com.r3corda.node.internal.Node import com.r3corda.node.internal.testing.MockNetwork +import com.r3corda.node.services.FixingSessionInitiationHandler +import com.r3corda.node.services.clientapi.NodeInterestRates +import com.r3corda.node.services.config.NodeConfiguration +import com.r3corda.node.services.config.NodeConfigurationFromConfig +import com.r3corda.node.services.messaging.ArtemisMessagingService +import com.r3corda.node.services.network.NetworkMapService import com.r3corda.node.services.transactions.SimpleNotaryService +import com.typesafe.config.ConfigFactory import joptsimple.OptionParser import joptsimple.OptionSet +import org.apache.commons.io.IOUtils import java.io.DataOutputStream import java.io.File import java.net.HttpURLConnection +import java.net.SocketTimeoutException import java.net.URL import java.nio.file.Files import java.nio.file.Path @@ -34,8 +37,6 @@ import java.nio.file.Paths import java.util.* import kotlin.concurrent.fixedRateTimer import kotlin.system.exitProcess -import org.apache.commons.io.IOUtils -import java.net.SocketTimeoutException // IRS DEMO // @@ -304,6 +305,7 @@ private fun runNode(cliParams: CliParams.RunNode): Int { AutoOfferProtocol.Handler.register(node) UpdateBusinessDayProtocol.Handler.register(node) ExitServerProtocol.Handler.register(node) + FixingSessionInitiationHandler.register(node) if (cliParams.uploadRates) { runUploadRates(cliParams.apiAddress) diff --git a/src/main/kotlin/com/r3corda/demos/RateFixDemo.kt b/src/main/kotlin/com/r3corda/demos/RateFixDemo.kt index 97bbbf2e4c..007cc51e36 100644 --- a/src/main/kotlin/com/r3corda/demos/RateFixDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/RateFixDemo.kt @@ -4,6 +4,7 @@ import com.google.common.net.HostAndPort import com.r3corda.contracts.cash.Cash import com.r3corda.core.contracts.* import com.r3corda.core.crypto.Party +import com.r3corda.core.hours import com.r3corda.core.logElapsedTime import com.r3corda.core.node.NodeInfo import com.r3corda.core.node.services.ServiceType @@ -83,7 +84,7 @@ fun main(args: Array) { // Make a garbage transaction that includes a rate fix. val tx = TransactionType.General.Builder() tx.addOutputState(TransactionState(Cash.State(1500.DOLLARS `issued by` node.storage.myLegalIdentity.ref(1), node.keyManagement.freshKey().public), notary.identity)) - val protocol = RatesFixProtocol(tx, oracleNode, fixOf, expectedRate, rateTolerance) + val protocol = RatesFixProtocol(tx, oracleNode, fixOf, expectedRate, rateTolerance, 24.hours) node.smm.add("demo.ratefix", protocol).get() node.stop() diff --git a/src/main/kotlin/com/r3corda/demos/protocols/AutoOfferProtocol.kt b/src/main/kotlin/com/r3corda/demos/protocols/AutoOfferProtocol.kt index c90561608c..2be25b79b4 100644 --- a/src/main/kotlin/com/r3corda/demos/protocols/AutoOfferProtocol.kt +++ b/src/main/kotlin/com/r3corda/demos/protocols/AutoOfferProtocol.kt @@ -25,6 +25,7 @@ object AutoOfferProtocol { val TOPIC = "autooffer.topic" data class AutoOfferMessage(val otherSide: SingleMessageRecipient, + val notary: Party, val otherSessionID: Long, val dealBeingOffered: DealState) object Handler { @@ -53,9 +54,7 @@ object AutoOfferProtocol { val autoOfferMessage = msg.data.deserialize() // Put the deal onto the ledger progressTracker.currentStep = DEALING - // TODO required as messaging layer does not currently queue messages that arrive before we expect them - Thread.sleep(100) - val seller = TwoPartyDealProtocol.Instigator(autoOfferMessage.otherSide, node.services.networkMapCache.notaryNodes.first(), + val seller = TwoPartyDealProtocol.Instigator(autoOfferMessage.otherSide, autoOfferMessage.notary, autoOfferMessage.dealBeingOffered, node.services.keyManagementService.freshKey(), autoOfferMessage.otherSessionID, progressTracker.getChildProgressTracker(DEALING)!!) val future = node.smm.add("${TwoPartyDealProtocol.DEAL_TOPIC}.seller", seller) // This is required because we are doing child progress outside of a subprotocol. In future, we should just wrap things like this in a protocol to avoid it @@ -94,16 +93,16 @@ object AutoOfferProtocol { require(serviceHub.networkMapCache.notaryNodes.isNotEmpty()) { "No notary nodes registered" } val ourSessionID = random63BitValue() - val notary = serviceHub.networkMapCache.notaryNodes.first() + val notary = serviceHub.networkMapCache.notaryNodes.first().identity // need to pick which ever party is not us val otherParty = notUs(*dealToBeOffered.parties).single() val otherNode = (serviceHub.networkMapCache.getNodeByLegalName(otherParty.name)) requireNotNull(otherNode) { "Cannot identify other party " + otherParty.name + ", know about: " + serviceHub.networkMapCache.partyNodes.map { it.identity } } val otherSide = otherNode!!.address progressTracker.currentStep = ANNOUNCING - send(TOPIC, otherSide, 0, AutoOfferMessage(serviceHub.networkService.myAddress, ourSessionID, dealToBeOffered)) + send(TOPIC, otherSide, 0, AutoOfferMessage(serviceHub.networkService.myAddress, notary, ourSessionID, dealToBeOffered)) progressTracker.currentStep = DEALING - val stx = subProtocol(TwoPartyDealProtocol.Acceptor(otherSide, notary.identity, dealToBeOffered, ourSessionID, progressTracker.getChildProgressTracker(DEALING)!!)) + val stx = subProtocol(TwoPartyDealProtocol.Acceptor(otherSide, notary, dealToBeOffered, ourSessionID, progressTracker.getChildProgressTracker(DEALING)!!)) return stx } diff --git a/src/main/kotlin/com/r3corda/demos/protocols/UpdateBusinessDayProtocol.kt b/src/main/kotlin/com/r3corda/demos/protocols/UpdateBusinessDayProtocol.kt index 452e315871..c702be19fc 100644 --- a/src/main/kotlin/com/r3corda/demos/protocols/UpdateBusinessDayProtocol.kt +++ b/src/main/kotlin/com/r3corda/demos/protocols/UpdateBusinessDayProtocol.kt @@ -1,171 +1,50 @@ package com.r3corda.demos.protocols import co.paralleluniverse.fibers.Suspendable -import com.r3corda.contracts.InterestRateSwap -import com.r3corda.core.contracts.DealState -import com.r3corda.core.contracts.StateAndRef -import com.r3corda.core.contracts.TransactionState import com.r3corda.core.node.NodeInfo -import com.r3corda.core.node.services.linearHeadsOfType import com.r3corda.core.protocols.ProtocolLogic -import com.r3corda.core.random63BitValue import com.r3corda.core.serialization.deserialize import com.r3corda.core.utilities.ProgressTracker import com.r3corda.demos.DemoClock import com.r3corda.node.internal.Node import com.r3corda.node.services.network.MockNetworkMapCache -import com.r3corda.node.utilities.ANSIProgressRenderer -import com.r3corda.protocols.TwoPartyDealProtocol import java.time.LocalDate /** - * This is a very temporary, demo-oriented way of initiating processing of temporal events and is not - * intended as the way things will necessarily be done longer term + * This is a less temporary, demo-oriented way of initiating processing of temporal events */ object UpdateBusinessDayProtocol { val TOPIC = "businessday.topic" - class Updater(val date: LocalDate, val sessionID: Long, - override val progressTracker: ProgressTracker = Updater.tracker()) : ProtocolLogic() { - - companion object { - object FETCHING : ProgressTracker.Step("Fetching deals") - object ITERATING_DEALS : ProgressTracker.Step("Interating over deals") - object ITERATING_FIXINGS : ProgressTracker.Step("Iterating over fixings") - object FIXING : ProgressTracker.Step("Fixing deal") - - fun tracker() = ProgressTracker(FETCHING, ITERATING_DEALS, ITERATING_FIXINGS, FIXING) - } - - @Suspendable - override fun call(): Boolean { - // Get deals - progressTracker.currentStep = FETCHING - val dealStateRefs = serviceHub.walletService.linearHeadsOfType() - val otherPartyToDeals = dealStateRefs.values.groupBy { otherParty(it.state.data) } - - // TODO we need to process these in parallel to stop there being an ordering problem across more than two nodes - val sortedParties = otherPartyToDeals.keys.sortedBy { it.identity.name } - for (party in sortedParties) { - val sortedDeals = otherPartyToDeals[party]!!.sortedBy { it.state.data.ref } - for (deal in sortedDeals) { - progressTracker.currentStep = ITERATING_DEALS - processDeal(party, deal, date, sessionID) - } - } - return false - } - - // This assumes we definitely have one key or the other - fun otherParty(deal: DealState): NodeInfo { - val ourKeys = serviceHub.keyManagementService.keys.keys - return serviceHub.networkMapCache.getNodeByLegalName(deal.parties.single { !ourKeys.contains(it.owningKey) }.name)!! - } - - // TODO we should make this more object oriented when we can ask a state for it's contract - @Suspendable - fun processDeal(party: NodeInfo, deal: StateAndRef, date: LocalDate, sessionID: Long) { - val s = deal.state.data - when (s) { - is InterestRateSwap.State -> processInterestRateSwap(party, StateAndRef(TransactionState(s, deal.state.notary), deal.ref), date, sessionID) - } - } - - // TODO and this would move to the InterestRateSwap and cope with permutations of Fixed/Floating and Floating/Floating etc - @Suspendable - fun processInterestRateSwap(party: NodeInfo, deal: StateAndRef, date: LocalDate, sessionID: Long) { - var dealStateAndRef: StateAndRef? = deal - var nextFixingDate = deal.state.data.calculation.nextFixingDate() - while (nextFixingDate != null && !nextFixingDate.isAfter(date)) { - progressTracker.currentStep = ITERATING_FIXINGS - /* - * Note that this choice of fixed versus floating leg is simply to assign roles in - * the fixing protocol and doesn't infer roles or responsibilities in a business sense. - * One of the parties needs to take the lead in the coordination and this is a reliable deterministic way - * to do it. - */ - if (party.identity.name == deal.state.data.fixedLeg.fixedRatePayer.name) { - dealStateAndRef = nextFixingFloatingLeg(dealStateAndRef!!, party, sessionID) - } else { - dealStateAndRef = nextFixingFixedLeg(dealStateAndRef!!, party, sessionID) - } - nextFixingDate = dealStateAndRef?.state?.data?.calculation?.nextFixingDate() - } - } - - @Suspendable - private fun nextFixingFloatingLeg(dealStateAndRef: StateAndRef, party: NodeInfo, sessionID: Long): StateAndRef? { - progressTracker.setChildProgressTracker(FIXING, TwoPartyDealProtocol.Primary.tracker()) - progressTracker.currentStep = FIXING - - val myName = serviceHub.storageService.myLegalIdentity.name - val deal: InterestRateSwap.State = dealStateAndRef.state.data - val myOldParty = deal.parties.single { it.name == myName } - val keyPair = serviceHub.keyManagementService.toKeyPair(myOldParty.owningKey) - val participant = TwoPartyDealProtocol.Floater(party.address, sessionID, serviceHub.networkMapCache.notaryNodes[0], dealStateAndRef, - keyPair, - sessionID, progressTracker.getChildProgressTracker(FIXING)!!) - val result = subProtocol(participant) - return result.tx.outRef(0) - } - - @Suspendable - private fun nextFixingFixedLeg(dealStateAndRef: StateAndRef, party: NodeInfo, sessionID: Long): StateAndRef? { - progressTracker.setChildProgressTracker(FIXING, TwoPartyDealProtocol.Secondary.tracker()) - progressTracker.currentStep = FIXING - - val participant = TwoPartyDealProtocol.Fixer( - party.address, - serviceHub.networkMapCache.notaryNodes[0].identity, - dealStateAndRef, - sessionID, - progressTracker.getChildProgressTracker(FIXING)!!) - val result = subProtocol(participant) - return result.tx.outRef(0) - } - } - - data class UpdateBusinessDayMessage(val date: LocalDate, val sessionID: Long) + data class UpdateBusinessDayMessage(val date: LocalDate) object Handler { + fun register(node: Node) { - node.net.addMessageHandler("$TOPIC.0") { msg, registration -> - // Just to validate we got the message + node.net.addMessageHandler("${TOPIC}.0") { msg, registration -> val updateBusinessDayMessage = msg.data.deserialize() - if ((node.services.clock as DemoClock).updateDate(updateBusinessDayMessage.date)) { - val participant = Updater(updateBusinessDayMessage.date, updateBusinessDayMessage.sessionID) - node.smm.add("update.business.day", participant) - } + (node.services.clock as DemoClock).updateDate(updateBusinessDayMessage.date) } } } class Broadcast(val date: LocalDate, - override val progressTracker: ProgressTracker = Broadcast.tracker()) : ProtocolLogic() { + override val progressTracker: ProgressTracker = Broadcast.tracker()) : ProtocolLogic() { companion object { - object NOTIFYING : ProgressTracker.Step("Notifying peer") - object LOCAL : ProgressTracker.Step("Updating locally") { - override fun childProgressTracker(): ProgressTracker = Updater.tracker() - } + object NOTIFYING : ProgressTracker.Step("Notifying peers") - fun tracker() = ProgressTracker(NOTIFYING, LOCAL) + fun tracker() = ProgressTracker(NOTIFYING) } @Suspendable - override fun call(): Boolean { - val message = UpdateBusinessDayMessage(date, random63BitValue()) - + override fun call(): Unit { + progressTracker.currentStep = NOTIFYING + val message = UpdateBusinessDayMessage(date) for (recipient in serviceHub.networkMapCache.partyNodes) { - progressTracker.currentStep = NOTIFYING doNextRecipient(recipient, message) } - if ((serviceHub.clock as DemoClock).updateDate(message.date)) { - progressTracker.currentStep = LOCAL - subProtocol(Updater(message.date, message.sessionID, progressTracker.getChildProgressTracker(LOCAL)!!)) - } - return true } @Suspendable @@ -173,10 +52,7 @@ object UpdateBusinessDayProtocol { if (recipient.address is MockNetworkMapCache.MockAddress) { // Ignore } else { - // TODO: messaging ourselves seems to trigger a bug for the time being and we continuously receive messages - if (recipient.identity != serviceHub.storageService.myLegalIdentity) { - send(TOPIC, recipient.address, 0, message) - } + send(TOPIC, recipient.address, 0, message) } } } From 55675ef7991ad5ff711fa87aefda6a598739b948 Mon Sep 17 00:00:00 2001 From: Mike Hearn Date: Thu, 30 Jun 2016 11:52:31 +0200 Subject: [PATCH 064/114] Refresh docs for M1 release. --- docs/source/inthebox.rst | 45 ++++++++---------- docs/source/release-notes.rst | 76 ++++++++++++++++++++++++------- docs/source/running-the-demos.rst | 4 +- 3 files changed, 81 insertions(+), 44 deletions(-) diff --git a/docs/source/inthebox.rst b/docs/source/inthebox.rst index 690932881c..8747037280 100644 --- a/docs/source/inthebox.rst +++ b/docs/source/inthebox.rst @@ -1,46 +1,46 @@ What's included? ================ -The current prototype consists of a small amount of code that defines: +The Corda prototype currently includes: -* Key data structures. +* A peer to peer network with message persistence and delivery retries. +* Key data structures for defining contracts and states. +* Smart contracts: + * Cash + * Cash obligations + * Interest rate swaps + * Commercial paper (implemented in both Java and Kotlin for comparison) * Algorithms that work with them, such as serialising, hashing, signing, and verification of the signatures. -* Two smart contracts that implement a notion of a cash claim and basic commercial paper (implemented twice, in two - different programming languages). These are simplified versions of the real things. -* Unit tests that check the algorithms do what is expected, and which verify the behaviour of the smart contracts. -* API documentation and tutorials (what you're reading) -* A simple standalone node that uses an embedded message queue broker as its P2P messaging layer. -* A trading demo that runs the node in either a listening/buying mode, or a connecting/selling mode, and swaps some - fake commercial paper assets for some self-issued IOU cash, using a generic *protocol framework*. -* It also includes two oracles: one for precise timestamping and another for interest rate swaps. +* API documentation and tutorials (what you're reading). +* A business process orchestration framework. +* Notary infrastructure for precise timestamping, and elimination of double spending without a blockchain. +* A simple REST API. Some things it does not currently include but should gain later are: * Sandboxing, distribution or publication of smart contract code -* A peer to peer network * Database persistence -* An API for integrating external software * A user interface for administration * Many other things -You can browse `the JIRA bug tracker `_. - The prototype's goal is rapid exploration of ideas. Therefore in places it takes shortcuts that a production system would not in order to boost productivity: * It uses an object graph serialization framework instead of a well specified, vendor neutral protocol. -* It uses secp256r1, an obsolete elliptic curve. * It uses the default, out of the box Apache Artemis MQ protocol instead of AMQP/1.0 (although switching should be easy) +* There is no inter-node SSL or other encryption yet. Contracts --------- The primary goal of this prototype is to implement various kinds of contracts and verify that useful business logic can be expressed with the data model, developing and refining an API along the way. To that end there are currently -two contracts in the repository: +four contracts in the repository: 1. Cash 2. Commercial paper +3. Nettable obligations +4. Commercial paper ``Cash`` implements the idea of a claim on some quantity of deposits at some institutional party, denominated in some currency, identified by some *deposit reference*. A deposit reference is an opaque byte array which is usable by @@ -57,12 +57,14 @@ contract is implemented twice, once in Java and once in a language called Kotlin ``InterestRateSwap`` implements a vanilla OTC same currency bilateral fixed / floating leg swap. For further details, see :doc:`irs` +``Obligation`` implements a bilaterally or multi-laterally nettable, fungible obligation that can default. + Each contract comes with unit tests. Kotlin ------ -The prototype is written in a language called `Kotlin `_. Kotlin is a language that targets the JVM +Corda is written in a language called `Kotlin `_. Kotlin is a language that targets the JVM and can be thought of as a simpler Scala, with much better Java interop. It is developed by and has commercial support from JetBrains, the makers of the IntelliJ IDE and other popular developer tools. @@ -71,11 +73,4 @@ Java for industrial use and as such, the syntax was carefully designed to be rea the language, after only a few minutes of introduction. Due to the seamless Java interop the use of Kotlin to extend the platform is *not* required and the tutorial shows how -to write contracts in both Kotlin and Java. You can `read more about why Kotlin is a potentially strong successor to Java here `_. - -Kotlin programs use the regular Java standard library and ordinary Java frameworks. Frameworks used at this time are: - -* JUnit for unit testing -* Kryo for serialisation (this is not intended to be permanent) -* Gradle for the build -* Guava for a few utility functions +to write contracts in both Kotlin and Java. You can `read more about why Kotlin is a potentially strong successor to Java here `_. \ No newline at end of file diff --git a/docs/source/release-notes.rst b/docs/source/release-notes.rst index 28a10605f7..f8a2637966 100644 --- a/docs/source/release-notes.rst +++ b/docs/source/release-notes.rst @@ -6,27 +6,71 @@ Here are brief summaries of what's changed between each snapshot release. Unreleased ---------- -Here are changes in git master that haven't yet made it to a snapshot release: +There are currently no unreleased changes. -* Made the ``NotaryService`` extensible, we now have both validating and non-validating notaries. -* Added a protocol for changing the notary for a state. -* Every ``ContractState`` now has to specify a *participants* field, which is a list of parties that are able to - consume this state in a valid transaction. This is used for e.g. making sure all relevant parties obtain the updated - state when changing a notary. -* Introduced ``TransactionState``, which wraps ``ContractState``, and is used when defining a transaction output. - The notary field is moved from ``ContractState`` into ``TransactionState``. -* Every transaction now has a *type* field, which specifies custom build & validation rules for that transaction type. - Currently two types are supported: +Milestone 1 +----------- - - **General**. Runs the default build and validation logic. - - **NotaryChange**. Contract code is not run during validation, checks that the notary field is the only difference - between the inputs and outputs. +Highlights of this release: -* The cash contract has moved from com.r3corda.contracts to com.r3corda.contracts.cash. -* Amount class is now generic, to support non-currency types (such as assets, or currency with additional information). +* Event scheduling. States in the ledger can now request protocols to be invoked at particular times, for states + considered relevant by the wallet. +* Upgrades to the notary/consensus service support: + + * There is now a way to change the notary controlling a state. + * You can pick between validating and non-validating notaries, these let you select your privacy/robustness tradeoff. + +* A new obligation contract that supports bilateral and multilateral netting of obligations, default tracking and + more. +* Improvements to the financial type system, with core classes and contracts made more generic. +* Switch to a better digital signature algorithm: ed25519 instead of the previous JDK default of secp256r1. +* A new integration test suite. +* A new Java unit testing DSL for contracts, similar in spirit to the one already developed for Kotlin users (which + depended on Kotlin specific features). +* An experimental module, where developers who want to work with the latest Corda code can check in contracts/cordapp + code before it's been fully reviewed. Code in this module has compiler warnings suppressed but we will still make + sure it compiles across refactorings. +* Persistence improvements: transaction data is now stored to disk and automatic protocol resume is now implemented. +* Many smaller bug fixes, cleanups and improvements. + +We have new documentation on: + +* :doc:`event-scheduling` +* :doc:`transaction-data-types` +* :doc:`consensus` + +Summary of API changes (not exhaustive): + +* Notary/consensus service: + + * ``NotaryService`` is now extensible. + * Every ``ContractState`` now has to specify a *participants* field, which is a list of parties that are able to + consume this state in a valid transaction. This is used for e.g. making sure all relevant parties obtain the updated + state when changing a notary. + * Introduced ``TransactionState``, which wraps ``ContractState``, and is used when defining a transaction output. + The notary field is moved from ``ContractState`` into ``TransactionState``. + * Every transaction now has a *type* field, which specifies custom build & validation rules for that transaction type. + Currently two types are supported: General (runs the default build and validation logic) and NotaryChange ( + contract code is not run during validation, checks that the notary field is the only difference between the + inputs and outputs). + +* The cash contract has moved from ``com.r3corda.contracts`` to ``com.r3corda.contracts.cash`` +* ``Amount`` class is now generic, to support non-currency types such as physical assets. Where you previously had just + ``Amount``, you should now use ``Amount``. * Refactored the Cash contract to have a new FungibleAsset superclass, to model all countable assets that can be merged and split (currency, barrels of oil, etc.) -* Switched to the ed25519 elliptic curve from secp256r1. Note that this introduces a new external lib dependency. +* Messaging: + + * ``addMessageHandler`` now has a different signature as part of error handling changes. + * If you want to return nothing to a protocol, use ``Ack`` instead of ``Unit`` from now on. + +* In the IRS contract, dateOffset is now an integer instead of an enum. +* In contracts, you now use ``tx.getInputs`` and ``tx.getOutputs`` instead of ``getInStates`` and ``getOutStates``. This is + just a renaming. +* A new ``NonEmptySet`` type has been added for cases where you wish to express that you have a collection of unique + objects which cannot be empty. +* Please use the global ``newSecureRandom()`` function rather than instantiating your own SecureRandom's from now on, as + the custom function forces the use of non-blocking random drivers on Linux. Milestone 0 ----------- diff --git a/docs/source/running-the-demos.rst b/docs/source/running-the-demos.rst index 93499522a5..a064258f66 100644 --- a/docs/source/running-the-demos.rst +++ b/docs/source/running-the-demos.rst @@ -73,9 +73,7 @@ And in the second run: ./build/install/r3prototyping/bin/irsdemo --role=NodeB -The node in the first terminal will complain that it didn't know about nodeB, so restart it. It'll then find the -location and identity keys of nodeA and be happy. NodeB also doubles up as the interest rates oracle and you should -see some rates data get loaded. +NodeB also doubles up as the interest rates oracle and you should see some rates data get loaded. Now in the third terminal run: From 9e174d3e3a974be00d243450788edd63985acbad Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Thu, 30 Jun 2016 11:30:05 +0100 Subject: [PATCH 065/114] irsdemo: Fix api address in Date role --- src/main/kotlin/com/r3corda/demos/IRSDemo.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt index 57a9bc63cf..c2a60d4609 100644 --- a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt @@ -189,7 +189,9 @@ sealed class CliParams { private fun parseDateChange(options: OptionSet): DateChange { return DateChange( - apiAddress = HostAndPort.fromString(options.valueOf(CliParamsSpec.apiAddressArg)), + apiAddress = HostAndPort.fromString(options.valueOf( + CliParamsSpec.apiAddressArg.defaultsTo("localhost:${defaultApiPort(IRSDemoNode.NodeA)}") + )), dateString = options.valuesOf(CliParamsSpec.nonOptions).let { if (it.size > 0) { it[0] From b30e431766ca9ffc90e4581b8da069a457254285 Mon Sep 17 00:00:00 2001 From: Andrius Dagys Date: Thu, 30 Jun 2016 11:46:26 +0100 Subject: [PATCH 066/114] Update release notes regarding use of TransactionBuilder --- docs/source/release-notes.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/release-notes.rst b/docs/source/release-notes.rst index f8a2637966..b78680b575 100644 --- a/docs/source/release-notes.rst +++ b/docs/source/release-notes.rst @@ -53,6 +53,7 @@ Summary of API changes (not exhaustive): Currently two types are supported: General (runs the default build and validation logic) and NotaryChange ( contract code is not run during validation, checks that the notary field is the only difference between the inputs and outputs). + ``TransactionBuilder()`` is now abstract, you should use ``TransactionType.General.Builder()`` for building transactions. * The cash contract has moved from ``com.r3corda.contracts`` to ``com.r3corda.contracts.cash`` * ``Amount`` class is now generic, to support non-currency types such as physical assets. Where you previously had just From 63cc3a04cec5b397e9a9fa98495b1d43b86512b2 Mon Sep 17 00:00:00 2001 From: Mike Hearn Date: Thu, 30 Jun 2016 12:59:19 +0200 Subject: [PATCH 067/114] Review feedback --- docs/source/inthebox.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/inthebox.rst b/docs/source/inthebox.rst index 8747037280..25ed8e2afa 100644 --- a/docs/source/inthebox.rst +++ b/docs/source/inthebox.rst @@ -40,7 +40,7 @@ four contracts in the repository: 1. Cash 2. Commercial paper 3. Nettable obligations -4. Commercial paper +4. Interest rate swaps ``Cash`` implements the idea of a claim on some quantity of deposits at some institutional party, denominated in some currency, identified by some *deposit reference*. A deposit reference is an opaque byte array which is usable by From a02263937c26d4f8c9c7d234126309179e15ef80 Mon Sep 17 00:00:00 2001 From: Shams Asari Date: Thu, 30 Jun 2016 11:18:28 +0100 Subject: [PATCH 068/114] send and sendAndReceive use Party for the destination --- .../protocols/TwoPartyTradeProtocol.kt | 5 ++- .../r3corda/core/node/services/Services.kt | 1 + .../r3corda/core/protocols/ProtocolLogic.kt | 15 ++++---- .../core/protocols/ProtocolStateMachine.kt | 8 ++--- .../protocols/AbstractRequestMessage.kt | 9 ----- .../protocols/FetchAttachmentsProtocol.kt | 4 +-- .../r3corda/protocols/FetchDataProtocol.kt | 8 ++--- .../protocols/FetchTransactionsProtocol.kt | 4 +-- .../com/r3corda/protocols/NotaryProtocol.kt | 32 ++++++++--------- .../com/r3corda/protocols/RatesFixProtocol.kt | 23 ++++++------- .../protocols/ResolveTransactionsProtocol.kt | 8 ++--- .../protocols/ServiceRequestMessage.kt | 20 +++++++++++ .../r3corda/protocols/TwoPartyDealProtocol.kt | 28 +++++++-------- .../protocols/ValidatingNotaryProtocol.kt | 6 ++-- .../AbstractStateReplacementProtocol.kt | 17 +++++----- .../kotlin/protocols/NotaryChangeProtocol.kt | 12 +------ .../com/r3corda/node/internal/AbstractNode.kt | 14 ++++---- .../node/internal/testing/IRSSimulation.kt | 4 +-- .../node/internal/testing/TradeSimulation.kt | 17 +++++++--- .../node/services/NotaryChangeService.kt | 8 ++--- .../node/services/api/AbstractNodeService.kt | 19 ++++++----- .../services/clientapi/NodeInterestRates.kt | 4 +-- .../services/network/NetworkMapService.kt | 19 +++++++---- .../persistence/DataVendingService.kt | 3 +- .../statemachine/ProtocolStateMachineImpl.kt | 16 +++++---- .../statemachine/StateMachineManager.kt | 11 +++--- .../services/transactions/NotaryService.kt | 10 +++--- .../transactions/SimpleNotaryService.kt | 4 ++- .../transactions/ValidatingNotaryService.kt | 10 +++--- .../r3corda/node/messaging/AttachmentTests.kt | 13 ++++--- .../messaging/TwoPartyTradeProtocolTests.kt | 25 ++++++-------- .../services/InMemoryNetworkMapServiceTest.kt | 16 +++++---- .../com/r3corda/node/services/MockServices.kt | 4 +-- .../node/services/NodeInterestRatesTest.kt | 7 ++-- .../kotlin/com/r3corda/demos/RateFixDemo.kt | 4 +-- .../kotlin/com/r3corda/demos/TraderDemo.kt | 34 ++++++++----------- .../demos/protocols/AutoOfferProtocol.kt | 9 +++-- .../demos/protocols/ExitServerProtocol.kt | 4 +-- .../protocols/UpdateBusinessDayProtocol.kt | 2 +- 39 files changed, 237 insertions(+), 220 deletions(-) delete mode 100644 core/src/main/kotlin/com/r3corda/protocols/AbstractRequestMessage.kt create mode 100644 core/src/main/kotlin/com/r3corda/protocols/ServiceRequestMessage.kt diff --git a/contracts/src/main/kotlin/com/r3corda/protocols/TwoPartyTradeProtocol.kt b/contracts/src/main/kotlin/com/r3corda/protocols/TwoPartyTradeProtocol.kt index 514f230675..9959de2fb8 100644 --- a/contracts/src/main/kotlin/com/r3corda/protocols/TwoPartyTradeProtocol.kt +++ b/contracts/src/main/kotlin/com/r3corda/protocols/TwoPartyTradeProtocol.kt @@ -7,7 +7,6 @@ import com.r3corda.core.contracts.* import com.r3corda.core.crypto.DigitalSignature import com.r3corda.core.crypto.Party import com.r3corda.core.crypto.signWithECDSA -import com.r3corda.core.messaging.SingleMessageRecipient import com.r3corda.core.node.NodeInfo import com.r3corda.core.protocols.ProtocolLogic import com.r3corda.core.random63BitValue @@ -61,7 +60,7 @@ object TwoPartyTradeProtocol { class SignaturesFromSeller(val sellerSig: DigitalSignature.WithKey, val notarySig: DigitalSignature.LegallyIdentifiable) - open class Seller(val otherSide: SingleMessageRecipient, + open class Seller(val otherSide: Party, val notaryNode: NodeInfo, val assetToSell: StateAndRef, val price: Amount>, @@ -172,7 +171,7 @@ object TwoPartyTradeProtocol { } } - open class Buyer(val otherSide: SingleMessageRecipient, + open class Buyer(val otherSide: Party, val notary: Party, val acceptablePrice: Amount>, val typeToBuy: Class, diff --git a/core/src/main/kotlin/com/r3corda/core/node/services/Services.kt b/core/src/main/kotlin/com/r3corda/core/node/services/Services.kt index 7596967949..deff8a419a 100644 --- a/core/src/main/kotlin/com/r3corda/core/node/services/Services.kt +++ b/core/src/main/kotlin/com/r3corda/core/node/services/Services.kt @@ -169,6 +169,7 @@ interface StorageService { * Returns the legal identity that this node is configured with. Assumed to be initialised when the node is * first installed. */ + //TODO this should be in the IdentityService, or somewhere not here val myLegalIdentity: Party val myLegalIdentityKey: KeyPair } diff --git a/core/src/main/kotlin/com/r3corda/core/protocols/ProtocolLogic.kt b/core/src/main/kotlin/com/r3corda/core/protocols/ProtocolLogic.kt index 0ab15a3be2..25f500d7fa 100644 --- a/core/src/main/kotlin/com/r3corda/core/protocols/ProtocolLogic.kt +++ b/core/src/main/kotlin/com/r3corda/core/protocols/ProtocolLogic.kt @@ -1,7 +1,7 @@ package com.r3corda.core.protocols import co.paralleluniverse.fibers.Suspendable -import com.r3corda.core.messaging.MessageRecipients +import com.r3corda.core.crypto.Party import com.r3corda.core.node.ServiceHub import com.r3corda.core.utilities.ProgressTracker import com.r3corda.core.utilities.UntrustworthyData @@ -39,9 +39,12 @@ abstract class ProtocolLogic { val serviceHub: ServiceHub get() = psm.serviceHub // Kotlin helpers that allow the use of generic types. - inline fun sendAndReceive(topic: String, destination: MessageRecipients, sessionIDForSend: Long, - sessionIDForReceive: Long, obj: Any): UntrustworthyData { - return psm.sendAndReceive(topic, destination, sessionIDForSend, sessionIDForReceive, obj, T::class.java) + inline fun sendAndReceive(topic: String, + destination: Party, + sessionIDForSend: Long, + sessionIDForReceive: Long, + payload: Any): UntrustworthyData { + return psm.sendAndReceive(topic, destination, sessionIDForSend, sessionIDForReceive, payload, T::class.java) } inline fun receive(topic: String, sessionIDForReceive: Long): UntrustworthyData { @@ -52,8 +55,8 @@ abstract class ProtocolLogic { return psm.receive(topic, sessionIDForReceive, clazz) } - @Suspendable fun send(topic: String, destination: MessageRecipients, sessionID: Long, obj: Any) { - psm.send(topic, destination, sessionID, obj) + @Suspendable fun send(topic: String, destination: Party, sessionID: Long, payload: Any) { + psm.send(topic, destination, sessionID, payload) } /** diff --git a/core/src/main/kotlin/com/r3corda/core/protocols/ProtocolStateMachine.kt b/core/src/main/kotlin/com/r3corda/core/protocols/ProtocolStateMachine.kt index fc4f8039e8..217df1752d 100644 --- a/core/src/main/kotlin/com/r3corda/core/protocols/ProtocolStateMachine.kt +++ b/core/src/main/kotlin/com/r3corda/core/protocols/ProtocolStateMachine.kt @@ -1,7 +1,7 @@ package com.r3corda.core.protocols import co.paralleluniverse.fibers.Suspendable -import com.r3corda.core.messaging.MessageRecipients +import com.r3corda.core.crypto.Party import com.r3corda.core.node.ServiceHub import com.r3corda.core.utilities.UntrustworthyData import org.slf4j.Logger @@ -12,14 +12,14 @@ import org.slf4j.Logger */ interface ProtocolStateMachine { @Suspendable - fun sendAndReceive(topic: String, destination: MessageRecipients, sessionIDForSend: Long, sessionIDForReceive: Long, - obj: Any, recvType: Class): UntrustworthyData + fun sendAndReceive(topic: String, destination: Party, sessionIDForSend: Long, sessionIDForReceive: Long, + payload: Any, recvType: Class): UntrustworthyData @Suspendable fun receive(topic: String, sessionIDForReceive: Long, recvType: Class): UntrustworthyData @Suspendable - fun send(topic: String, destination: MessageRecipients, sessionID: Long, obj: Any) + fun send(topic: String, destination: Party, sessionID: Long, payload: Any) val serviceHub: ServiceHub val logger: Logger diff --git a/core/src/main/kotlin/com/r3corda/protocols/AbstractRequestMessage.kt b/core/src/main/kotlin/com/r3corda/protocols/AbstractRequestMessage.kt deleted file mode 100644 index 414df561f5..0000000000 --- a/core/src/main/kotlin/com/r3corda/protocols/AbstractRequestMessage.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.r3corda.protocols - -import com.r3corda.core.messaging.MessageRecipients - -/** - * Abstract superclass for request messages sent to services, which includes common - * fields such as replyTo and replyToTopic. - */ -abstract class AbstractRequestMessage(val replyTo: MessageRecipients, val sessionID: Long?) \ No newline at end of file diff --git a/core/src/main/kotlin/com/r3corda/protocols/FetchAttachmentsProtocol.kt b/core/src/main/kotlin/com/r3corda/protocols/FetchAttachmentsProtocol.kt index dd19927281..993c078206 100644 --- a/core/src/main/kotlin/com/r3corda/protocols/FetchAttachmentsProtocol.kt +++ b/core/src/main/kotlin/com/r3corda/protocols/FetchAttachmentsProtocol.kt @@ -1,9 +1,9 @@ package com.r3corda.protocols import com.r3corda.core.contracts.Attachment +import com.r3corda.core.crypto.Party import com.r3corda.core.crypto.SecureHash import com.r3corda.core.crypto.sha256 -import com.r3corda.core.messaging.SingleMessageRecipient import java.io.ByteArrayInputStream import java.io.InputStream @@ -12,7 +12,7 @@ import java.io.InputStream * attachments are saved to local storage automatically. */ class FetchAttachmentsProtocol(requests: Set, - otherSide: SingleMessageRecipient) : FetchDataProtocol(requests, otherSide) { + otherSide: Party) : FetchDataProtocol(requests, otherSide) { companion object { const val TOPIC = "platform.fetch.attachment" } diff --git a/core/src/main/kotlin/com/r3corda/protocols/FetchDataProtocol.kt b/core/src/main/kotlin/com/r3corda/protocols/FetchDataProtocol.kt index 2530269bd9..ee4dc1d31c 100644 --- a/core/src/main/kotlin/com/r3corda/protocols/FetchDataProtocol.kt +++ b/core/src/main/kotlin/com/r3corda/protocols/FetchDataProtocol.kt @@ -2,8 +2,8 @@ package com.r3corda.protocols import co.paralleluniverse.fibers.Suspendable import com.r3corda.core.contracts.NamedByHash +import com.r3corda.core.crypto.Party import com.r3corda.core.crypto.SecureHash -import com.r3corda.core.messaging.SingleMessageRecipient import com.r3corda.core.protocols.ProtocolLogic import com.r3corda.core.random63BitValue import com.r3corda.core.utilities.UntrustworthyData @@ -27,13 +27,13 @@ import java.util.* */ abstract class FetchDataProtocol( protected val requests: Set, - protected val otherSide: SingleMessageRecipient) : ProtocolLogic>() { + protected val otherSide: Party) : ProtocolLogic>() { open class BadAnswer : Exception() class HashNotFound(val requested: SecureHash) : BadAnswer() class DownloadedVsRequestedDataMismatch(val requested: SecureHash, val got: SecureHash) : BadAnswer() - class Request(val hashes: List, replyTo: SingleMessageRecipient, sessionID: Long) : AbstractRequestMessage(replyTo, sessionID) + class Request(val hashes: List, replyTo: Party, override val sessionID: Long) : AbstractRequestMessage(replyTo) data class Result(val fromDisk: List, val downloaded: List) protected abstract val queryTopic: String @@ -49,7 +49,7 @@ abstract class FetchDataProtocol( logger.trace("Requesting ${toFetch.size} dependency(s) for verification") val sid = random63BitValue() - val fetchReq = Request(toFetch, serviceHub.networkService.myAddress, sid) + val fetchReq = Request(toFetch, serviceHub.storageService.myLegalIdentity, sid) // TODO: Support "large message" response streaming so response sizes are not limited by RAM. val maybeItems = sendAndReceive>(queryTopic, otherSide, 0, sid, fetchReq) // Check for a buggy/malicious peer answering with something that we didn't ask for. diff --git a/core/src/main/kotlin/com/r3corda/protocols/FetchTransactionsProtocol.kt b/core/src/main/kotlin/com/r3corda/protocols/FetchTransactionsProtocol.kt index 032fa9b583..667937c1be 100644 --- a/core/src/main/kotlin/com/r3corda/protocols/FetchTransactionsProtocol.kt +++ b/core/src/main/kotlin/com/r3corda/protocols/FetchTransactionsProtocol.kt @@ -1,8 +1,8 @@ package com.r3corda.protocols import com.r3corda.core.contracts.SignedTransaction +import com.r3corda.core.crypto.Party import com.r3corda.core.crypto.SecureHash -import com.r3corda.core.messaging.SingleMessageRecipient /** * Given a set of tx hashes (IDs), either loads them from local disk or asks the remote peer to provide them. @@ -12,7 +12,7 @@ import com.r3corda.core.messaging.SingleMessageRecipient * results in a [FetchDataProtocol.HashNotFound] exception. Note that returned transactions are not inserted into * the database, because it's up to the caller to actually verify the transactions are valid. */ -class FetchTransactionsProtocol(requests: Set, otherSide: SingleMessageRecipient) : +class FetchTransactionsProtocol(requests: Set, otherSide: Party) : FetchDataProtocol(requests, otherSide) { companion object { const val TOPIC = "platform.fetch.tx" diff --git a/core/src/main/kotlin/com/r3corda/protocols/NotaryProtocol.kt b/core/src/main/kotlin/com/r3corda/protocols/NotaryProtocol.kt index f7e50cf3d4..1da1d4d674 100644 --- a/core/src/main/kotlin/com/r3corda/protocols/NotaryProtocol.kt +++ b/core/src/main/kotlin/com/r3corda/protocols/NotaryProtocol.kt @@ -9,8 +9,6 @@ import com.r3corda.core.crypto.Party import com.r3corda.core.crypto.SignedData import com.r3corda.core.crypto.signWithECDSA import com.r3corda.core.messaging.Ack -import com.r3corda.core.messaging.SingleMessageRecipient -import com.r3corda.core.node.NodeInfo import com.r3corda.core.node.services.TimestampChecker import com.r3corda.core.node.services.UniquenessException import com.r3corda.core.node.services.UniquenessProvider @@ -45,21 +43,21 @@ object NotaryProtocol { fun tracker() = ProgressTracker(REQUESTING, VALIDATING) } - lateinit var notaryNode: NodeInfo + lateinit var notaryParty: Party @Suspendable override fun call(): DigitalSignature.LegallyIdentifiable { progressTracker.currentStep = REQUESTING - notaryNode = findNotaryNode() + notaryParty = findNotaryParty() val sendSessionID = random63BitValue() val receiveSessionID = random63BitValue() - val handshake = Handshake(serviceHub.networkService.myAddress, sendSessionID, receiveSessionID) - sendAndReceive(TOPIC_INITIATE, notaryNode.address, 0, receiveSessionID, handshake) + val handshake = Handshake(serviceHub.storageService.myLegalIdentity, sendSessionID, receiveSessionID) + sendAndReceive(TOPIC_INITIATE, notaryParty, 0, receiveSessionID, handshake) val request = SignRequest(stx, serviceHub.storageService.myLegalIdentity) - val response = sendAndReceive(TOPIC, notaryNode.address, sendSessionID, receiveSessionID, request) + val response = sendAndReceive(TOPIC, notaryParty, sendSessionID, receiveSessionID, request) val notaryResult = validateResponse(response) return notaryResult.sig ?: throw NotaryException(notaryResult.error!!) @@ -72,17 +70,17 @@ object NotaryProtocol { if (it.sig != null) validateSignature(it.sig, stx.txBits) else if (it.error is NotaryError.Conflict) it.error.conflict.verified() else if (it.error == null || it.error !is NotaryError) - throw IllegalStateException("Received invalid result from Notary service '${notaryNode.identity}'") + throw IllegalStateException("Received invalid result from Notary service '$notaryParty'") return it } } private fun validateSignature(sig: DigitalSignature.LegallyIdentifiable, data: SerializedBytes) { - check(sig.signer == notaryNode.identity) { "Notary result not signed by the correct service" } + check(sig.signer == notaryParty) { "Notary result not signed by the correct service" } sig.verifyWithECDSA(data) } - private fun findNotaryNode(): NodeInfo { + private fun findNotaryParty(): Party { var maybeNotaryKey: PublicKey? = null val wtx = stx.tx @@ -97,8 +95,8 @@ object NotaryProtocol { } val notaryKey = maybeNotaryKey ?: throw IllegalStateException("Transaction does not specify a Notary") - val notaryNode = serviceHub.networkMapCache.getNodeByPublicKey(notaryKey) - return notaryNode ?: throw IllegalStateException("No Notary node can be found with the specified public key") + val notaryParty = serviceHub.networkMapCache.getNodeByPublicKey(notaryKey)?.identity + return notaryParty ?: throw IllegalStateException("No Notary node can be found with the specified public key") } } @@ -110,7 +108,7 @@ object NotaryProtocol { * * TODO: the notary service should only be able to see timestamp commands and inputs */ - open class Service(val otherSide: SingleMessageRecipient, + open class Service(val otherSide: Party, val sendSessionID: Long, val receiveSessionID: Long, val timestampChecker: TimestampChecker, @@ -181,9 +179,9 @@ object NotaryProtocol { } class Handshake( - replyTo: SingleMessageRecipient, + replyTo: Party, val sendSessionID: Long, - sessionID: Long) : AbstractRequestMessage(replyTo, sessionID) + override val sessionID: Long) : AbstractRequestMessage(replyTo) /** TODO: The caller must authenticate instead of just specifying its identity */ class SignRequest(val tx: SignedTransaction, @@ -197,7 +195,7 @@ object NotaryProtocol { } interface Factory { - fun create(otherSide: SingleMessageRecipient, + fun create(otherSide: Party, sendSessionID: Long, receiveSessionID: Long, timestampChecker: TimestampChecker, @@ -205,7 +203,7 @@ object NotaryProtocol { } object DefaultFactory : Factory { - override fun create(otherSide: SingleMessageRecipient, + override fun create(otherSide: Party, sendSessionID: Long, receiveSessionID: Long, timestampChecker: TimestampChecker, diff --git a/core/src/main/kotlin/com/r3corda/protocols/RatesFixProtocol.kt b/core/src/main/kotlin/com/r3corda/protocols/RatesFixProtocol.kt index 1b910c8698..fd1378f548 100644 --- a/core/src/main/kotlin/com/r3corda/protocols/RatesFixProtocol.kt +++ b/core/src/main/kotlin/com/r3corda/protocols/RatesFixProtocol.kt @@ -6,8 +6,7 @@ import com.r3corda.core.contracts.FixOf import com.r3corda.core.contracts.TransactionBuilder import com.r3corda.core.contracts.WireTransaction import com.r3corda.core.crypto.DigitalSignature -import com.r3corda.core.messaging.SingleMessageRecipient -import com.r3corda.core.node.NodeInfo +import com.r3corda.core.crypto.Party import com.r3corda.core.protocols.ProtocolLogic import com.r3corda.core.random63BitValue import com.r3corda.core.utilities.ProgressTracker @@ -28,7 +27,7 @@ import java.util.* * @throws FixOutOfRange if the returned fix was further away from the expected rate by the given amount. */ open class RatesFixProtocol(protected val tx: TransactionBuilder, - private val oracle: NodeInfo, + private val oracle: Party, private val fixOf: FixOf, private val expectedRate: BigDecimal, private val rateTolerance: BigDecimal, @@ -48,8 +47,8 @@ open class RatesFixProtocol(protected val tx: TransactionBuilder, class FixOutOfRange(val byAmount: BigDecimal) : Exception() - class QueryRequest(val queries: List, replyTo: SingleMessageRecipient, sessionID: Long, val deadline: Instant) : AbstractRequestMessage(replyTo, sessionID) - class SignRequest(val tx: WireTransaction, replyTo: SingleMessageRecipient, sessionID: Long) : AbstractRequestMessage(replyTo, sessionID) + class QueryRequest(val queries: List, replyTo: Party, override val sessionID: Long, val deadline: Instant) : AbstractRequestMessage(replyTo) + class SignRequest(val tx: WireTransaction, replyTo: Party, override val sessionID: Long) : AbstractRequestMessage(replyTo) @Suspendable override fun call() { @@ -57,7 +56,7 @@ open class RatesFixProtocol(protected val tx: TransactionBuilder, val fix = query() progressTracker.currentStep = WORKING checkFixIsNearExpected(fix) - tx.addCommand(fix, oracle.identity.owningKey) + tx.addCommand(fix, oracle.owningKey) beforeSigning(fix) progressTracker.currentStep = SIGNING tx.addSignatureUnchecked(sign()) @@ -83,11 +82,11 @@ open class RatesFixProtocol(protected val tx: TransactionBuilder, fun sign(): DigitalSignature.LegallyIdentifiable { val sessionID = random63BitValue() val wtx = tx.toWireTransaction() - val req = SignRequest(wtx, serviceHub.networkService.myAddress, sessionID) - val resp = sendAndReceive(TOPIC_SIGN, oracle.address, 0, sessionID, req) + val req = SignRequest(wtx, serviceHub.storageService.myLegalIdentity, sessionID) + val resp = sendAndReceive(TOPIC_SIGN, oracle, 0, sessionID, req) return resp.validate { sig -> - check(sig.signer == oracle.identity) + check(sig.signer == oracle) tx.checkSignature(sig) sig } @@ -96,10 +95,10 @@ open class RatesFixProtocol(protected val tx: TransactionBuilder, @Suspendable fun query(): Fix { val sessionID = random63BitValue() - val deadline = suggestInterestRateAnnouncementTimeWindow(fixOf.name, oracle.identity.name, fixOf.forDay).end - val req = QueryRequest(listOf(fixOf), serviceHub.networkService.myAddress, sessionID, deadline) + val deadline = suggestInterestRateAnnouncementTimeWindow(fixOf.name, oracle.name, fixOf.forDay).end + val req = QueryRequest(listOf(fixOf), serviceHub.storageService.myLegalIdentity, sessionID, deadline) // TODO: add deadline to receive - val resp = sendAndReceive>(TOPIC_QUERY, oracle.address, 0, sessionID, req) + val resp = sendAndReceive>(TOPIC_QUERY, oracle, 0, sessionID, req) return resp.validate { val fix = it.first() diff --git a/core/src/main/kotlin/com/r3corda/protocols/ResolveTransactionsProtocol.kt b/core/src/main/kotlin/com/r3corda/protocols/ResolveTransactionsProtocol.kt index 7639a0befb..f6bc21fd56 100644 --- a/core/src/main/kotlin/com/r3corda/protocols/ResolveTransactionsProtocol.kt +++ b/core/src/main/kotlin/com/r3corda/protocols/ResolveTransactionsProtocol.kt @@ -2,8 +2,8 @@ package com.r3corda.protocols import co.paralleluniverse.fibers.Suspendable import com.r3corda.core.contracts.* +import com.r3corda.core.crypto.Party import com.r3corda.core.crypto.SecureHash -import com.r3corda.core.messaging.SingleMessageRecipient import com.r3corda.core.protocols.ProtocolLogic import java.util.* @@ -21,7 +21,7 @@ import java.util.* * protocol is helpful when resolving and verifying a finished but partially signed transaction. */ class ResolveTransactionsProtocol(private val txHashes: Set, - private val otherSide: SingleMessageRecipient) : ProtocolLogic() { + private val otherSide: Party) : ProtocolLogic() { companion object { private fun dependencyIDs(wtx: WireTransaction) = wtx.inputs.map { it.txhash }.toSet() @@ -33,11 +33,11 @@ class ResolveTransactionsProtocol(private val txHashes: Set, private var stx: SignedTransaction? = null private var wtx: WireTransaction? = null - constructor(stx: SignedTransaction, otherSide: SingleMessageRecipient) : this(stx.tx, otherSide) { + constructor(stx: SignedTransaction, otherSide: Party) : this(stx.tx, otherSide) { this.stx = stx } - constructor(wtx: WireTransaction, otherSide: SingleMessageRecipient) : this(dependencyIDs(wtx), otherSide) { + constructor(wtx: WireTransaction, otherSide: Party) : this(dependencyIDs(wtx), otherSide) { this.wtx = wtx } diff --git a/core/src/main/kotlin/com/r3corda/protocols/ServiceRequestMessage.kt b/core/src/main/kotlin/com/r3corda/protocols/ServiceRequestMessage.kt new file mode 100644 index 0000000000..6f6fbb21ee --- /dev/null +++ b/core/src/main/kotlin/com/r3corda/protocols/ServiceRequestMessage.kt @@ -0,0 +1,20 @@ +package com.r3corda.protocols + +import com.r3corda.core.crypto.Party +import com.r3corda.core.messaging.MessageRecipients +import com.r3corda.core.node.services.NetworkMapCache + +/** + * Abstract superclass for request messages sent to services, which includes common + * fields such as replyTo and replyToTopic. + */ +interface ServiceRequestMessage { + val sessionID: Long + fun getReplyTo(networkMapCache: NetworkMapCache): MessageRecipients +} + +abstract class AbstractRequestMessage(val replyToParty: Party): ServiceRequestMessage { + override fun getReplyTo(networkMapCache: NetworkMapCache): MessageRecipients { + return networkMapCache.partyNodes.single { it.identity == replyToParty }.address + } +} \ No newline at end of file diff --git a/core/src/main/kotlin/com/r3corda/protocols/TwoPartyDealProtocol.kt b/core/src/main/kotlin/com/r3corda/protocols/TwoPartyDealProtocol.kt index d78fe77fef..f716dfa314 100644 --- a/core/src/main/kotlin/com/r3corda/protocols/TwoPartyDealProtocol.kt +++ b/core/src/main/kotlin/com/r3corda/protocols/TwoPartyDealProtocol.kt @@ -6,7 +6,6 @@ import com.r3corda.core.contracts.* import com.r3corda.core.crypto.DigitalSignature import com.r3corda.core.crypto.Party import com.r3corda.core.crypto.signWithECDSA -import com.r3corda.core.messaging.SingleMessageRecipient import com.r3corda.core.node.NodeInfo import com.r3corda.core.protocols.ProtocolLogic import com.r3corda.core.random63BitValue @@ -72,7 +71,7 @@ object TwoPartyDealProtocol { abstract val payload: U abstract val notaryNode: NodeInfo - abstract val otherSide: SingleMessageRecipient + abstract val otherSide: Party abstract val otherSessionID: Long abstract val myKeyPair: KeyPair @@ -153,7 +152,7 @@ object TwoPartyDealProtocol { // Copy the transaction to every regulator in the network. This is obviously completely bogus, it's // just for demo purposes. for (regulator in regulators) { - send("regulator.all.seeing.eye", regulator.address, 0, fullySigned) + send("regulator.all.seeing.eye", regulator.identity, 0, fullySigned) } } @@ -203,7 +202,7 @@ object TwoPartyDealProtocol { fun tracker() = ProgressTracker(RECEIVING, VERIFYING, SIGNING, SWAPPING_SIGNATURES, RECORDING) } - abstract val otherSide: SingleMessageRecipient + abstract val otherSide: Party abstract val sessionID: Long @Suspendable @@ -276,7 +275,7 @@ object TwoPartyDealProtocol { /** * One side of the protocol for inserting a pre-agreed deal. */ - open class Instigator(override val otherSide: SingleMessageRecipient, + open class Instigator(override val otherSide: Party, val notary: Party, override val payload: T, override val myKeyPair: KeyPair, @@ -290,7 +289,7 @@ object TwoPartyDealProtocol { /** * One side of the protocol for inserting a pre-agreed deal. */ - open class Acceptor(override val otherSide: SingleMessageRecipient, + open class Acceptor(override val otherSide: Party, val notary: Party, val dealToBuy: T, override val sessionID: Long, @@ -342,7 +341,7 @@ object TwoPartyDealProtocol { override val sessionID: Long get() = initiation.sessionID - override val otherSide: SingleMessageRecipient get() = initiation.sender + override val otherSide: Party get() = initiation.sender private lateinit var txState: TransactionState<*> private lateinit var deal: FixableDealState @@ -360,8 +359,6 @@ object TwoPartyDealProtocol { val myName = serviceHub.storageService.myLegalIdentity.name val otherParty = deal.parties.filter { it.name != myName }.single() check(otherParty == initiation.party) - val otherPartyAddress = serviceHub.networkMapCache.getNodeByLegalName(otherParty.name)!!.address - check(otherPartyAddress == otherSide) // Also check we are one of the parties deal.parties.filter { it.name == myName }.single() @@ -380,7 +377,7 @@ object TwoPartyDealProtocol { val newDeal = deal val ptx = TransactionType.General.Builder() - val addFixing = object : RatesFixProtocol(ptx, serviceHub.networkMapCache.ratesOracleNodes[0], fixOf, BigDecimal.ZERO, BigDecimal.ONE, initiation.timeout) { + val addFixing = object : RatesFixProtocol(ptx, serviceHub.networkMapCache.ratesOracleNodes[0].identity, fixOf, BigDecimal.ZERO, BigDecimal.ONE, initiation.timeout) { @Suspendable override fun beforeSigning(fix: Fix) { newDeal.generateFix(ptx, StateAndRef(txState, handshake.payload), fix) @@ -417,11 +414,10 @@ object TwoPartyDealProtocol { return serviceHub.keyManagementService.toKeyPair(publicKey) } - override val otherSide: SingleMessageRecipient get() { + override val otherSide: Party get() { // TODO: what happens if there's no node? Move to messaging taking Party and then handled in messaging layer val myName = serviceHub.storageService.myLegalIdentity.name - val otherParty = dealToFix.state.data.parties.filter { it.name != myName }.single() - return serviceHub.networkMapCache.getNodeByLegalName(otherParty.name)!!.address + return dealToFix.state.data.parties.filter { it.name != myName }.single() } override val notaryNode: NodeInfo get() = @@ -432,7 +428,7 @@ object TwoPartyDealProtocol { val FIX_INITIATE_TOPIC = "platform.fix.initiate" /** Used to set up the session between [Floater] and [Fixer] */ - data class FixingSessionInitiation(val sessionID: Long, val party: Party, val sender: SingleMessageRecipient, val timeout: Duration) + data class FixingSessionInitiation(val sessionID: Long, val party: Party, val sender: Party, val timeout: Duration) /** * This protocol looks at the deal and decides whether to be the Fixer or Floater role in agreeing a fixing. @@ -459,10 +455,10 @@ object TwoPartyDealProtocol { if (sortedParties[0].name == serviceHub.storageService.myLegalIdentity.name) { // Generate sessionID val sessionID = random63BitValue() - val initation = FixingSessionInitiation(sessionID, sortedParties[0], serviceHub.networkService.myAddress, timeout) + val initation = FixingSessionInitiation(sessionID, sortedParties[0], serviceHub.storageService.myLegalIdentity, timeout) // Send initiation to other side to launch one side of the fixing protocol (the Fixer). - send(FIX_INITIATE_TOPIC, serviceHub.networkMapCache.getNodeByLegalName(sortedParties[1].name)!!.address, 0, initation) + send(FIX_INITIATE_TOPIC, sortedParties[1], 0, initation) // Then start the other side of the fixing protocol. val protocol = Floater(ref, sessionID) diff --git a/core/src/main/kotlin/com/r3corda/protocols/ValidatingNotaryProtocol.kt b/core/src/main/kotlin/com/r3corda/protocols/ValidatingNotaryProtocol.kt index ea36c2fe66..0b45e7f15a 100644 --- a/core/src/main/kotlin/com/r3corda/protocols/ValidatingNotaryProtocol.kt +++ b/core/src/main/kotlin/com/r3corda/protocols/ValidatingNotaryProtocol.kt @@ -6,7 +6,6 @@ import com.r3corda.core.contracts.TransactionVerificationException import com.r3corda.core.contracts.WireTransaction import com.r3corda.core.contracts.toLedgerTransaction import com.r3corda.core.crypto.Party -import com.r3corda.core.messaging.SingleMessageRecipient import com.r3corda.core.node.services.TimestampChecker import com.r3corda.core.node.services.UniquenessProvider import java.security.SignatureException @@ -17,7 +16,7 @@ import java.security.SignatureException * has its input states "blocked" by a transaction from another party, and needs to establish whether that transaction was * indeed valid */ -class ValidatingNotaryProtocol(otherSide: SingleMessageRecipient, +class ValidatingNotaryProtocol(otherSide: Party, sessionIdForSend: Long, sessionIdForReceive: Long, timestampChecker: TimestampChecker, @@ -52,7 +51,6 @@ class ValidatingNotaryProtocol(otherSide: SingleMessageRecipient, @Suspendable private fun validateDependencies(reqIdentity: Party, wtx: WireTransaction) { - val otherSide = serviceHub.networkMapCache.getNodeByPublicKey(reqIdentity.owningKey)!!.address - subProtocol(ResolveTransactionsProtocol(wtx, otherSide)) + subProtocol(ResolveTransactionsProtocol(wtx, reqIdentity)) } } \ No newline at end of file diff --git a/core/src/main/kotlin/protocols/AbstractStateReplacementProtocol.kt b/core/src/main/kotlin/protocols/AbstractStateReplacementProtocol.kt index d1dbd6b7be..ba302424d9 100644 --- a/core/src/main/kotlin/protocols/AbstractStateReplacementProtocol.kt +++ b/core/src/main/kotlin/protocols/AbstractStateReplacementProtocol.kt @@ -6,7 +6,6 @@ import com.r3corda.core.crypto.DigitalSignature import com.r3corda.core.crypto.Party import com.r3corda.core.crypto.signWithECDSA import com.r3corda.core.messaging.Ack -import com.r3corda.core.messaging.SingleMessageRecipient import com.r3corda.core.node.NodeInfo import com.r3corda.core.protocols.ProtocolLogic import com.r3corda.core.random63BitValue @@ -34,8 +33,8 @@ abstract class AbstractStateReplacementProtocol { } class Handshake(val sessionIdForSend: Long, - replyTo: SingleMessageRecipient, - replySessionId: Long) : AbstractRequestMessage(replyTo, replySessionId) + replyTo: Party, + override val sessionID: Long) : AbstractRequestMessage(replyTo) abstract class Instigator(val originalState: StateAndRef, val modification: T, @@ -89,7 +88,7 @@ abstract class AbstractStateReplacementProtocol { } val allSignatures = participantSignatures + getNotarySignature(stx) - sessions.forEach { send(TOPIC_CHANGE, it.key.address, it.value, allSignatures) } + sessions.forEach { send(TOPIC_CHANGE, it.key.identity, it.value, allSignatures) } return allSignatures } @@ -99,10 +98,10 @@ abstract class AbstractStateReplacementProtocol { val sessionIdForReceive = random63BitValue() val proposal = assembleProposal(originalState.ref, modification, stx) - val handshake = Handshake(sessionIdForSend, serviceHub.networkService.myAddress, sessionIdForReceive) - sendAndReceive(TOPIC_INITIATE, node.address, 0, sessionIdForReceive, handshake) + val handshake = Handshake(sessionIdForSend, serviceHub.storageService.myLegalIdentity, sessionIdForReceive) + sendAndReceive(TOPIC_INITIATE, node.identity, 0, sessionIdForReceive, handshake) - val response = sendAndReceive(TOPIC_CHANGE, node.address, sessionIdForSend, sessionIdForReceive, proposal) + val response = sendAndReceive(TOPIC_CHANGE, node.identity, sessionIdForSend, sessionIdForReceive, proposal) val participantSignature = response.validate { if (it.sig == null) throw StateReplacementException(it.error!!) else { @@ -122,7 +121,7 @@ abstract class AbstractStateReplacementProtocol { } } - abstract class Acceptor(val otherSide: SingleMessageRecipient, + abstract class Acceptor(val otherSide: Party, val sessionIdForSend: Long, val sessionIdForReceive: Long, override val progressTracker: ProgressTracker = tracker()) : ProtocolLogic() { @@ -241,4 +240,4 @@ class StateReplacementRefused(val identity: Party, val state: StateRef, val deta } class StateReplacementException(val error: StateReplacementRefused) -: Exception("State change failed - ${error}") \ No newline at end of file +: Exception("State change failed - $error") \ No newline at end of file diff --git a/core/src/main/kotlin/protocols/NotaryChangeProtocol.kt b/core/src/main/kotlin/protocols/NotaryChangeProtocol.kt index 2caf6069c2..f4427aee15 100644 --- a/core/src/main/kotlin/protocols/NotaryChangeProtocol.kt +++ b/core/src/main/kotlin/protocols/NotaryChangeProtocol.kt @@ -2,18 +2,8 @@ package protocols import co.paralleluniverse.fibers.Suspendable import com.r3corda.core.contracts.* -import com.r3corda.core.crypto.DigitalSignature import com.r3corda.core.crypto.Party -import com.r3corda.core.crypto.signWithECDSA -import com.r3corda.core.messaging.Ack -import com.r3corda.core.messaging.SingleMessageRecipient -import com.r3corda.core.node.NodeInfo -import com.r3corda.core.protocols.ProtocolLogic -import com.r3corda.core.random63BitValue import com.r3corda.core.utilities.ProgressTracker -import com.r3corda.protocols.AbstractRequestMessage -import com.r3corda.protocols.NotaryProtocol -import com.r3corda.protocols.ResolveTransactionsProtocol import java.security.PublicKey /** @@ -58,7 +48,7 @@ object NotaryChangeProtocol: AbstractStateReplacementProtocol() { } } - class Acceptor(otherSide: SingleMessageRecipient, + class Acceptor(otherSide: Party, sessionIdForSend: Long, sessionIdForReceive: Long, override val progressTracker: ProgressTracker = tracker()) diff --git a/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt index 06abdc96b1..7838807b5a 100644 --- a/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt @@ -33,6 +33,7 @@ import com.r3corda.node.services.keys.E2ETestKeyManagementService import com.r3corda.node.services.network.InMemoryNetworkMapCache import com.r3corda.node.services.network.InMemoryNetworkMapService import com.r3corda.node.services.network.NetworkMapService +import com.r3corda.node.services.network.NetworkMapService.Companion.REGISTER_PROTOCOL_TOPIC import com.r3corda.node.services.network.NodeRegistration import com.r3corda.node.services.persistence.* import com.r3corda.node.services.statemachine.StateMachineManager @@ -50,7 +51,6 @@ import java.nio.file.FileAlreadyExistsException import java.nio.file.Files import java.nio.file.Path import java.security.KeyPair -import java.security.Security import java.time.Clock import java.util.* @@ -160,8 +160,8 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration, // This object doesn't need to be referenced from this class because it registers handlers on the network // service and so that keeps it from being collected. - DataVendingService(net, storage) - NotaryChangeService(net, smm) + DataVendingService(net, storage, services.networkMapCache) + NotaryChangeService(net, smm, services.networkMapCache) buildAdvertisedServices() @@ -231,9 +231,9 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration, val reg = NodeRegistration(info, networkMapSeq++, type, expires) val sessionID = random63BitValue() val request = NetworkMapService.RegistrationRequest(reg.toWire(storage.myLegalIdentityKey.private), net.myAddress, sessionID) - val message = net.createMessage(NetworkMapService.REGISTER_PROTOCOL_TOPIC + ".0", request.serialize().bits) + val message = net.createMessage("$REGISTER_PROTOCOL_TOPIC.0", request.serialize().bits) val future = SettableFuture.create() - val topic = NetworkMapService.REGISTER_PROTOCOL_TOPIC + "." + sessionID + val topic = "$REGISTER_PROTOCOL_TOPIC.$sessionID" net.runOnNextMessage(topic, RunOnCallerThread) { message -> future.set(message.data.deserialize()) @@ -254,8 +254,8 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration, val timestampChecker = TimestampChecker(platformClock, 30.seconds) inNodeNotaryService = when (type) { - is SimpleNotaryService.Type -> SimpleNotaryService(smm, net, timestampChecker, uniquenessProvider) - is ValidatingNotaryService.Type -> ValidatingNotaryService(smm, net, timestampChecker, uniquenessProvider) + is SimpleNotaryService.Type -> SimpleNotaryService(smm, net, timestampChecker, uniquenessProvider, services.networkMapCache) + is ValidatingNotaryService.Type -> ValidatingNotaryService(smm, net, timestampChecker, uniquenessProvider, services.networkMapCache) else -> null } } diff --git a/node/src/main/kotlin/com/r3corda/node/internal/testing/IRSSimulation.kt b/node/src/main/kotlin/com/r3corda/node/internal/testing/IRSSimulation.kt index d3bf112590..674d663d4d 100644 --- a/node/src/main/kotlin/com/r3corda/node/internal/testing/IRSSimulation.kt +++ b/node/src/main/kotlin/com/r3corda/node/internal/testing/IRSSimulation.kt @@ -130,8 +130,8 @@ class IRSSimulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, laten val sessionID = random63BitValue() - val instigator = TwoPartyDealProtocol.Instigator(node2.net.myAddress, notary.info.identity, irs, nodeAKey!!, sessionID) - val acceptor = TwoPartyDealProtocol.Acceptor(node1.net.myAddress, notary.info.identity, irs, sessionID) + val instigator = TwoPartyDealProtocol.Instigator(node2.info.identity, notary.info.identity, irs, nodeAKey!!, sessionID) + val acceptor = TwoPartyDealProtocol.Acceptor(node1.info.identity, notary.info.identity, irs, sessionID) showProgressFor(listOf(node1, node2)) showConsensusFor(listOf(node1, node2, regulators[0])) diff --git a/node/src/main/kotlin/com/r3corda/node/internal/testing/TradeSimulation.kt b/node/src/main/kotlin/com/r3corda/node/internal/testing/TradeSimulation.kt index 1acf61bc08..f86236517e 100644 --- a/node/src/main/kotlin/com/r3corda/node/internal/testing/TradeSimulation.kt +++ b/node/src/main/kotlin/com/r3corda/node/internal/testing/TradeSimulation.kt @@ -44,10 +44,19 @@ class TradeSimulation(runAsync: Boolean, latencyInjector: InMemoryMessagingNetwo val cashIssuerKey = generateKeyPair() val amount = 1000.DOLLARS `issued by` Party("Big friendly bank", cashIssuerKey.public).ref(1) val sessionID = random63BitValue() - val buyerProtocol = TwoPartyTradeProtocol.Buyer(seller.net.myAddress, notary.info.identity, - amount, CommercialPaper.State::class.java, sessionID) - val sellerProtocol = TwoPartyTradeProtocol.Seller(buyer.net.myAddress, notary.info, - issuance.tx.outRef(0), amount, seller.storage.myLegalIdentityKey, sessionID) + val buyerProtocol = TwoPartyTradeProtocol.Buyer( + seller.info.identity, + notary.info.identity, + amount, + CommercialPaper.State::class.java, + sessionID) + val sellerProtocol = TwoPartyTradeProtocol.Seller( + buyer.info.identity, + notary.info, + issuance.tx.outRef(0), + amount, + seller.storage.myLegalIdentityKey, + sessionID) showConsensusFor(listOf(buyer, seller, notary)) showProgressFor(listOf(buyer, seller)) diff --git a/node/src/main/kotlin/com/r3corda/node/services/NotaryChangeService.kt b/node/src/main/kotlin/com/r3corda/node/services/NotaryChangeService.kt index 6e0378c52f..e1b88f1c36 100644 --- a/node/src/main/kotlin/com/r3corda/node/services/NotaryChangeService.kt +++ b/node/src/main/kotlin/com/r3corda/node/services/NotaryChangeService.kt @@ -2,7 +2,7 @@ package com.r3corda.node.services import com.r3corda.core.messaging.Ack import com.r3corda.core.messaging.MessagingService -import com.r3corda.core.messaging.SingleMessageRecipient +import com.r3corda.core.node.services.NetworkMapCache import com.r3corda.node.services.api.AbstractNodeService import com.r3corda.node.services.statemachine.StateMachineManager import protocols.AbstractStateReplacementProtocol @@ -12,7 +12,7 @@ import protocols.NotaryChangeProtocol * A service that monitors the network for requests for changing the notary of a state, * and immediately runs the [NotaryChangeProtocol] if the auto-accept criteria are met. */ -class NotaryChangeService(net: MessagingService, val smm: StateMachineManager) : AbstractNodeService(net) { +class NotaryChangeService(net: MessagingService, val smm: StateMachineManager, networkMapCache: NetworkMapCache) : AbstractNodeService(net, networkMapCache) { init { addMessageHandler(NotaryChangeProtocol.TOPIC_INITIATE, { req: AbstractStateReplacementProtocol.Handshake -> handleChangeNotaryRequest(req) } @@ -21,8 +21,8 @@ class NotaryChangeService(net: MessagingService, val smm: StateMachineManager) : private fun handleChangeNotaryRequest(req: AbstractStateReplacementProtocol.Handshake): Ack { val protocol = NotaryChangeProtocol.Acceptor( - req.replyTo as SingleMessageRecipient, - req.sessionID!!, + req.replyToParty, + req.sessionID, req.sessionIdForSend) smm.add(NotaryChangeProtocol.TOPIC_CHANGE, protocol) return Ack diff --git a/node/src/main/kotlin/com/r3corda/node/services/api/AbstractNodeService.kt b/node/src/main/kotlin/com/r3corda/node/services/api/AbstractNodeService.kt index 0827dc1066..d688a8e834 100644 --- a/node/src/main/kotlin/com/r3corda/node/services/api/AbstractNodeService.kt +++ b/node/src/main/kotlin/com/r3corda/node/services/api/AbstractNodeService.kt @@ -2,18 +2,19 @@ package com.r3corda.node.services.api import com.r3corda.core.messaging.Message import com.r3corda.core.messaging.MessagingService +import com.r3corda.core.node.services.NetworkMapCache import com.r3corda.core.node.services.TOPIC_DEFAULT_POSTFIX import com.r3corda.core.serialization.SingletonSerializeAsToken import com.r3corda.core.serialization.deserialize import com.r3corda.core.serialization.serialize -import com.r3corda.protocols.AbstractRequestMessage +import com.r3corda.protocols.ServiceRequestMessage import javax.annotation.concurrent.ThreadSafe /** * Abstract superclass for services that a node can host, which provides helper functions. */ @ThreadSafe -abstract class AbstractNodeService(val net: MessagingService) : SingletonSerializeAsToken() { +abstract class AbstractNodeService(val net: MessagingService, val networkMapCache: NetworkMapCache) : SingletonSerializeAsToken() { /** * Register a handler for a message topic. In comparison to using net.addMessageHandler() this manages a lot of @@ -24,18 +25,18 @@ abstract class AbstractNodeService(val net: MessagingService) : SingletonSeriali * @param handler a function to handle the deserialised request and return an optional response (if return type not Unit) * @param exceptionConsumer a function to which any thrown exception is passed. */ - protected inline fun + protected inline fun addMessageHandler(topic: String, crossinline handler: (Q) -> R, crossinline exceptionConsumer: (Message, Exception) -> Unit) { net.addMessageHandler(topic + TOPIC_DEFAULT_POSTFIX, null) { message, r -> try { - val req = message.data.deserialize() - val data = handler(req) + val request = message.data.deserialize() + val response = handler(request) // If the return type R is Unit, then do not send a response - if (data.javaClass != Unit.javaClass) { - val msg = net.createMessage("$topic.${req.sessionID}", data.serialize().bits) - net.send(msg, req.replyTo) + if (response.javaClass != Unit.javaClass) { + val msg = net.createMessage("$topic.${request.sessionID}", response.serialize().bits) + net.send(msg, request.getReplyTo(networkMapCache)) } } catch(e: Exception) { exceptionConsumer(message, e) @@ -51,7 +52,7 @@ abstract class AbstractNodeService(val net: MessagingService) : SingletonSeriali * @param topic the topic, without the default session ID postfix (".0) * @param handler a function to handle the deserialised request and return an optional response (if return type not Unit) */ - protected inline fun + protected inline fun addMessageHandler(topic: String, crossinline handler: (Q) -> R) { addMessageHandler(topic, handler, { message: Message, exception: Exception -> throw exception }) diff --git a/node/src/main/kotlin/com/r3corda/node/services/clientapi/NodeInterestRates.kt b/node/src/main/kotlin/com/r3corda/node/services/clientapi/NodeInterestRates.kt index 83102bd4ff..f4cd859470 100644 --- a/node/src/main/kotlin/com/r3corda/node/services/clientapi/NodeInterestRates.kt +++ b/node/src/main/kotlin/com/r3corda/node/services/clientapi/NodeInterestRates.kt @@ -41,7 +41,7 @@ object NodeInterestRates { /** * The Service that wraps [Oracle] and handles messages/network interaction/request scrubbing. */ - class Service(node: AbstractNode) : AcceptsFileUpload, AbstractNodeService(node.services.networkService) { + class Service(node: AbstractNode) : AcceptsFileUpload, AbstractNodeService(node.services.networkService, node.services.networkMapCache) { val ss = node.services.storageService val oracle = Oracle(ss.myLegalIdentity, ss.myLegalIdentityKey, node.services.clock) @@ -84,7 +84,7 @@ object NodeInterestRates { override fun call(): Unit { val answers = service.oracle.query(request.queries, request.deadline) progressTracker.currentStep = SENDING - send("${RatesFixProtocol.TOPIC}.query", request.replyTo, request.sessionID!!, answers) + send("${RatesFixProtocol.TOPIC}.query", request.replyToParty, request.sessionID, answers) } } diff --git a/node/src/main/kotlin/com/r3corda/node/services/network/NetworkMapService.kt b/node/src/main/kotlin/com/r3corda/node/services/network/NetworkMapService.kt index ede0a51205..ccd6a3545c 100644 --- a/node/src/main/kotlin/com/r3corda/node/services/network/NetworkMapService.kt +++ b/node/src/main/kotlin/com/r3corda/node/services/network/NetworkMapService.kt @@ -7,16 +7,16 @@ import com.r3corda.core.messaging.MessageRecipients import com.r3corda.core.messaging.MessagingService import com.r3corda.core.messaging.SingleMessageRecipient import com.r3corda.core.node.NodeInfo -import com.r3corda.core.node.services.ServiceType import com.r3corda.core.node.services.NetworkMapCache +import com.r3corda.core.node.services.ServiceType import com.r3corda.core.node.services.TOPIC_DEFAULT_POSTFIX import com.r3corda.core.serialization.SerializedBytes import com.r3corda.core.serialization.deserialize import com.r3corda.core.serialization.serialize import com.r3corda.node.services.api.AbstractNodeService import com.r3corda.node.utilities.AddOrRemove +import com.r3corda.protocols.ServiceRequestMessage import org.slf4j.LoggerFactory -import com.r3corda.protocols.AbstractRequestMessage import java.security.PrivateKey import java.security.SignatureException import java.time.Instant @@ -61,20 +61,25 @@ interface NetworkMapService { val nodes: List - class FetchMapRequest(val subscribe: Boolean, val ifChangedSinceVersion: Int?, replyTo: MessageRecipients, sessionID: Long) : AbstractRequestMessage(replyTo, sessionID) + abstract class NetworkMapRequestMessage(val replyTo: MessageRecipients) : ServiceRequestMessage { + override fun getReplyTo(networkMapCache: NetworkMapCache): MessageRecipients = replyTo + } + + class FetchMapRequest(val subscribe: Boolean, val ifChangedSinceVersion: Int?, replyTo: MessageRecipients, override val sessionID: Long) : NetworkMapRequestMessage(replyTo) data class FetchMapResponse(val nodes: Collection?, val version: Int) - class QueryIdentityRequest(val identity: Party, replyTo: MessageRecipients, sessionID: Long) : AbstractRequestMessage(replyTo, sessionID) + class QueryIdentityRequest(val identity: Party, replyTo: MessageRecipients, override val sessionID: Long) : NetworkMapRequestMessage(replyTo) data class QueryIdentityResponse(val node: NodeInfo?) - class RegistrationRequest(val wireReg: WireNodeRegistration, replyTo: MessageRecipients, sessionID: Long) : AbstractRequestMessage(replyTo, sessionID) + class RegistrationRequest(val wireReg: WireNodeRegistration, replyTo: MessageRecipients, override val sessionID: Long) : NetworkMapRequestMessage(replyTo) data class RegistrationResponse(val success: Boolean) - class SubscribeRequest(val subscribe: Boolean, replyTo: MessageRecipients, sessionID: Long) : AbstractRequestMessage(replyTo, sessionID) + class SubscribeRequest(val subscribe: Boolean, replyTo: MessageRecipients, override val sessionID: Long) : NetworkMapRequestMessage(replyTo) data class SubscribeResponse(val confirmed: Boolean) data class Update(val wireReg: WireNodeRegistration, val replyTo: MessageRecipients) data class UpdateAcknowledge(val wireRegHash: SecureHash, val replyTo: MessageRecipients) } + @ThreadSafe -class InMemoryNetworkMapService(net: MessagingService, home: NodeRegistration, val cache: NetworkMapCache) : NetworkMapService, AbstractNodeService(net) { +class InMemoryNetworkMapService(net: MessagingService, home: NodeRegistration, val cache: NetworkMapCache) : NetworkMapService, AbstractNodeService(net, cache) { private val registeredNodes = ConcurrentHashMap() // Map from subscriber address, to a list of unacknowledged updates private val subscribers = ThreadBox(mutableMapOf>()) diff --git a/node/src/main/kotlin/com/r3corda/node/services/persistence/DataVendingService.kt b/node/src/main/kotlin/com/r3corda/node/services/persistence/DataVendingService.kt index 43a09867ab..1468897f9a 100644 --- a/node/src/main/kotlin/com/r3corda/node/services/persistence/DataVendingService.kt +++ b/node/src/main/kotlin/com/r3corda/node/services/persistence/DataVendingService.kt @@ -2,6 +2,7 @@ package com.r3corda.node.services.persistence import com.r3corda.core.contracts.SignedTransaction import com.r3corda.core.messaging.MessagingService +import com.r3corda.core.node.services.NetworkMapCache import com.r3corda.core.node.services.StorageService import com.r3corda.core.utilities.loggerFor import com.r3corda.node.services.api.AbstractNodeService @@ -24,7 +25,7 @@ import javax.annotation.concurrent.ThreadSafe * Additionally, because nodes do not store invalid transactions, requesting such a transaction will always yield null. */ @ThreadSafe -class DataVendingService(net: MessagingService, private val storage: StorageService) : AbstractNodeService(net) { +class DataVendingService(net: MessagingService, private val storage: StorageService, networkMapCache: NetworkMapCache) : AbstractNodeService(net, networkMapCache) { companion object { val logger = loggerFor() } diff --git a/node/src/main/kotlin/com/r3corda/node/services/statemachine/ProtocolStateMachineImpl.kt b/node/src/main/kotlin/com/r3corda/node/services/statemachine/ProtocolStateMachineImpl.kt index 56000f4700..43a5aa98cc 100644 --- a/node/src/main/kotlin/com/r3corda/node/services/statemachine/ProtocolStateMachineImpl.kt +++ b/node/src/main/kotlin/com/r3corda/node/services/statemachine/ProtocolStateMachineImpl.kt @@ -5,7 +5,7 @@ import co.paralleluniverse.fibers.FiberScheduler import co.paralleluniverse.fibers.Suspendable import com.google.common.util.concurrent.ListenableFuture import com.google.common.util.concurrent.SettableFuture -import com.r3corda.core.messaging.MessageRecipients +import com.r3corda.core.crypto.Party import com.r3corda.core.protocols.ProtocolLogic import com.r3corda.core.protocols.ProtocolStateMachine import com.r3corda.core.utilities.UntrustworthyData @@ -81,9 +81,13 @@ class ProtocolStateMachineImpl(val logic: ProtocolLogic, } @Suspendable @Suppress("UNCHECKED_CAST") - override fun sendAndReceive(topic: String, destination: MessageRecipients, sessionIDForSend: Long, sessionIDForReceive: Long, - obj: Any, recvType: Class): UntrustworthyData { - val result = StateMachineManager.FiberRequest.ExpectingResponse(topic, destination, sessionIDForSend, sessionIDForReceive, obj, recvType) + override fun sendAndReceive(topic: String, + destination: Party, + sessionIDForSend: Long, + sessionIDForReceive: Long, + payload: Any, + recvType: Class): UntrustworthyData { + val result = StateMachineManager.FiberRequest.ExpectingResponse(topic, destination, sessionIDForSend, sessionIDForReceive, payload, recvType) return suspendAndExpectReceive(result) } @@ -94,8 +98,8 @@ class ProtocolStateMachineImpl(val logic: ProtocolLogic, } @Suspendable - override fun send(topic: String, destination: MessageRecipients, sessionID: Long, obj: Any) { - val result = StateMachineManager.FiberRequest.NotExpectingResponse(topic, destination, sessionID, obj) + override fun send(topic: String, destination: Party, sessionID: Long, payload: Any) { + val result = StateMachineManager.FiberRequest.NotExpectingResponse(topic, destination, sessionID, payload) suspend(result) } diff --git a/node/src/main/kotlin/com/r3corda/node/services/statemachine/StateMachineManager.kt b/node/src/main/kotlin/com/r3corda/node/services/statemachine/StateMachineManager.kt index 2616585dec..dfb752cfd0 100644 --- a/node/src/main/kotlin/com/r3corda/node/services/statemachine/StateMachineManager.kt +++ b/node/src/main/kotlin/com/r3corda/node/services/statemachine/StateMachineManager.kt @@ -8,7 +8,7 @@ import com.esotericsoftware.kryo.Kryo import com.google.common.base.Throwables import com.google.common.util.concurrent.ListenableFuture import com.r3corda.core.abbreviate -import com.r3corda.core.messaging.MessageRecipients +import com.r3corda.core.crypto.Party import com.r3corda.core.messaging.runOnNextMessage import com.r3corda.core.messaging.send import com.r3corda.core.protocols.ProtocolLogic @@ -253,7 +253,8 @@ class StateMachineManager(val serviceHub: ServiceHubInternal, tokenizableService request.payload?.let { val topic = "${request.topic}.${request.sessionIDForSend}" psm.logger.trace { "Sending message of type ${it.javaClass.name} using topic $topic to ${request.destination} (${it.toString().abbreviate(50)})" } - serviceHub.networkService.send(topic, it, request.destination!!) + val address = serviceHub.networkMapCache.getNodeByLegalName(request.destination!!.name)!!.address + serviceHub.networkService.send(topic, it, address) } if (request is FiberRequest.NotExpectingResponse) { // We sent a message, but don't expect a response, so re-enter the continuation to let it keep going. @@ -307,7 +308,7 @@ class StateMachineManager(val serviceHub: ServiceHubInternal, tokenizableService // TODO: Clean this up open class FiberRequest(val topic: String, - val destination: MessageRecipients?, + val destination: Party?, val sessionIDForSend: Long, val sessionIDForReceive: Long, val payload: Any?) { @@ -317,7 +318,7 @@ class StateMachineManager(val serviceHub: ServiceHubInternal, tokenizableService class ExpectingResponse( topic: String, - destination: MessageRecipients?, + destination: Party?, sessionIDForSend: Long, sessionIDForReceive: Long, obj: Any?, @@ -326,7 +327,7 @@ class StateMachineManager(val serviceHub: ServiceHubInternal, tokenizableService class NotExpectingResponse( topic: String, - destination: MessageRecipients, + destination: Party, sessionIDForSend: Long, obj: Any? ) : FiberRequest(topic, destination, sessionIDForSend, -1, obj) diff --git a/node/src/main/kotlin/com/r3corda/node/services/transactions/NotaryService.kt b/node/src/main/kotlin/com/r3corda/node/services/transactions/NotaryService.kt index c549734ad0..aa69394e70 100644 --- a/node/src/main/kotlin/com/r3corda/node/services/transactions/NotaryService.kt +++ b/node/src/main/kotlin/com/r3corda/node/services/transactions/NotaryService.kt @@ -2,7 +2,7 @@ package com.r3corda.node.services.transactions import com.r3corda.core.messaging.Ack import com.r3corda.core.messaging.MessagingService -import com.r3corda.core.messaging.SingleMessageRecipient +import com.r3corda.core.node.services.NetworkMapCache import com.r3corda.core.node.services.ServiceType import com.r3corda.core.node.services.TimestampChecker import com.r3corda.core.node.services.UniquenessProvider @@ -22,7 +22,8 @@ import com.r3corda.protocols.NotaryProtocol abstract class NotaryService(val smm: StateMachineManager, net: MessagingService, val timestampChecker: TimestampChecker, - val uniquenessProvider: UniquenessProvider) : AbstractNodeService(net) { + val uniquenessProvider: UniquenessProvider, + networkMapCache: NetworkMapCache) : AbstractNodeService(net, networkMapCache) { object Type : ServiceType("corda.notary") abstract val logger: org.slf4j.Logger @@ -37,8 +38,9 @@ abstract class NotaryService(val smm: StateMachineManager, } private fun processRequest(req: NotaryProtocol.Handshake): Ack { - val protocol = protocolFactory.create(req.replyTo as SingleMessageRecipient, - req.sessionID!!, + val protocol = protocolFactory.create( + req.replyToParty, + req.sessionID, req.sendSessionID, timestampChecker, uniquenessProvider) diff --git a/node/src/main/kotlin/com/r3corda/node/services/transactions/SimpleNotaryService.kt b/node/src/main/kotlin/com/r3corda/node/services/transactions/SimpleNotaryService.kt index 850d84d40f..3cf38589f8 100644 --- a/node/src/main/kotlin/com/r3corda/node/services/transactions/SimpleNotaryService.kt +++ b/node/src/main/kotlin/com/r3corda/node/services/transactions/SimpleNotaryService.kt @@ -1,6 +1,7 @@ package com.r3corda.node.services.transactions import com.r3corda.core.messaging.MessagingService +import com.r3corda.core.node.services.NetworkMapCache import com.r3corda.core.node.services.ServiceType import com.r3corda.core.node.services.TimestampChecker import com.r3corda.core.node.services.UniquenessProvider @@ -13,7 +14,8 @@ class SimpleNotaryService( smm: StateMachineManager, net: MessagingService, timestampChecker: TimestampChecker, - uniquenessProvider: UniquenessProvider) : NotaryService(smm, net, timestampChecker, uniquenessProvider) { + uniquenessProvider: UniquenessProvider, + networkMapCache: NetworkMapCache) : NotaryService(smm, net, timestampChecker, uniquenessProvider, networkMapCache) { object Type : ServiceType("corda.notary.simple") override val logger = loggerFor() diff --git a/node/src/main/kotlin/com/r3corda/node/services/transactions/ValidatingNotaryService.kt b/node/src/main/kotlin/com/r3corda/node/services/transactions/ValidatingNotaryService.kt index 3b0fc6faf1..d6f8fac88a 100644 --- a/node/src/main/kotlin/com/r3corda/node/services/transactions/ValidatingNotaryService.kt +++ b/node/src/main/kotlin/com/r3corda/node/services/transactions/ValidatingNotaryService.kt @@ -1,7 +1,8 @@ package com.r3corda.node.services.transactions +import com.r3corda.core.crypto.Party import com.r3corda.core.messaging.MessagingService -import com.r3corda.core.messaging.SingleMessageRecipient +import com.r3corda.core.node.services.NetworkMapCache import com.r3corda.core.node.services.ServiceType import com.r3corda.core.node.services.TimestampChecker import com.r3corda.core.node.services.UniquenessProvider @@ -15,14 +16,15 @@ class ValidatingNotaryService( smm: StateMachineManager, net: MessagingService, timestampChecker: TimestampChecker, - uniquenessProvider: UniquenessProvider -) : NotaryService(smm, net, timestampChecker, uniquenessProvider) { + uniquenessProvider: UniquenessProvider, + networkMapCache: NetworkMapCache +) : NotaryService(smm, net, timestampChecker, uniquenessProvider, networkMapCache) { object Type : ServiceType("corda.notary.validating") override val logger = loggerFor() override val protocolFactory = object : NotaryProtocol.Factory { - override fun create(otherSide: SingleMessageRecipient, + override fun create(otherSide: Party, sendSessionID: Long, receiveSessionID: Long, timestampChecker: TimestampChecker, diff --git a/node/src/test/kotlin/com/r3corda/node/messaging/AttachmentTests.kt b/node/src/test/kotlin/com/r3corda/node/messaging/AttachmentTests.kt index b38dc92be6..eddd1f3f94 100644 --- a/node/src/test/kotlin/com/r3corda/node/messaging/AttachmentTests.kt +++ b/node/src/test/kotlin/com/r3corda/node/messaging/AttachmentTests.kt @@ -59,7 +59,8 @@ class AttachmentTests { val id = n0.storage.attachments.importAttachment(ByteArrayInputStream(fakeAttachment())) // Get node one to run a protocol to fetch it and insert it. - val f1 = n1.smm.add("tests.fetch1", FetchAttachmentsProtocol(setOf(id), n0.net.myAddress)) + network.runNetwork() + val f1 = n1.smm.add("tests.fetch1", FetchAttachmentsProtocol(setOf(id), n0.info.identity)) network.runNetwork() assertEquals(0, f1.get().fromDisk.size) @@ -70,7 +71,7 @@ class AttachmentTests { // Shut down node zero and ensure node one can still resolve the attachment. n0.stop() - val response: FetchDataProtocol.Result = n1.smm.add("tests.fetch1", FetchAttachmentsProtocol(setOf(id), n0.net.myAddress)).get() + val response: FetchDataProtocol.Result = n1.smm.add("tests.fetch1", FetchAttachmentsProtocol(setOf(id), n0.info.identity)).get() assertEquals(attachment, response.fromDisk[0]) } @@ -80,14 +81,15 @@ class AttachmentTests { // Get node one to fetch a non-existent attachment. val hash = SecureHash.randomSHA256() - val f1 = n1.smm.add("tests.fetch2", FetchAttachmentsProtocol(setOf(hash), n0.net.myAddress)) + network.runNetwork() + val f1 = n1.smm.add("tests.fetch2", FetchAttachmentsProtocol(setOf(hash), n0.info.identity)) network.runNetwork() val e = assertFailsWith { rootCauseExceptions { f1.get() } } assertEquals(hash, e.requested) } @Test - fun maliciousResponse() { + fun `malicious response`() { // Make a node that doesn't do sanity checking at load time. val n0 = network.createNode(null, -1, object : MockNetwork.Factory { override fun create(dir: Path, config: NodeConfiguration, network: MockNetwork, networkMapAddr: NodeInfo?, @@ -112,7 +114,8 @@ class AttachmentTests { writer.close() // Get n1 to fetch the attachment. Should receive corrupted bytes. - val f1 = n1.smm.add("tests.fetch1", FetchAttachmentsProtocol(setOf(id), n0.net.myAddress)) + network.runNetwork() + val f1 = n1.smm.add("tests.fetch1", FetchAttachmentsProtocol(setOf(id), n0.info.identity)) network.runNetwork() assertFailsWith { rootCauseExceptions { f1.get() } diff --git a/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt b/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt index 7975972f8b..0934eed820 100644 --- a/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt +++ b/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt @@ -11,7 +11,6 @@ import com.r3corda.core.contracts.* import com.r3corda.core.crypto.Party import com.r3corda.core.crypto.SecureHash import com.r3corda.core.days -import com.r3corda.core.messaging.SingleMessageRecipient import com.r3corda.core.node.NodeInfo import com.r3corda.core.node.ServiceHub import com.r3corda.core.node.services.ServiceType @@ -56,14 +55,14 @@ class TwoPartyTradeProtocolTests { lateinit var net: MockNetwork private fun runSeller(smm: StateMachineManager, notary: NodeInfo, - otherSide: SingleMessageRecipient, assetToSell: StateAndRef, price: Amount>, + otherSide: Party, assetToSell: StateAndRef, price: Amount>, myKeyPair: KeyPair, buyerSessionID: Long): ListenableFuture { val seller = TwoPartyTradeProtocol.Seller(otherSide, notary, assetToSell, price, myKeyPair, buyerSessionID) return smm.add("${TwoPartyTradeProtocol.TRADE_TOPIC}.seller", seller) } private fun runBuyer(smm: StateMachineManager, notaryNode: NodeInfo, - otherSide: SingleMessageRecipient, acceptablePrice: Amount>, typeToBuy: Class, + otherSide: Party, acceptablePrice: Amount>, typeToBuy: Class, sessionID: Long): ListenableFuture { val buyer = TwoPartyTradeProtocol.Buyer(otherSide, notaryNode.identity, acceptablePrice, typeToBuy, sessionID) return smm.add("${TwoPartyTradeProtocol.TRADE_TOPIC}.buyer", buyer) @@ -105,7 +104,7 @@ class TwoPartyTradeProtocolTests { val bobResult = runBuyer( bobNode.smm, notaryNode.info, - aliceNode.net.myAddress, + aliceNode.info.identity, 1000.DOLLARS `issued by` issuer, CommercialPaper.State::class.java, buyerSessionID @@ -113,7 +112,7 @@ class TwoPartyTradeProtocolTests { val aliceResult = runSeller( aliceNode.smm, notaryNode.info, - bobNode.net.myAddress, + bobNode.info.identity, lookup("alice's paper"), 1000.DOLLARS `issued by` issuer, ALICE_KEY, @@ -139,7 +138,6 @@ class TwoPartyTradeProtocolTests { val aliceNode = net.createPartyNode(notaryNode.info, ALICE.name, ALICE_KEY) var bobNode = net.createPartyNode(notaryNode.info, BOB.name, BOB_KEY) - val aliceAddr = aliceNode.net.myAddress val bobAddr = bobNode.net.myAddress as InMemoryMessagingNetwork.Handle val networkMapAddr = notaryNode.info val issuer = bobNode.services.storageService.myLegalIdentity.ref(0) @@ -156,7 +154,7 @@ class TwoPartyTradeProtocolTests { val aliceFuture = runSeller( aliceNode.smm, notaryNode.info, - bobAddr, + bobNode.info.identity, lookup("alice's paper"), 1000.DOLLARS `issued by` issuer, ALICE_KEY, @@ -165,7 +163,7 @@ class TwoPartyTradeProtocolTests { runBuyer( bobNode.smm, notaryNode.info, - aliceAddr, + aliceNode.info.identity, 1000.DOLLARS `issued by` issuer, CommercialPaper.State::class.java, buyerSessionID @@ -276,7 +274,7 @@ class TwoPartyTradeProtocolTests { runSeller( aliceNode.smm, notaryNode.info, - bobNode.net.myAddress, + bobNode.info.identity, lookup("alice's paper"), 1000.DOLLARS `issued by` issuer, ALICE_KEY, @@ -285,7 +283,7 @@ class TwoPartyTradeProtocolTests { runBuyer( bobNode.smm, notaryNode.info, - aliceNode.net.myAddress, + aliceNode.info.identity, 1000.DOLLARS `issued by` issuer, CommercialPaper.State::class.java, buyerSessionID @@ -371,9 +369,6 @@ class TwoPartyTradeProtocolTests { val bobNode = net.createPartyNode(notaryNode.info, BOB.name, BOB_KEY) val issuer = MEGA_CORP.ref(1, 2, 3) - val aliceAddr = aliceNode.net.myAddress - val bobAddr = bobNode.net.myAddress as InMemoryMessagingNetwork.Handle - val bobKey = bobNode.keyManagement.freshKey() val bobsBadCash = fillUpForBuyer(bobError, bobKey.public).second val alicesFakePaper = fillUpForSeller(aliceError, aliceNode.storage.myLegalIdentity.owningKey, @@ -389,7 +384,7 @@ class TwoPartyTradeProtocolTests { val aliceResult = runSeller( aliceNode.smm, notaryNode.info, - bobAddr, + bobNode.info.identity, lookup("alice's paper"), 1000.DOLLARS `issued by` issuer, ALICE_KEY, @@ -398,7 +393,7 @@ class TwoPartyTradeProtocolTests { val bobResult = runBuyer( bobNode.smm, notaryNode.info, - aliceAddr, + aliceNode.info.identity, 1000.DOLLARS `issued by` issuer, CommercialPaper.State::class.java, buyerSessionID diff --git a/node/src/test/kotlin/com/r3corda/node/services/InMemoryNetworkMapServiceTest.kt b/node/src/test/kotlin/com/r3corda/node/services/InMemoryNetworkMapServiceTest.kt index cbfabb5bfe..29c1221d98 100644 --- a/node/src/test/kotlin/com/r3corda/node/services/InMemoryNetworkMapServiceTest.kt +++ b/node/src/test/kotlin/com/r3corda/node/services/InMemoryNetworkMapServiceTest.kt @@ -59,7 +59,7 @@ class InMemoryNetworkMapServiceTest { assertEquals(2, service.nodes.count()) // Confirm that de-registering the node succeeds and drops it from the node lists - var removeChange = NodeRegistration(registerNode.info, seq, AddOrRemove.REMOVE, expires) + val removeChange = NodeRegistration(registerNode.info, seq, AddOrRemove.REMOVE, expires) val removeWireChange = removeChange.toWire(nodeKey.private) assert(service.processRegistrationChangeRequest(NetworkMapService.RegistrationRequest(removeWireChange, mapServiceNode.info.address, Long.MIN_VALUE)).success) assertNull(service.processQueryRequest(NetworkMapService.QueryIdentityRequest(registerNode.info.identity, mapServiceNode.info.address, Long.MIN_VALUE)).node) @@ -73,7 +73,7 @@ class InMemoryNetworkMapServiceTest { @Suspendable override fun call() { val req = NetworkMapService.UpdateAcknowledge(hash, serviceHub.networkService.myAddress) - send(NetworkMapService.PUSH_ACK_PROTOCOL_TOPIC, server.address, 0, req) + send(NetworkMapService.PUSH_ACK_PROTOCOL_TOPIC, server.identity, 0, req) } } @@ -84,7 +84,7 @@ class InMemoryNetworkMapServiceTest { val sessionID = random63BitValue() val req = NetworkMapService.FetchMapRequest(subscribe, ifChangedSinceVersion, serviceHub.networkService.myAddress, sessionID) return sendAndReceive( - NetworkMapService.FETCH_PROTOCOL_TOPIC, server.address, 0, sessionID, req) + NetworkMapService.FETCH_PROTOCOL_TOPIC, server.identity, 0, sessionID, req) .validate { it.nodes } } } @@ -97,7 +97,7 @@ class InMemoryNetworkMapServiceTest { val req = NetworkMapService.RegistrationRequest(reg.toWire(privateKey), serviceHub.networkService.myAddress, sessionID) return sendAndReceive( - NetworkMapService.REGISTER_PROTOCOL_TOPIC, server.address, 0, sessionID, req) + NetworkMapService.REGISTER_PROTOCOL_TOPIC, server.identity, 0, sessionID, req) .validate { it } } } @@ -110,19 +110,20 @@ class InMemoryNetworkMapServiceTest { val req = NetworkMapService.SubscribeRequest(subscribe, serviceHub.networkService.myAddress, sessionID) return sendAndReceive( - NetworkMapService.SUBSCRIPTION_PROTOCOL_TOPIC, server.address, 0, sessionID, req) + NetworkMapService.SUBSCRIPTION_PROTOCOL_TOPIC, server.identity, 0, sessionID, req) .validate { it } } } @Test - fun successWithNetwork() { + fun `success with network`() { val (mapServiceNode, registerNode) = network.createTwoNodes() // Confirm there's a network map service on node 0 assertNotNull(mapServiceNode.inNodeNetworkMapService) // Confirm all nodes have registered themselves + network.runNetwork() var fetchPsm = registerNode.smm.add(NetworkMapService.FETCH_PROTOCOL_TOPIC, TestFetchPSM(mapServiceNode.info, false)) network.runNetwork() assertEquals(2, fetchPsm.get()?.count()) @@ -143,11 +144,12 @@ class InMemoryNetworkMapServiceTest { } @Test - fun subscribeWithNetwork() { + fun `subscribe with network`() { val (mapServiceNode, registerNode) = network.createTwoNodes() val service = (mapServiceNode.inNodeNetworkMapService as InMemoryNetworkMapService) // Test subscribing to updates + network.runNetwork() val subscribePsm = registerNode.smm.add(NetworkMapService.SUBSCRIPTION_PROTOCOL_TOPIC, TestSubscribePSM(mapServiceNode.info, true)) network.runNetwork() diff --git a/node/src/test/kotlin/com/r3corda/node/services/MockServices.kt b/node/src/test/kotlin/com/r3corda/node/services/MockServices.kt index 72bd57df44..242d41dbf2 100644 --- a/node/src/test/kotlin/com/r3corda/node/services/MockServices.kt +++ b/node/src/test/kotlin/com/r3corda/node/services/MockServices.kt @@ -1,8 +1,8 @@ package com.r3corda.node.services import com.codahale.metrics.MetricRegistry -import com.r3corda.core.contracts.SignedTransaction import com.google.common.util.concurrent.ListenableFuture +import com.r3corda.core.contracts.SignedTransaction import com.r3corda.core.messaging.MessagingService import com.r3corda.core.node.services.* import com.r3corda.core.node.services.testing.MockStorageService @@ -68,7 +68,7 @@ open class MockServices( if (net != null && storage != null) { // Creating this class is sufficient, we don't have to store it anywhere, because it registers a listener // on the networking service, so that will keep it from being collected. - DataVendingService(net, storage) + DataVendingService(net, storage, networkMapCache) } } } diff --git a/node/src/test/kotlin/com/r3corda/node/services/NodeInterestRatesTest.kt b/node/src/test/kotlin/com/r3corda/node/services/NodeInterestRatesTest.kt index 983db252d8..2cb5ba4f38 100644 --- a/node/src/test/kotlin/com/r3corda/node/services/NodeInterestRatesTest.kt +++ b/node/src/test/kotlin/com/r3corda/node/services/NodeInterestRatesTest.kt @@ -8,9 +8,9 @@ import com.r3corda.contracts.testing.`with notary` import com.r3corda.core.bd import com.r3corda.core.contracts.DOLLARS import com.r3corda.core.contracts.Fix +import com.r3corda.core.contracts.TransactionType import com.r3corda.core.crypto.Party import com.r3corda.core.crypto.generateKeyPair -import com.r3corda.core.contracts.TransactionType import com.r3corda.core.testing.ALICE_PUBKEY import com.r3corda.core.testing.DUMMY_NOTARY import com.r3corda.core.testing.MEGA_CORP @@ -109,8 +109,9 @@ class NodeInterestRatesTest { val tx = TransactionType.General.Builder() val fixOf = NodeInterestRates.parseFixOf("LIBOR 2016-03-16 1M") - val protocol = RatesFixProtocol(tx, n2.info, fixOf, "0.675".bd, "0.1".bd, Duration.ofNanos(1)) + val protocol = RatesFixProtocol(tx, n2.info.identity, fixOf, "0.675".bd, "0.1".bd, Duration.ofNanos(1)) BriefLogFormatter.initVerbose("rates") + net.runNetwork() val future = n1.smm.add("rates", protocol) net.runNetwork() @@ -123,4 +124,4 @@ class NodeInterestRatesTest { } private fun makeTX() = TransactionType.General.Builder().withItems(1000.DOLLARS.CASH `issued by` DUMMY_CASH_ISSUER `owned by` ALICE_PUBKEY `with notary` DUMMY_NOTARY) -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/r3corda/demos/RateFixDemo.kt b/src/main/kotlin/com/r3corda/demos/RateFixDemo.kt index 007cc51e36..e795510e85 100644 --- a/src/main/kotlin/com/r3corda/demos/RateFixDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/RateFixDemo.kt @@ -65,7 +65,7 @@ fun main(args: Array) { val rateTolerance = BigDecimal(options.valueOf(rateToleranceArg)) // Bring up node. - var advertisedServices: Set = emptySet() + val advertisedServices: Set = emptySet() val myNetAddr = ArtemisMessagingService.toHostAndPort(options.valueOf(networkAddressArg)) val config = object : NodeConfiguration { override val myLegalName: String = "Rate fix demo node" @@ -84,7 +84,7 @@ fun main(args: Array) { // Make a garbage transaction that includes a rate fix. val tx = TransactionType.General.Builder() tx.addOutputState(TransactionState(Cash.State(1500.DOLLARS `issued by` node.storage.myLegalIdentity.ref(1), node.keyManagement.freshKey().public), notary.identity)) - val protocol = RatesFixProtocol(tx, oracleNode, fixOf, expectedRate, rateTolerance, 24.hours) + val protocol = RatesFixProtocol(tx, oracleNode.identity, fixOf, expectedRate, rateTolerance, 24.hours) node.smm.add("demo.ratefix", protocol).get() node.stop() diff --git a/src/main/kotlin/com/r3corda/demos/TraderDemo.kt b/src/main/kotlin/com/r3corda/demos/TraderDemo.kt index 8178309c4b..c15bfd82e7 100644 --- a/src/main/kotlin/com/r3corda/demos/TraderDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/TraderDemo.kt @@ -11,7 +11,6 @@ import com.r3corda.core.crypto.SecureHash import com.r3corda.core.crypto.generateKeyPair import com.r3corda.core.days import com.r3corda.core.logElapsedTime -import com.r3corda.core.messaging.SingleMessageRecipient import com.r3corda.core.node.NodeInfo import com.r3corda.core.node.services.ServiceType import com.r3corda.core.protocols.ProtocolLogic @@ -163,17 +162,13 @@ fun runTraderDemo(args: Array): Int { if (role == Role.BUYER) { runBuyer(node, amount) } else { - val recipient = ArtemisMessagingService.makeRecipient(theirNetAddr) - runSeller(myNetAddr, node, recipient, amount) + runSeller(node, amount, cashIssuer) } return 0 } -private fun runSeller(myNetAddr: HostAndPort, - node: Node, - recipient: SingleMessageRecipient, - amount: Amount>) { +private fun runSeller(node: Node, amount: Amount>, otherSide: Party) { // The seller will sell some commercial paper to the buyer, who will pay with (self issued) cash. // // The CP sale transaction comes with a prospectus PDF, which will tag along for the ride in an @@ -192,7 +187,7 @@ private fun runSeller(myNetAddr: HostAndPort, it.second.get() } } else { - val seller = TraderDemoProtocolSeller(myNetAddr, recipient, amount) + val seller = TraderDemoProtocolSeller(otherSide, amount) node.smm.add("demo.seller", seller).get() } @@ -208,8 +203,7 @@ private fun runBuyer(node: Node, amount: Amount>) { } val future = if (node.isPreviousCheckpointsPresent) { - val (@Suppress("UNUSED_VARIABLE") buyer, future) = node.smm.findStateMachines(TraderDemoProtocolBuyer::class.java).single() - future + node.smm.findStateMachines(TraderDemoProtocolBuyer::class.java).single().second } else { // We use a simple scenario-specific wrapper protocol to make things happen. val buyer = TraderDemoProtocolBuyer(attachmentsPath, node.info.identity, amount) @@ -249,16 +243,19 @@ private class TraderDemoProtocolBuyer(private val attachmentsPath: Path, // As the seller initiates the two-party trade protocol, here, we will be the buyer. try { progressTracker.currentStep = WAITING_FOR_SELLER_TO_CONNECT - val origin = receive(DEMO_TOPIC, 0).validate { it.withDefaultPort(Node.DEFAULT_PORT) } - val recipient = ArtemisMessagingService.makeRecipient(origin as HostAndPort) + val newPartnerParty = receive(DEMO_TOPIC, 0).validate { + val ourVersionOfParty = serviceHub.networkMapCache.getNodeByLegalName(it.name)!!.identity + require(ourVersionOfParty == it) + it + } // The session ID disambiguates the test trade. val sessionID = random63BitValue() progressTracker.currentStep = STARTING_BUY - send(DEMO_TOPIC, recipient, 0, sessionID) + send(DEMO_TOPIC, newPartnerParty, 0, sessionID) val notary = serviceHub.networkMapCache.notaryNodes[0] - val buyer = TwoPartyTradeProtocol.Buyer(recipient, notary.identity, amount, + val buyer = TwoPartyTradeProtocol.Buyer(newPartnerParty, notary.identity, amount, CommercialPaper.State::class.java, sessionID) // This invokes the trading protocol and out pops our finished transaction. @@ -301,10 +298,9 @@ ${Emoji.renderIfSupported(cpIssuance)}""") } } -private class TraderDemoProtocolSeller(val myAddress: HostAndPort, - val otherSide: SingleMessageRecipient, - val amount: Amount>, - override val progressTracker: ProgressTracker = TraderDemoProtocolSeller.tracker()) : ProtocolLogic() { +private class TraderDemoProtocolSeller(val otherSide: Party, + val amount: Amount>, + override val progressTracker: ProgressTracker = TraderDemoProtocolSeller.tracker()) : ProtocolLogic() { companion object { val PROSPECTUS_HASH = SecureHash.parse("decd098666b9657314870e192ced0c3519c2c9d395507a238338f8d003929de9") @@ -326,7 +322,7 @@ private class TraderDemoProtocolSeller(val myAddress: HostAndPort, override fun call() { progressTracker.currentStep = ANNOUNCING - val sessionID = sendAndReceive(DEMO_TOPIC, otherSide, 0, 0, myAddress).validate { it } + val sessionID = sendAndReceive(DEMO_TOPIC, otherSide, 0, 0, serviceHub.storageService.myLegalIdentity).validate { it } progressTracker.currentStep = SELF_ISSUING diff --git a/src/main/kotlin/com/r3corda/demos/protocols/AutoOfferProtocol.kt b/src/main/kotlin/com/r3corda/demos/protocols/AutoOfferProtocol.kt index 2be25b79b4..a2f5a72fa3 100644 --- a/src/main/kotlin/com/r3corda/demos/protocols/AutoOfferProtocol.kt +++ b/src/main/kotlin/com/r3corda/demos/protocols/AutoOfferProtocol.kt @@ -6,7 +6,6 @@ import com.google.common.util.concurrent.Futures import com.r3corda.core.contracts.DealState import com.r3corda.core.contracts.SignedTransaction import com.r3corda.core.crypto.Party -import com.r3corda.core.messaging.SingleMessageRecipient import com.r3corda.core.protocols.ProtocolLogic import com.r3corda.core.random63BitValue import com.r3corda.core.serialization.deserialize @@ -24,7 +23,7 @@ import com.r3corda.protocols.TwoPartyDealProtocol object AutoOfferProtocol { val TOPIC = "autooffer.topic" - data class AutoOfferMessage(val otherSide: SingleMessageRecipient, + data class AutoOfferMessage(val otherSide: Party, val notary: Party, val otherSessionID: Long, val dealBeingOffered: DealState) @@ -67,7 +66,7 @@ object AutoOfferProtocol { } - class Requester(val dealToBeOffered: DealState) : ProtocolLogic() { + class Requester(val dealToBeOffered: DealState) : ProtocolLogic() { companion object { object RECEIVED : ProgressTracker.Step("Received API call") @@ -98,9 +97,9 @@ object AutoOfferProtocol { val otherParty = notUs(*dealToBeOffered.parties).single() val otherNode = (serviceHub.networkMapCache.getNodeByLegalName(otherParty.name)) requireNotNull(otherNode) { "Cannot identify other party " + otherParty.name + ", know about: " + serviceHub.networkMapCache.partyNodes.map { it.identity } } - val otherSide = otherNode!!.address + val otherSide = otherNode!!.identity progressTracker.currentStep = ANNOUNCING - send(TOPIC, otherSide, 0, AutoOfferMessage(serviceHub.networkService.myAddress, notary, ourSessionID, dealToBeOffered)) + send(TOPIC, otherSide, 0, AutoOfferMessage(serviceHub.storageService.myLegalIdentity, notary, ourSessionID, dealToBeOffered)) progressTracker.currentStep = DEALING val stx = subProtocol(TwoPartyDealProtocol.Acceptor(otherSide, notary, dealToBeOffered, ourSessionID, progressTracker.getChildProgressTracker(DEALING)!!)) return stx diff --git a/src/main/kotlin/com/r3corda/demos/protocols/ExitServerProtocol.kt b/src/main/kotlin/com/r3corda/demos/protocols/ExitServerProtocol.kt index abf20e3809..a3b9d6a01c 100644 --- a/src/main/kotlin/com/r3corda/demos/protocols/ExitServerProtocol.kt +++ b/src/main/kotlin/com/r3corda/demos/protocols/ExitServerProtocol.kt @@ -22,7 +22,7 @@ object ExitServerProtocol { object Handler { fun register(node: Node) { - node.net.addMessageHandler("${TOPIC}.0") { msg, registration -> + node.net.addMessageHandler("$TOPIC.0") { msg, registration -> // Just to validate we got the message if (enabled) { val message = msg.data.deserialize() @@ -62,7 +62,7 @@ object ExitServerProtocol { } else { // TODO: messaging ourselves seems to trigger a bug for the time being and we continuously receive messages if (recipient.identity != serviceHub.storageService.myLegalIdentity) { - send(TOPIC, recipient.address, 0, message) + send(TOPIC, recipient.identity, 0, message) } } } diff --git a/src/main/kotlin/com/r3corda/demos/protocols/UpdateBusinessDayProtocol.kt b/src/main/kotlin/com/r3corda/demos/protocols/UpdateBusinessDayProtocol.kt index c702be19fc..00ede632fa 100644 --- a/src/main/kotlin/com/r3corda/demos/protocols/UpdateBusinessDayProtocol.kt +++ b/src/main/kotlin/com/r3corda/demos/protocols/UpdateBusinessDayProtocol.kt @@ -52,7 +52,7 @@ object UpdateBusinessDayProtocol { if (recipient.address is MockNetworkMapCache.MockAddress) { // Ignore } else { - send(TOPIC, recipient.address, 0, message) + send(TOPIC, recipient.identity, 0, message) } } } From 6dad7efa226de1542d680146cc7920e0e6317825 Mon Sep 17 00:00:00 2001 From: Ross Nicoll Date: Thu, 30 Jun 2016 10:28:56 +0100 Subject: [PATCH 069/114] Replace references to cash, with (fungible) asset --- .../com/r3corda/contracts/Obligation.kt | 103 +++++++++--------- .../com/r3corda/contracts/ObligationTests.kt | 2 +- 2 files changed, 52 insertions(+), 53 deletions(-) diff --git a/contracts/src/main/kotlin/com/r3corda/contracts/Obligation.kt b/contracts/src/main/kotlin/com/r3corda/contracts/Obligation.kt index e5c25dcb14..6ce0119de3 100644 --- a/contracts/src/main/kotlin/com/r3corda/contracts/Obligation.kt +++ b/contracts/src/main/kotlin/com/r3corda/contracts/Obligation.kt @@ -1,7 +1,8 @@ package com.r3corda.contracts import com.google.common.annotations.VisibleForTesting -import com.r3corda.contracts.cash.* +import com.r3corda.contracts.cash.FungibleAssetState +import com.r3corda.contracts.cash.sumFungibleOrNull import com.r3corda.core.contracts.* import com.r3corda.core.crypto.Party import com.r3corda.core.crypto.SecureHash @@ -18,12 +19,10 @@ import java.util.* val OBLIGATION_PROGRAM_ID = Obligation() /** - * A cash settlement contract commits the obligor to delivering a specified amount of cash (represented as the [Cash] - * contract) at a specified future point in time. Similarly to cash, settlement transactions may split and merge - * contracts across multiple input and output states. - * - * The goal of this design is to handle money owed, and these contracts are expected to be netted/merged, with - * settlement only for any remainder amount. + * An obligation contract commits the obligor to delivering a specified amount of a fungible asset (for example the + * [Cash] contract) at a specified future point in time. Settlement transactions may split and merge contracts across + * multiple input and output states. The goal of this design is to handle amounts owed, and these contracts are expected + * to be netted/merged, with settlement only for any remainder amount. * * @param P the product the obligation is for payment of. */ @@ -92,9 +91,9 @@ class Obligation

: Contract { * @param P the product the obligation is for payment of. */ data class StateTemplate

( - /** The hash of the cash contract we're willing to accept in payment for this debt. */ + /** The hash of the asset contract we're willing to accept in payment for this debt. */ val acceptableContracts: NonEmptySet, - /** The parties whose cash we are willing to accept in payment for this debt. */ + /** The parties whose assets we are willing to accept in payment for this debt. */ val acceptableIssuedProducts: NonEmptySet>, /** When the contract must be settled by. */ @@ -119,7 +118,7 @@ class Obligation

: Contract { /** * A state representing the obligation of one party (obligor) to deliver a specified number of - * units of an underlying asset (described as issuanceDef.acceptableCashIssuance) to the beneficiary + * units of an underlying asset (described as issuanceDef.acceptableIssuedProducts) to the beneficiary * no later than the specified time. * * @param P the product the obligation is for payment of. @@ -197,7 +196,7 @@ class Obligation

: Contract { // Just for grouping interface Commands : CommandData { /** - * Net two or more cash settlement states together in a close-out netting style. Limited to bilateral netting + * Net two or more obligation states together in a close-out netting style. Limited to bilateral netting * as only the beneficiary (not the obligor) needs to sign. */ data class Net(val type: NetType) : Commands @@ -222,7 +221,7 @@ class Obligation

: Contract { /** * A command stating that the obligor is settling some or all of the amount owed by transferring a suitable * state object to the beneficiary. If this reduces the balance to zero, the state object is destroyed. - * @see [Cash.Commands.Move] + * @see [MoveCommand] */ data class Settle

(override val aggregateState: IssuanceDefinition

, val amount: Amount

) : Commands, IssuanceCommands

@@ -288,9 +287,9 @@ class Obligation

: Contract { outputs: List>, obligor: Party, key: IssuanceDefinition

) { - // We've already pre-grouped by currency amongst other fields, and verified above that every state specifies + // We've already pre-grouped by product amongst other fields, and verified above that every state specifies // at least one acceptable issuance definition, so we can just use the first issuance definition to - // determine currency + // determine product val issued = key.template.acceptableIssuedProducts.first() // Issue, default, net and settle commands are all single commands (there's only ever one of them, and @@ -482,13 +481,13 @@ class Obligation

: Contract { val inputAmount: Amount

= inputs.sumObligationsOrNull

() ?: throw IllegalArgumentException("there is at least one obligation input for this group") val outputAmount: Amount

= outputs.sumObligationsOrZero(issued.product) - // Sum up all cash state objects that are moving and fulfil our requirements + // Sum up all asset state objects that are moving and fulfil our requirements - // The cash contract verification handles ensuring there's inputs enough to cover the output states, we only - // care about counting how much cash is output in this transaction. We then calculate the difference in + // The fungible asset contract verification handles ensuring there's inputs enough to cover the output states, + // we only care about counting how much is output in this transaction. We then calculate the difference in // settlement amounts between the transaction inputs and outputs, and the two must match. No elimination is - // done of amounts paid in by each beneficiary, as it's presumed the beneficiarys have enough sense to do that themselves. - // Therefore if someone actually signed the following transaction: + // done of amounts paid in by each beneficiary, as it's presumed the beneficiaries have enough sense to do that + // themselves. Therefore if someone actually signed the following transaction (using cash just for an example): // // Inputs: // £1m cash owned by B @@ -500,23 +499,23 @@ class Obligation

: Contract { // Move (signed by B) // // That would pass this check. Ensuring they do not is best addressed in the transaction generation stage. - val cashStates = tx.outputs.filterIsInstance>() - val acceptableCashStates = cashStates - // TODO: This filter is nonsense, because it just checks there is a cash contract loaded, we need to - // verify the cash contract is the cash contract we expect. + val assetStates = tx.outputs.filterIsInstance>() + val acceptableAssetStates = assetStates + // TODO: This filter is nonsense, because it just checks there is an asset contract loaded, we need to + // verify the asset contract is the asset contract we expect. // Something like: - // attachments.mustHaveOneOf(key.acceptableCashContract) + // attachments.mustHaveOneOf(key.acceptableAssetContract) .filter { it.contract.legalContractReference in template.acceptableContracts } // Restrict the states to those of the correct issuance definition (this normally - // covers currency and obligor, but is opaque to us) + // covers issued product and obligor, but is opaque to us) .filter { it.issuanceDef in template.acceptableIssuedProducts } // Catch that there's nothing useful here, so we can dump out a useful error requireThat { - "there are cash state outputs" by (cashStates.size > 0) - "there are defined acceptable cash states" by (acceptableCashStates.size > 0) + "there are fungible asset state outputs" by (assetStates.size > 0) + "there are defined acceptable fungible asset states" by (acceptableAssetStates.size > 0) } - val amountReceivedByOwner = acceptableCashStates.groupBy { it.owner } + val amountReceivedByOwner = acceptableAssetStates.groupBy { it.owner } // Note we really do want to search all commands, because we want move commands of other contracts, not just // this one. val moveCommands = tx.commands.select() @@ -524,7 +523,7 @@ class Obligation

: Contract { val requiredSigners = inputs.map { it.obligor.owningKey }.toSet() for ((beneficiary, obligations) in inputs.groupBy { it.beneficiary }) { - val settled = amountReceivedByOwner[beneficiary]?.sumCashOrNull() + val settled = amountReceivedByOwner[beneficiary]?.sumFungibleOrNull

() if (settled != null) { val debt = obligations.sumObligationsOrZero(issued) require(settled.quantity <= debt.quantity) { "Payment of $settled must not exceed debt $debt" } @@ -655,20 +654,22 @@ class Obligation

: Contract { /** * @param statesAndRefs a list of state objects, which MUST all have the same aggregate state. This is done as * only a single settlement command can be present in a transaction, to avoid potential problems with allocating - * cash to different obligation issuances. - * @param cashStatesAndRefs a list of cash state objects, which MUST all be in the same currency. It is strongly - * encouraged that these all have the same beneficiary. + * assets to different obligation issuances. + * @param assetStatesAndRefs a list of fungible asset state objects, which MUST all be of the same issued product. + * It is strongly encouraged that these all have the same beneficiary. + * @param moveCommand the command used to move the asset state objects to their new owner. */ fun generateSettle(tx: TransactionBuilder, statesAndRefs: Iterable>>, - cashStatesAndRefs: Iterable>>, + assetStatesAndRefs: Iterable>>, + moveCommand: MoveCommand, notary: Party) { val states = statesAndRefs.map { it.state } val obligationIssuer = states.first().data.obligor val obligationOwner = states.first().data.beneficiary requireThat { - "all cash states use the same notary" by (cashStatesAndRefs.all { it.state.notary == notary }) + "all fungible asset states use the same notary" by (assetStatesAndRefs.all { it.state.notary == notary }) "all obligation states are in the normal state" by (statesAndRefs.all { it.state.data.lifecycle == Lifecycle.NORMAL }) "all obligation states use the same notary" by (statesAndRefs.all { it.state.notary == notary }) "all obligation states have the same obligor" by (statesAndRefs.all { it.state.data.obligor == obligationIssuer }) @@ -676,32 +677,32 @@ class Obligation

: Contract { } // TODO: A much better (but more complex) solution would be to have two iterators, one for obligations, - // one for cash, and step through each in a semi-synced manner. For now however we just bundle all the states + // one for the assets, and step through each in a semi-synced manner. For now however we just bundle all the states // on each side together val issuanceDef = getIssuanceDefinitionOrThrow(statesAndRefs.map { it.state.data }) val template = issuanceDef.template val obligationTotal: Amount

= states.map { it.data }.sumObligations

() var obligationRemaining: Amount

= obligationTotal - val cashSigners = HashSet() + val assetSigners = HashSet() statesAndRefs.forEach { tx.addInputState(it) } - // Move the cash to the new beneficiary - cashStatesAndRefs.forEach { + // Move the assets to the new beneficiary + assetStatesAndRefs.forEach { if (obligationRemaining.quantity > 0L) { - val cashState = it.state + val assetState = it.state tx.addInputState(it) - if (obligationRemaining >= cashState.data.productAmount) { - tx.addOutputState(cashState.data.move(cashState.data.productAmount, obligationOwner), notary) - obligationRemaining -= cashState.data.productAmount + if (obligationRemaining >= assetState.data.productAmount) { + tx.addOutputState(assetState.data.move(assetState.data.productAmount, obligationOwner), notary) + obligationRemaining -= assetState.data.productAmount } else { // Split the state in two, sending the change back to the previous beneficiary - tx.addOutputState(cashState.data.move(obligationRemaining, obligationOwner), notary) - tx.addOutputState(cashState.data.move(cashState.data.productAmount - obligationRemaining, cashState.data.owner), notary) + tx.addOutputState(assetState.data.move(obligationRemaining, obligationOwner), notary) + tx.addOutputState(assetState.data.move(assetState.data.productAmount - obligationRemaining, assetState.data.owner), notary) obligationRemaining -= Amount(0L, obligationRemaining.token) } - cashSigners.add(cashState.data.owner) + assetSigners.add(assetState.data.owner) } } @@ -712,8 +713,8 @@ class Obligation

: Contract { // Destroy all of the states } - // Add the cash move command and obligation settle - tx.addCommand(Cash.Commands.Move(), cashSigners.toList()) + // Add the asset move command and obligation settle + tx.addCommand(moveCommand, assetSigners.toList()) tx.addCommand(Commands.Settle(issuanceDef, obligationTotal - obligationRemaining), obligationOwner) } @@ -801,17 +802,15 @@ fun

sumAmountsDue(balances: Map, Amount

>): Map return sum } -/** Sums the cash states in the list, throwing an exception if there are none. - * All cash states in the list are presumed to be nettable. - */ +/** Sums the obligation states in the list, throwing an exception if there are none. All state objects in the list are presumed to be nettable. */ fun

Iterable.sumObligations(): Amount

= filterIsInstance>().map { it.amount }.sumOrThrow() -/** Sums the cash settlement states in the list, returning null if there are none. */ +/** Sums the obligation states in the list, returning null if there are none. */ fun

Iterable.sumObligationsOrNull(): Amount

? = filterIsInstance>().filter { it.lifecycle == Obligation.Lifecycle.NORMAL }.map { it.amount }.sumOrNull() -/** Sums the cash settlement states in the list, returning zero of the given currency if there are none. */ +/** Sums the obligation states in the list, returning zero of the given product if there are none. */ fun

Iterable.sumObligationsOrZero(product: P): Amount

= filterIsInstance>().filter { it.lifecycle == Obligation.Lifecycle.NORMAL }.map { it.amount }.sumOrZero(product) diff --git a/contracts/src/test/kotlin/com/r3corda/contracts/ObligationTests.kt b/contracts/src/test/kotlin/com/r3corda/contracts/ObligationTests.kt index c9ba546142..f7144334bd 100644 --- a/contracts/src/test/kotlin/com/r3corda/contracts/ObligationTests.kt +++ b/contracts/src/test/kotlin/com/r3corda/contracts/ObligationTests.kt @@ -317,7 +317,7 @@ class ObligationTests { // Now generate a transaction settling the obligation val settleTx = TransactionType.General.Builder(DUMMY_NOTARY).apply { - Obligation().generateSettle(this, listOf(obligationTx.outRef(0)), listOf(cashTx.outRef(0)), DUMMY_NOTARY) + Obligation().generateSettle(this, listOf(obligationTx.outRef(0)), listOf(cashTx.outRef(0)), Cash.Commands.Move(), DUMMY_NOTARY) signWith(DUMMY_NOTARY_KEY) signWith(MINI_CORP_KEY) }.toSignedTransaction().tx From 212182466222093a77578147411c4c5b21b76c5a Mon Sep 17 00:00:00 2001 From: Ross Nicoll Date: Thu, 30 Jun 2016 10:37:25 +0100 Subject: [PATCH 070/114] Rename com.r3cord.contracts.cash package to ...asset --- .../contracts/JavaCommercialPaper.java | 6 +-- .../com/r3corda/contracts/CommercialPaper.kt | 6 +-- .../r3corda/contracts/{cash => asset}/Cash.kt | 2 +- .../{cash => asset}/FungibleAsset.kt | 2 +- .../{cash => asset}/FungibleAssetState.kt | 2 +- .../contracts/{ => asset}/Obligation.kt | 12 +++--- .../r3corda/contracts/testing/TestUtils.kt | 5 ++- .../r3corda/contracts/testing/WalletFiller.kt | 2 +- .../protocols/TwoPartyTradeProtocol.kt | 4 +- .../{cash => asset}/CashTestsJava.java | 4 +- .../r3corda/contracts/CommercialPaperTests.kt | 2 +- .../contracts/{cash => asset}/CashTests.kt | 6 +-- .../contracts/{ => asset}/ObligationTests.kt | 38 +++++++++---------- docs/build/html/api/alltypes/index.html | 10 ++--- .../-asset-issuance-definition/deposit.html | 4 +- .../-asset-issuance-definition/index.html | 2 +- .../-asset-issuance-definition/token.html | 4 +- .../-c-a-s-h_-p-r-o-g-r-a-m_-i-d.html | 4 +- .../-cash/-commands/-exit/-init-.html | 4 +- .../-cash/-commands/-exit/amount.html | 4 +- .../-cash/-commands/-exit/index.html | 4 +- .../-cash/-commands/-issue/-init-.html | 4 +- .../-cash/-commands/-issue/index.html | 4 +- .../-cash/-commands/-issue/nonce.html | 4 +- .../-cash/-issuance-definition/-init-.html | 4 +- .../-cash/-issuance-definition/deposit.html | 4 +- .../-cash/-issuance-definition/index.html | 4 +- .../-cash/-issuance-definition/token.html | 4 +- .../-cash/-state/-init-.html | 4 +- .../-cash/-state/amount.html | 4 +- .../-cash/-state/contract.html | 4 +- .../-cash/-state/deposit.html | 4 +- .../-cash/-state/index.html | 10 ++--- .../-cash/-state/issuance-def.html | 4 +- .../-cash/-state/notary.html | 4 +- .../-cash/-state/owner.html | 4 +- .../-cash/-state/to-string.html | 4 +- .../-cash/-state/with-new-owner.html | 6 +-- .../-cash/generate-issue.html | 10 ++--- .../-cash/generate-spend.html | 6 +-- .../-cash/index.html | 10 ++--- .../-cash/legal-contract-reference.html | 4 +- .../-fungible-asset-state/amount.html | 4 +- .../-fungible-asset-state/deposit.html | 4 +- .../-fungible-asset-state/issuance-def.html | 4 +- .../-commands/-exit/amount.html | 4 +- .../-commands/-exit/index.html | 2 +- .../-commands/-issue/index.html | 2 +- .../-commands/-issue/nonce.html | 4 +- .../-fungible-asset/-commands/-move.html | 2 +- .../-fungible-asset/-init-.html | 2 +- .../-fungible-asset/-state/amount.html | 4 +- .../-fungible-asset/-state/deposit.html | 4 +- .../-fungible-asset/-state/index.html | 2 +- .../-fungible-asset/-state/notary.html | 4 +- .../-fungible-asset/-state/owner.html | 4 +- .../-fungible-asset/index.html | 4 +- .../-fungible-asset/verify.html | 6 +-- .../-init-.html | 4 +- .../amount-missing.html | 4 +- .../index.html | 4 +- .../api/com.r3corda.contracts.cash/index.html | 6 +-- .../kotlin.collections.-iterable/index.html | 12 +++--- .../sum-cash-by.html | 6 +-- .../sum-cash-or-null.html | 4 +- .../sum-cash-or-zero.html | 6 +-- .../sum-cash.html | 4 +- .../sum-fungible-by.html | 6 +-- .../sum-fungible-or-null.html | 4 +- .../sum-fungible-or-zero.html | 6 +-- .../sum-fungible.html | 4 +- .../com.r3corda.contracts.testing/index.html | 4 +- .../issued by.html | 4 +- .../owned by.html | 4 +- .../-commercial-paper/generate-redeem.html | 4 +- .../-commercial-paper/index.html | 2 +- docs/build/html/api/index.html | 2 +- .../wallet/CashBalanceAsMetricsObserver.kt | 2 +- .../messaging/TwoPartyTradeProtocolTests.kt | 2 +- .../node/services/NodeInterestRatesTest.kt | 2 +- .../node/services/WalletWithCashTest.kt | 4 +- .../kotlin/com/r3corda/demos/RateFixDemo.kt | 2 +- .../kotlin/com/r3corda/demos/TraderDemo.kt | 2 +- 83 files changed, 197 insertions(+), 196 deletions(-) rename contracts/src/main/kotlin/com/r3corda/contracts/{cash => asset}/Cash.kt (99%) rename contracts/src/main/kotlin/com/r3corda/contracts/{cash => asset}/FungibleAsset.kt (99%) rename contracts/src/main/kotlin/com/r3corda/contracts/{cash => asset}/FungibleAssetState.kt (91%) rename contracts/src/main/kotlin/com/r3corda/contracts/{ => asset}/Obligation.kt (99%) rename contracts/src/test/java/com/r3corda/contracts/{cash => asset}/CashTestsJava.java (95%) rename contracts/src/test/kotlin/com/r3corda/contracts/{cash => asset}/CashTests.kt (99%) rename contracts/src/test/kotlin/com/r3corda/contracts/{ => asset}/ObligationTests.kt (96%) diff --git a/contracts/src/main/java/com/r3corda/contracts/JavaCommercialPaper.java b/contracts/src/main/java/com/r3corda/contracts/JavaCommercialPaper.java index a1ba26e559..5b37c86887 100644 --- a/contracts/src/main/java/com/r3corda/contracts/JavaCommercialPaper.java +++ b/contracts/src/main/java/com/r3corda/contracts/JavaCommercialPaper.java @@ -1,9 +1,9 @@ package com.r3corda.contracts; import com.google.common.collect.ImmutableList; -import com.r3corda.contracts.cash.Cash; -import com.r3corda.contracts.cash.CashKt; -import com.r3corda.contracts.cash.InsufficientBalanceException; +import com.r3corda.contracts.asset.Cash; +import com.r3corda.contracts.asset.CashKt; +import com.r3corda.contracts.asset.InsufficientBalanceException; import com.r3corda.core.contracts.*; import com.r3corda.core.contracts.TransactionForContract.InOutGroup; import com.r3corda.core.crypto.NullPublicKey; diff --git a/contracts/src/main/kotlin/com/r3corda/contracts/CommercialPaper.kt b/contracts/src/main/kotlin/com/r3corda/contracts/CommercialPaper.kt index eabb650386..27d41a59df 100644 --- a/contracts/src/main/kotlin/com/r3corda/contracts/CommercialPaper.kt +++ b/contracts/src/main/kotlin/com/r3corda/contracts/CommercialPaper.kt @@ -1,8 +1,8 @@ package com.r3corda.contracts -import com.r3corda.contracts.cash.Cash -import com.r3corda.contracts.cash.InsufficientBalanceException -import com.r3corda.contracts.cash.sumCashBy +import com.r3corda.contracts.asset.Cash +import com.r3corda.contracts.asset.InsufficientBalanceException +import com.r3corda.contracts.asset.sumCashBy import com.r3corda.core.contracts.* import com.r3corda.core.crypto.NullPublicKey import com.r3corda.core.crypto.Party diff --git a/contracts/src/main/kotlin/com/r3corda/contracts/cash/Cash.kt b/contracts/src/main/kotlin/com/r3corda/contracts/asset/Cash.kt similarity index 99% rename from contracts/src/main/kotlin/com/r3corda/contracts/cash/Cash.kt rename to contracts/src/main/kotlin/com/r3corda/contracts/asset/Cash.kt index 606f430014..446e90f8c2 100644 --- a/contracts/src/main/kotlin/com/r3corda/contracts/cash/Cash.kt +++ b/contracts/src/main/kotlin/com/r3corda/contracts/asset/Cash.kt @@ -1,4 +1,4 @@ -package com.r3corda.contracts.cash +package com.r3corda.contracts.asset import com.r3corda.core.contracts.* import com.r3corda.core.crypto.Party diff --git a/contracts/src/main/kotlin/com/r3corda/contracts/cash/FungibleAsset.kt b/contracts/src/main/kotlin/com/r3corda/contracts/asset/FungibleAsset.kt similarity index 99% rename from contracts/src/main/kotlin/com/r3corda/contracts/cash/FungibleAsset.kt rename to contracts/src/main/kotlin/com/r3corda/contracts/asset/FungibleAsset.kt index 869ddea6d5..59ae41fdbc 100644 --- a/contracts/src/main/kotlin/com/r3corda/contracts/cash/FungibleAsset.kt +++ b/contracts/src/main/kotlin/com/r3corda/contracts/asset/FungibleAsset.kt @@ -1,4 +1,4 @@ -package com.r3corda.contracts.cash +package com.r3corda.contracts.asset import com.r3corda.core.contracts.* import com.r3corda.core.crypto.Party diff --git a/contracts/src/main/kotlin/com/r3corda/contracts/cash/FungibleAssetState.kt b/contracts/src/main/kotlin/com/r3corda/contracts/asset/FungibleAssetState.kt similarity index 91% rename from contracts/src/main/kotlin/com/r3corda/contracts/cash/FungibleAssetState.kt rename to contracts/src/main/kotlin/com/r3corda/contracts/asset/FungibleAssetState.kt index 28a85c173e..436919b690 100644 --- a/contracts/src/main/kotlin/com/r3corda/contracts/cash/FungibleAssetState.kt +++ b/contracts/src/main/kotlin/com/r3corda/contracts/asset/FungibleAssetState.kt @@ -1,4 +1,4 @@ -package com.r3corda.contracts.cash +package com.r3corda.contracts.asset import com.r3corda.core.contracts.Amount import com.r3corda.core.contracts.Issued diff --git a/contracts/src/main/kotlin/com/r3corda/contracts/Obligation.kt b/contracts/src/main/kotlin/com/r3corda/contracts/asset/Obligation.kt similarity index 99% rename from contracts/src/main/kotlin/com/r3corda/contracts/Obligation.kt rename to contracts/src/main/kotlin/com/r3corda/contracts/asset/Obligation.kt index 6ce0119de3..1aa3538461 100644 --- a/contracts/src/main/kotlin/com/r3corda/contracts/Obligation.kt +++ b/contracts/src/main/kotlin/com/r3corda/contracts/asset/Obligation.kt @@ -1,8 +1,8 @@ -package com.r3corda.contracts +package com.r3corda.contracts.asset import com.google.common.annotations.VisibleForTesting -import com.r3corda.contracts.cash.FungibleAssetState -import com.r3corda.contracts.cash.sumFungibleOrNull +import com.r3corda.contracts.asset.FungibleAssetState +import com.r3corda.contracts.asset.sumFungibleOrNull import com.r3corda.core.contracts.* import com.r3corda.core.crypto.Party import com.r3corda.core.crypto.SecureHash @@ -152,7 +152,7 @@ class Obligation

: Contract { override val owner: PublicKey get() = beneficiary - override fun move(newAmount: Amount

, newOwner: PublicKey): Obligation.State

+ override fun move(newAmount: Amount

, newOwner: PublicKey): State

= copy(quantity = newAmount.quantity, beneficiary = newOwner) override fun toString() = when (lifecycle) { @@ -249,10 +249,10 @@ class Obligation

: Contract { /** This is the function EVERYONE runs */ override fun verify(tx: TransactionForContract) { - val commands = tx.commands.select() + val commands = tx.commands.select() // Net commands are special, and cross issuance definitions, so handle them first - val netCommands = commands.select() + val netCommands = commands.select() if (netCommands.isNotEmpty()) { val netCommand = netCommands.single() val groups = when (netCommand.value.type) { diff --git a/contracts/src/main/kotlin/com/r3corda/contracts/testing/TestUtils.kt b/contracts/src/main/kotlin/com/r3corda/contracts/testing/TestUtils.kt index f3bc5eab21..bd13e1178e 100644 --- a/contracts/src/main/kotlin/com/r3corda/contracts/testing/TestUtils.kt +++ b/contracts/src/main/kotlin/com/r3corda/contracts/testing/TestUtils.kt @@ -1,8 +1,9 @@ package com.r3corda.contracts.testing import com.r3corda.contracts.* -import com.r3corda.contracts.cash.CASH_PROGRAM_ID -import com.r3corda.contracts.cash.Cash +import com.r3corda.contracts.asset.CASH_PROGRAM_ID +import com.r3corda.contracts.asset.Cash +import com.r3corda.contracts.asset.Obligation import com.r3corda.core.contracts.Amount import com.r3corda.core.contracts.Contract import com.r3corda.core.contracts.ContractState diff --git a/contracts/src/main/kotlin/com/r3corda/contracts/testing/WalletFiller.kt b/contracts/src/main/kotlin/com/r3corda/contracts/testing/WalletFiller.kt index ec7bec2404..2a9bd90fac 100644 --- a/contracts/src/main/kotlin/com/r3corda/contracts/testing/WalletFiller.kt +++ b/contracts/src/main/kotlin/com/r3corda/contracts/testing/WalletFiller.kt @@ -1,7 +1,7 @@ @file:JvmName("WalletFiller") package com.r3corda.contracts.testing -import com.r3corda.contracts.cash.Cash +import com.r3corda.contracts.asset.Cash import com.r3corda.core.contracts.Amount import com.r3corda.core.contracts.Issued import com.r3corda.core.contracts.SignedTransaction diff --git a/contracts/src/main/kotlin/com/r3corda/protocols/TwoPartyTradeProtocol.kt b/contracts/src/main/kotlin/com/r3corda/protocols/TwoPartyTradeProtocol.kt index 9959de2fb8..9a3a5db056 100644 --- a/contracts/src/main/kotlin/com/r3corda/protocols/TwoPartyTradeProtocol.kt +++ b/contracts/src/main/kotlin/com/r3corda/protocols/TwoPartyTradeProtocol.kt @@ -1,8 +1,8 @@ package com.r3corda.protocols import co.paralleluniverse.fibers.Suspendable -import com.r3corda.contracts.cash.Cash -import com.r3corda.contracts.cash.sumCashBy +import com.r3corda.contracts.asset.Cash +import com.r3corda.contracts.asset.sumCashBy import com.r3corda.core.contracts.* import com.r3corda.core.crypto.DigitalSignature import com.r3corda.core.crypto.Party diff --git a/contracts/src/test/java/com/r3corda/contracts/cash/CashTestsJava.java b/contracts/src/test/java/com/r3corda/contracts/asset/CashTestsJava.java similarity index 95% rename from contracts/src/test/java/com/r3corda/contracts/cash/CashTestsJava.java rename to contracts/src/test/java/com/r3corda/contracts/asset/CashTestsJava.java index 63772ab0dc..4d62148f70 100644 --- a/contracts/src/test/java/com/r3corda/contracts/cash/CashTestsJava.java +++ b/contracts/src/test/java/com/r3corda/contracts/asset/CashTestsJava.java @@ -1,4 +1,4 @@ -package com.r3corda.contracts.cash; +package com.r3corda.contracts.asset; import com.r3corda.core.contracts.PartyAndReference; import com.r3corda.core.serialization.OpaqueBytes; @@ -33,7 +33,7 @@ public class CashTestsJava { tx.tweak(tw -> { tw.output(outState); // No command arguments - return tw.failsRequirement("required com.r3corda.contracts.cash.FungibleAsset.Commands.Move command"); + return tw.failsRequirement("required com.r3corda.contracts.asset.FungibleAsset.Commands.Move command"); }); tx.tweak(tw -> { tw.output(outState); diff --git a/contracts/src/test/kotlin/com/r3corda/contracts/CommercialPaperTests.kt b/contracts/src/test/kotlin/com/r3corda/contracts/CommercialPaperTests.kt index 9b69908e1e..e7f0fb3083 100644 --- a/contracts/src/test/kotlin/com/r3corda/contracts/CommercialPaperTests.kt +++ b/contracts/src/test/kotlin/com/r3corda/contracts/CommercialPaperTests.kt @@ -1,6 +1,6 @@ package com.r3corda.contracts -import com.r3corda.contracts.cash.Cash +import com.r3corda.contracts.asset.Cash import com.r3corda.contracts.testing.* import com.r3corda.core.contracts.* import com.r3corda.core.crypto.SecureHash diff --git a/contracts/src/test/kotlin/com/r3corda/contracts/cash/CashTests.kt b/contracts/src/test/kotlin/com/r3corda/contracts/asset/CashTests.kt similarity index 99% rename from contracts/src/test/kotlin/com/r3corda/contracts/cash/CashTests.kt rename to contracts/src/test/kotlin/com/r3corda/contracts/asset/CashTests.kt index 000a7bb959..72f0cde8ab 100644 --- a/contracts/src/test/kotlin/com/r3corda/contracts/cash/CashTests.kt +++ b/contracts/src/test/kotlin/com/r3corda/contracts/asset/CashTests.kt @@ -1,4 +1,4 @@ -package com.r3corda.contracts.cash +package com.r3corda.contracts.asset import com.r3corda.contracts.testing.`issued by` import com.r3corda.contracts.testing.`owned by` @@ -40,7 +40,7 @@ class CashTests { tweak { output { outState } // No command arguments - this `fails requirement` "required com.r3corda.contracts.cash.FungibleAsset.Commands.Move command" + this `fails requirement` "required com.r3corda.contracts.asset.FungibleAsset.Commands.Move command" } tweak { output { outState } @@ -294,7 +294,7 @@ class CashTests { tweak { arg(MEGA_CORP_PUBKEY) { Cash.Commands.Exit(200.DOLLARS `issued by` defaultIssuer) } - this `fails requirement` "required com.r3corda.contracts.cash.FungibleAsset.Commands.Move command" + this `fails requirement` "required com.r3corda.contracts.asset.FungibleAsset.Commands.Move command" tweak { arg(DUMMY_PUBKEY_1) { Cash.Commands.Move() } diff --git a/contracts/src/test/kotlin/com/r3corda/contracts/ObligationTests.kt b/contracts/src/test/kotlin/com/r3corda/contracts/asset/ObligationTests.kt similarity index 96% rename from contracts/src/test/kotlin/com/r3corda/contracts/ObligationTests.kt rename to contracts/src/test/kotlin/com/r3corda/contracts/asset/ObligationTests.kt index f7144334bd..ea0cd5ea2c 100644 --- a/contracts/src/test/kotlin/com/r3corda/contracts/ObligationTests.kt +++ b/contracts/src/test/kotlin/com/r3corda/contracts/asset/ObligationTests.kt @@ -1,7 +1,7 @@ -package com.r3corda.contracts +package com.r3corda.contracts.asset -import com.r3corda.contracts.cash.Cash -import com.r3corda.contracts.Obligation.Lifecycle +import com.r3corda.contracts.asset.* +import com.r3corda.contracts.asset.Obligation.Lifecycle import com.r3corda.contracts.testing.* import com.r3corda.core.contracts.* import com.r3corda.core.crypto.SecureHash @@ -18,7 +18,7 @@ class ObligationTests { val defaultIssuer = MEGA_CORP.ref(1) val defaultUsd = USD `issued by` defaultIssuer val oneMillionDollars = 1000000.DOLLARS `issued by` defaultIssuer - val trustedCashContract = nonEmptySetOf(SecureHash.randomSHA256() as SecureHash) + val trustedCashContract = nonEmptySetOf(SecureHash.Companion.randomSHA256() as SecureHash) val megaIssuedDollars = nonEmptySetOf(Issued(defaultIssuer, USD)) val megaIssuedPounds = nonEmptySetOf(Issued(defaultIssuer, GBP)) val fivePm = Instant.parse("2016-01-01T17:00:00.00Z") @@ -54,7 +54,7 @@ class ObligationTests { tweak { output { outState } // No command arguments - this `fails requirement` "required com.r3corda.contracts.Obligation.Commands.Move command" + this `fails requirement` "required com.r3corda.contracts.asset.Obligation.Commands.Move command" } tweak { output { outState } @@ -280,23 +280,23 @@ class ObligationTests { // Now generate a transaction marking the obligation as having defaulted tx = TransactionType.General.Builder(DUMMY_NOTARY).apply { - Obligation().generateSetLifecycle(this, listOf(stateAndRef), Obligation.Lifecycle.DEFAULTED, DUMMY_NOTARY) + Obligation().generateSetLifecycle(this, listOf(stateAndRef), Lifecycle.DEFAULTED, DUMMY_NOTARY) signWith(MINI_CORP_KEY) signWith(DUMMY_NOTARY_KEY) }.toSignedTransaction() assertEquals(1, tx.tx.outputs.size) - assertEquals(stateAndRef.state.data.copy(lifecycle = Obligation.Lifecycle.DEFAULTED), tx.tx.outputs[0].data) + assertEquals(stateAndRef.state.data.copy(lifecycle = Lifecycle.DEFAULTED), tx.tx.outputs[0].data) assertTrue(tx.verify().isEmpty()) // And set it back stateAndRef = tx.tx.outRef>(0) tx = TransactionType.General.Builder(DUMMY_NOTARY).apply { - Obligation().generateSetLifecycle(this, listOf(stateAndRef), Obligation.Lifecycle.NORMAL, DUMMY_NOTARY) + Obligation().generateSetLifecycle(this, listOf(stateAndRef), Lifecycle.NORMAL, DUMMY_NOTARY) signWith(MINI_CORP_KEY) signWith(DUMMY_NOTARY_KEY) }.toSignedTransaction() assertEquals(1, tx.tx.outputs.size) - assertEquals(stateAndRef.state.data.copy(lifecycle = Obligation.Lifecycle.NORMAL), tx.tx.outputs[0].data) + assertEquals(stateAndRef.state.data.copy(lifecycle = Lifecycle.NORMAL), tx.tx.outputs[0].data) assertTrue(tx.verify().isEmpty()) } @@ -450,8 +450,8 @@ class ObligationTests { obligationTestRoots(this) transaction("Settlement") { input("Alice's $1,000,000 obligation to Bob") - output("Alice's defaulted $1,000,000 obligation to Bob") { (oneMillionDollars.OBLIGATION `between` Pair(ALICE, BOB_PUBKEY)).copy(lifecycle = Obligation.Lifecycle.DEFAULTED) } - arg(BOB_PUBKEY) { Obligation.Commands.SetLifecycle(Obligation.IssuanceDefinition(ALICE, defaultUsd.OBLIGATION_DEF), Obligation.Lifecycle.DEFAULTED) } + output("Alice's defaulted $1,000,000 obligation to Bob") { (oneMillionDollars.OBLIGATION `between` Pair(ALICE, BOB_PUBKEY)).copy(lifecycle = Lifecycle.DEFAULTED) } + arg(BOB_PUBKEY) { Obligation.Commands.SetLifecycle(Obligation.IssuanceDefinition(ALICE, defaultUsd.OBLIGATION_DEF), Lifecycle.DEFAULTED) } } }.expectFailureOfTx(1, "there is a timestamp from the authority") @@ -464,8 +464,8 @@ class ObligationTests { } transaction("Settlement") { input("Alice's $1,000,000 obligation to Bob") - output("Alice's defaulted $1,000,000 obligation to Bob") { (oneMillionDollars.OBLIGATION `between` Pair(ALICE, BOB_PUBKEY) `at` futureTestTime).copy(lifecycle = Obligation.Lifecycle.DEFAULTED) } - arg(BOB_PUBKEY) { Obligation.Commands.SetLifecycle(Obligation.IssuanceDefinition(ALICE, defaultUsd.OBLIGATION_DEF) `at` futureTestTime, Obligation.Lifecycle.DEFAULTED) } + output("Alice's defaulted $1,000,000 obligation to Bob") { (oneMillionDollars.OBLIGATION `between` Pair(ALICE, BOB_PUBKEY) `at` futureTestTime).copy(lifecycle = Lifecycle.DEFAULTED) } + arg(BOB_PUBKEY) { Obligation.Commands.SetLifecycle(Obligation.IssuanceDefinition(ALICE, defaultUsd.OBLIGATION_DEF) `at` futureTestTime, Lifecycle.DEFAULTED) } timestamp(TEST_TX_TIME) } }.expectFailureOfTx(1, "the due date has passed") @@ -477,8 +477,8 @@ class ObligationTests { } transaction("Settlement") { input("Alice's $1,000,000 obligation to Bob") - output("Alice's defaulted $1,000,000 obligation to Bob") { (oneMillionDollars.OBLIGATION `between` Pair(ALICE, BOB_PUBKEY) `at` pastTestTime).copy(lifecycle = Obligation.Lifecycle.DEFAULTED) } - arg(BOB_PUBKEY) { Obligation.Commands.SetLifecycle(Obligation.IssuanceDefinition(ALICE, defaultUsd.OBLIGATION_DEF) `at` pastTestTime, Obligation.Lifecycle.DEFAULTED) } + output("Alice's defaulted $1,000,000 obligation to Bob") { (oneMillionDollars.OBLIGATION `between` Pair(ALICE, BOB_PUBKEY) `at` pastTestTime).copy(lifecycle = Lifecycle.DEFAULTED) } + arg(BOB_PUBKEY) { Obligation.Commands.SetLifecycle(Obligation.IssuanceDefinition(ALICE, defaultUsd.OBLIGATION_DEF) `at` pastTestTime, Lifecycle.DEFAULTED) } timestamp(TEST_TX_TIME) } }.verify() @@ -557,8 +557,8 @@ class ObligationTests { input { inState } input { inState `issued by` MINI_CORP } output { outState } - arg(DUMMY_PUBKEY_1) {Obligation.Commands.Move(inState.issuanceDef) } - arg(DUMMY_PUBKEY_1) {Obligation.Commands.Move((inState `issued by` MINI_CORP).issuanceDef) } + arg(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } + arg(DUMMY_PUBKEY_1) { Obligation.Commands.Move((inState `issued by` MINI_CORP).issuanceDef) } this `fails requirement` "at obligor MiniCorp the amounts balance" } } @@ -578,7 +578,7 @@ class ObligationTests { tweak { arg(MEGA_CORP_PUBKEY) { Obligation.Commands.Exit(inState.issuanceDef, 200.DOLLARS) } - this `fails requirement` "required com.r3corda.contracts.Obligation.Commands.Move command" + this `fails requirement` "required com.r3corda.contracts.asset.Obligation.Commands.Move command" tweak { arg(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } @@ -683,7 +683,7 @@ class ObligationTests { // States must not be nettable if the cash contract differs assertNotEquals(fiveKDollarsFromMegaToMega.bilateralNetState, - fiveKDollarsFromMegaToMega.copy(template = megaCorpDollarSettlement.copy(acceptableContracts = nonEmptySetOf(SecureHash.randomSHA256()))).bilateralNetState) + fiveKDollarsFromMegaToMega.copy(template = megaCorpDollarSettlement.copy(acceptableContracts = nonEmptySetOf(SecureHash.Companion.randomSHA256()))).bilateralNetState) // States must not be nettable if the trusted issuers differ val miniCorpIssuer = nonEmptySetOf(Issued(MINI_CORP.ref(1), USD)) diff --git a/docs/build/html/api/alltypes/index.html b/docs/build/html/api/alltypes/index.html index a61c9e0e8b..aede8b799b 100644 --- a/docs/build/html/api/alltypes/index.html +++ b/docs/build/html/api/alltypes/index.html @@ -124,7 +124,7 @@ as well.

-com.r3corda.contracts.cash.AssetIssuanceDefinition +com.r3corda.contracts.asset.AssetIssuanceDefinition

Subset of cash-like contract state, containing the issuance definition. If these definitions match for two contracts states, those states can be aggregated.

@@ -209,7 +209,7 @@ no staff are around to handle problems.

-com.r3corda.contracts.cash.Cash +com.r3corda.contracts.asset.Cash

A cash transaction may split and merge money represented by a set of (issuer, depositRef) pairs, across multiple input and output states. Imagine a Bitcoin transaction but in which all UTXOs had a colour @@ -569,7 +569,7 @@ that would divide into (eg annually = 1, semiannual = 2, monthly = 12 etc).

-com.r3corda.contracts.cash.FungibleAsset +com.r3corda.contracts.asset.FungibleAsset

Superclass for contracts 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 @@ -581,7 +581,7 @@ countable, and so on.

-com.r3corda.contracts.cash.FungibleAssetState +com.r3corda.contracts.asset.FungibleAssetState

Common elements of cash contract states.

@@ -656,7 +656,7 @@ testing).

-com.r3corda.contracts.cash.InsufficientBalanceException +com.r3corda.contracts.asset.InsufficientBalanceException diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-asset-issuance-definition/deposit.html b/docs/build/html/api/com.r3corda.contracts.cash/-asset-issuance-definition/deposit.html index a301089776..35629ba7c5 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-asset-issuance-definition/deposit.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-asset-issuance-definition/deposit.html @@ -4,10 +4,10 @@ -com.r3corda.contracts.cash / AssetIssuanceDefinition / deposit
+com.r3corda.contracts.asset / AssetIssuanceDefinition / deposit

deposit

- + abstract val deposit: PartyAndReference

Where the underlying asset backing this ledger entry can be found (propagated)


diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-asset-issuance-definition/index.html b/docs/build/html/api/com.r3corda.contracts.cash/-asset-issuance-definition/index.html index 8c90481cca..b140e10db6 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-asset-issuance-definition/index.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-asset-issuance-definition/index.html @@ -4,7 +4,7 @@ -com.r3corda.contracts.cash / AssetIssuanceDefinition
+com.r3corda.contracts.asset / AssetIssuanceDefinition

AssetIssuanceDefinition

interface AssetIssuanceDefinition<T> : IssuanceDefinition
diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-asset-issuance-definition/token.html b/docs/build/html/api/com.r3corda.contracts.cash/-asset-issuance-definition/token.html index 1f0863afa4..ff26264a37 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-asset-issuance-definition/token.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-asset-issuance-definition/token.html @@ -4,10 +4,10 @@ -com.r3corda.contracts.cash / AssetIssuanceDefinition / token
+com.r3corda.contracts.asset / AssetIssuanceDefinition / token

token

- + abstract val token: T


diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-c-a-s-h_-p-r-o-g-r-a-m_-i-d.html b/docs/build/html/api/com.r3corda.contracts.cash/-c-a-s-h_-p-r-o-g-r-a-m_-i-d.html index 45544c9893..663d79fe8f 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-c-a-s-h_-p-r-o-g-r-a-m_-i-d.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-c-a-s-h_-p-r-o-g-r-a-m_-i-d.html @@ -4,10 +4,10 @@ -com.r3corda.contracts.cash / CASH_PROGRAM_ID
+com.r3corda.contracts.asset / CASH_PROGRAM_ID

CASH_PROGRAM_ID

- + val CASH_PROGRAM_ID: Cash


diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-commands/-exit/-init-.html b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-commands/-exit/-init-.html index 3101bfed2a..f56b66c5b4 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-commands/-exit/-init-.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-commands/-exit/-init-.html @@ -4,10 +4,10 @@ -com.r3corda.contracts.cash / Cash / Commands / Exit / <init>
+com.r3corda.contracts.asset / Cash / Commands / Exit / <init>

<init>

-Exit(amount: Amount<Currency>)
+Exit(amount: Amount<Currency>)

A command stating that money has been withdrawn from the shared ledger and is now accounted for in some other way.


diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-commands/-exit/amount.html b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-commands/-exit/amount.html index 5178e04d6e..310f5ee798 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-commands/-exit/amount.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-commands/-exit/amount.html @@ -4,10 +4,10 @@ -com.r3corda.contracts.cash / Cash / Commands / Exit / amount
+com.r3corda.contracts.asset / Cash / Commands / Exit / amount

amount

- + val amount: Amount<Currency>
Overrides Exit.amount

diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-commands/-exit/index.html b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-commands/-exit/index.html index 4d7475222e..b84e6c7ee1 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-commands/-exit/index.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-commands/-exit/index.html @@ -4,7 +4,7 @@ -com.r3corda.contracts.cash / Cash / Commands / Exit
+com.r3corda.contracts.asset / Cash / Commands / Exit

Exit

data class Exit : Commands, Exit<Currency>
@@ -19,7 +19,7 @@ in some other way.

<init> -Exit(amount: Amount<Currency>)

A command stating that money has been withdrawn from the shared ledger and is now accounted for +Exit(amount: Amount<Currency>)

A command stating that money has been withdrawn from the shared ledger and is now accounted for in some other way.

diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-commands/-issue/-init-.html b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-commands/-issue/-init-.html index d14e6d85de..ab8a7b3a61 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-commands/-issue/-init-.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-commands/-issue/-init-.html @@ -4,10 +4,10 @@ -com.r3corda.contracts.cash / Cash / Commands / Issue / <init>
+com.r3corda.contracts.asset / Cash / Commands / Issue / <init>

<init>

-Issue(nonce: Long = SecureRandom.getInstanceStrong().nextLong())
+Issue(nonce: Long = SecureRandom.getInstanceStrong().nextLong())

Allows new cash states to be issued into existence: the nonce ("number used once") ensures the transaction has a unique ID even when there are no inputs.


diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-commands/-issue/index.html b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-commands/-issue/index.html index 5fb028818d..b24c274985 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-commands/-issue/index.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-commands/-issue/index.html @@ -4,7 +4,7 @@ -com.r3corda.contracts.cash / Cash / Commands / Issue
+com.r3corda.contracts.asset / Cash / Commands / Issue

Issue

data class Issue : Issue
@@ -19,7 +19,7 @@ has a unique ID even when there are no inputs.

<init> -Issue(nonce: Long = SecureRandom.getInstanceStrong().nextLong())

Allows new cash states to be issued into existence: the nonce ("number used once") ensures the transaction +Issue(nonce: Long = SecureRandom.getInstanceStrong().nextLong())

Allows new cash states to be issued into existence: the nonce ("number used once") ensures the transaction has a unique ID even when there are no inputs.

diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-commands/-issue/nonce.html b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-commands/-issue/nonce.html index e9551f169b..cbac655421 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-commands/-issue/nonce.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-commands/-issue/nonce.html @@ -4,10 +4,10 @@ -com.r3corda.contracts.cash / Cash / Commands / Issue / nonce
+com.r3corda.contracts.asset / Cash / Commands / Issue / nonce

nonce

- + val nonce: Long
Overrides Issue.nonce

diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-issuance-definition/-init-.html b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-issuance-definition/-init-.html index 90b93a9810..78d3da604a 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-issuance-definition/-init-.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-issuance-definition/-init-.html @@ -4,10 +4,10 @@ -com.r3corda.contracts.cash / Cash / IssuanceDefinition / <init>
+com.r3corda.contracts.asset / Cash / IssuanceDefinition / <init>

<init>

-IssuanceDefinition(deposit: PartyAndReference, token: T)
+IssuanceDefinition(deposit: PartyAndReference, token: T)


diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-issuance-definition/deposit.html b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-issuance-definition/deposit.html index a7af136488..1577a0c22a 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-issuance-definition/deposit.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-issuance-definition/deposit.html @@ -4,10 +4,10 @@ -com.r3corda.contracts.cash / Cash / IssuanceDefinition / deposit
+com.r3corda.contracts.asset / Cash / IssuanceDefinition / deposit

deposit

- + val deposit: PartyAndReference
Overrides AssetIssuanceDefinition.deposit

Where the underlying currency backing this ledger entry can be found (propagated)

diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-issuance-definition/index.html b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-issuance-definition/index.html index 92ba11b85f..f3b3bd692b 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-issuance-definition/index.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-issuance-definition/index.html @@ -4,7 +4,7 @@ -com.r3corda.contracts.cash / Cash / IssuanceDefinition
+com.r3corda.contracts.asset / Cash / IssuanceDefinition

IssuanceDefinition

data class IssuanceDefinition<T> : AssetIssuanceDefinition<T>
@@ -17,7 +17,7 @@ <init> -IssuanceDefinition(deposit: PartyAndReference, token: T) +IssuanceDefinition(deposit: PartyAndReference, token: T) diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-issuance-definition/token.html b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-issuance-definition/token.html index f2198b84d9..446f4cce08 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-issuance-definition/token.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-issuance-definition/token.html @@ -4,10 +4,10 @@ -com.r3corda.contracts.cash / Cash / IssuanceDefinition / token
+com.r3corda.contracts.asset / Cash / IssuanceDefinition / token

token

- + val token: T
Overrides AssetIssuanceDefinition.token

diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/-init-.html b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/-init-.html index 051dafea4c..fd387fc606 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/-init-.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/-init-.html @@ -4,10 +4,10 @@ -com.r3corda.contracts.cash / Cash / State / <init>
+com.r3corda.contracts.asset / Cash / State / <init>

<init>

-State(deposit: PartyAndReference, amount: Amount<Currency>, owner: PublicKey, notary: Party)
+State(deposit: PartyAndReference, amount: Amount<Currency>, owner: PublicKey, notary: Party)

A state representing a cash claim against some party



diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/amount.html b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/amount.html index 875ded550f..459c6819d5 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/amount.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/amount.html @@ -4,10 +4,10 @@ -com.r3corda.contracts.cash / Cash / State / amount
+com.r3corda.contracts.asset / Cash / State / amount

amount

- + val amount: Amount<Currency>
Overrides State.amount

diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/contract.html b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/contract.html index 2d4374c009..fed4080ebc 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/contract.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/contract.html @@ -4,10 +4,10 @@ -com.r3corda.contracts.cash / Cash / State / contract
+com.r3corda.contracts.asset / Cash / State / contract

contract

- + val contract: Cash
Overrides ContractState.contract

Contract by which the state belongs

diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/deposit.html b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/deposit.html index 098ecb1ab7..8196717f65 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/deposit.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/deposit.html @@ -4,10 +4,10 @@ -com.r3corda.contracts.cash / Cash / State / deposit
+com.r3corda.contracts.asset / Cash / State / deposit

deposit

- + val deposit: PartyAndReference
Overrides State.deposit

Where the underlying currency backing this ledger entry can be found (propagated)

diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/index.html b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/index.html index ce72e23d98..16d3ce9533 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/index.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/index.html @@ -4,7 +4,7 @@ -com.r3corda.contracts.cash / Cash / State
+com.r3corda.contracts.asset / Cash / State

State

data class State : State<Currency>
@@ -18,7 +18,7 @@ <init> -State(deposit: PartyAndReference, amount: Amount<Currency>, owner: PublicKey, notary: Party)

A state representing a cash claim against some party

+State(deposit: PartyAndReference, amount: Amount<Currency>, owner: PublicKey, notary: Party)

A state representing a cash claim against some party

@@ -81,7 +81,7 @@ withNewOwner -fun withNewOwner(newOwner: PublicKey): <ERROR CLASS>

Copies the underlying data structure, replacing the owner field with this new value and leaving the rest alone

+fun withNewOwner(newOwner: PublicKey): <ERROR CLASS>

Copies the underlying data structure, replacing the owner field with this new value and leaving the rest alone

@@ -93,13 +93,13 @@ issued by -infix fun State.issued by(party: Party): State +infix fun State.issued by(party: Party): State owned by -infix fun State.owned by(owner: PublicKey): State +infix fun State.owned by(owner: PublicKey): State diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/issuance-def.html b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/issuance-def.html index e11f23a197..00f59635c9 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/issuance-def.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/issuance-def.html @@ -4,10 +4,10 @@ -com.r3corda.contracts.cash / Cash / State / issuanceDef
+com.r3corda.contracts.asset / Cash / State / issuanceDef

issuanceDef

- + val issuanceDef: IssuanceDefinition<Currency>
Overrides FungibleAssetState.issuanceDef

diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/notary.html b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/notary.html index 9dbf7ee9ea..607a64a7d3 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/notary.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/notary.html @@ -4,10 +4,10 @@ -com.r3corda.contracts.cash / Cash / State / notary
+com.r3corda.contracts.asset / Cash / State / notary

notary

- + val notary: Party
Overrides State.notary

Identity of the notary that ensures this state is not used as an input to a transaction more than once

diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/owner.html b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/owner.html index 156afc21eb..60b915aa35 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/owner.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/owner.html @@ -4,10 +4,10 @@ -com.r3corda.contracts.cash / Cash / State / owner
+com.r3corda.contracts.asset / Cash / State / owner

owner

- + val owner: PublicKey
Overrides State.owner

There must be a MoveCommand signed by this key to claim the amount

diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/to-string.html b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/to-string.html index 1362fb6a6f..94c2abeecd 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/to-string.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/to-string.html @@ -4,10 +4,10 @@ -com.r3corda.contracts.cash / Cash / State / toString
+com.r3corda.contracts.asset / Cash / State / toString

toString

- + fun toString(): String


diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/with-new-owner.html b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/with-new-owner.html index acb1a8c71c..d0fdf7138e 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/with-new-owner.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-cash/-state/with-new-owner.html @@ -4,11 +4,11 @@ -com.r3corda.contracts.cash / Cash / State / withNewOwner
+com.r3corda.contracts.asset / Cash / State / withNewOwner

withNewOwner

- -fun withNewOwner(newOwner: PublicKey): <ERROR CLASS>
+ +fun withNewOwner(newOwner: PublicKey): <ERROR CLASS>
Overrides OwnableState.withNewOwner

Copies the underlying data structure, replacing the owner field with this new value and leaving the rest alone


diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-cash/generate-issue.html b/docs/build/html/api/com.r3corda.contracts.cash/-cash/generate-issue.html index bbef2a8e04..df54fe9cb5 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-cash/generate-issue.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-cash/generate-issue.html @@ -4,16 +4,16 @@ -com.r3corda.contracts.cash / Cash / generateIssue
+com.r3corda.contracts.asset / Cash / generateIssue

generateIssue

- -fun generateIssue(tx: TransactionBuilder, issuanceDef: AssetIssuanceDefinition<Currency>, pennies: Long, owner: PublicKey, notary: Party): Unit
+ +fun generateIssue(tx: TransactionBuilder, issuanceDef: AssetIssuanceDefinition<Currency>, pennies: Long, owner: PublicKey, notary: Party): Unit

Puts together an issuance transaction from the given template, that starts out being owned by the given pubkey.



- -fun generateIssue(tx: TransactionBuilder, amount: Amount<Currency>, at: PartyAndReference, owner: PublicKey, notary: Party): Unit
+ +fun generateIssue(tx: TransactionBuilder, amount: Amount<Currency>, at: PartyAndReference, owner: PublicKey, notary: Party): Unit

Puts together an issuance transaction for the specified amount that starts out being owned by the given pubkey.



diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-cash/generate-spend.html b/docs/build/html/api/com.r3corda.contracts.cash/-cash/generate-spend.html index 096c6f0bca..ca1d11d271 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-cash/generate-spend.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-cash/generate-spend.html @@ -4,11 +4,11 @@ -com.r3corda.contracts.cash / Cash / generateSpend
+com.r3corda.contracts.asset / Cash / generateSpend

generateSpend

- -fun generateSpend(tx: TransactionBuilder, amount: Amount<Currency>, to: PublicKey, cashStates: List<StateAndRef<State>>, onlyFromParties: Set<Party>? = null): List<PublicKey>
+ +fun generateSpend(tx: TransactionBuilder, amount: Amount<Currency>, to: PublicKey, cashStates: List<StateAndRef<State>>, onlyFromParties: Set<Party>? = null): List<PublicKey>

Generate a transaction that consumes one or more of the given input states to move money to the given pubkey. Note that the wallet list is not updated: its up to you to do that.

Parameters

diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-cash/index.html b/docs/build/html/api/com.r3corda.contracts.cash/-cash/index.html index 5080176564..fe92eabb22 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-cash/index.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-cash/index.html @@ -4,7 +4,7 @@ -com.r3corda.contracts.cash / Cash
+com.r3corda.contracts.asset / Cash

Cash

class Cash : FungibleAsset<Currency>
@@ -79,15 +79,15 @@ the same transaction.

generateIssue -fun generateIssue(tx: TransactionBuilder, issuanceDef: AssetIssuanceDefinition<Currency>, pennies: Long, owner: PublicKey, notary: Party): Unit

Puts together an issuance transaction from the given template, that starts out being owned by the given pubkey.

-fun generateIssue(tx: TransactionBuilder, amount: Amount<Currency>, at: PartyAndReference, owner: PublicKey, notary: Party): Unit

Puts together an issuance transaction for the specified amount that starts out being owned by the given pubkey.

+fun generateIssue(tx: TransactionBuilder, issuanceDef: AssetIssuanceDefinition<Currency>, pennies: Long, owner: PublicKey, notary: Party): Unit

Puts together an issuance transaction from the given template, that starts out being owned by the given pubkey.

+fun generateIssue(tx: TransactionBuilder, amount: Amount<Currency>, at: PartyAndReference, owner: PublicKey, notary: Party): Unit

Puts together an issuance transaction for the specified amount that starts out being owned by the given pubkey.

generateSpend -fun generateSpend(tx: TransactionBuilder, amount: Amount<Currency>, to: PublicKey, cashStates: List<StateAndRef<State>>, onlyFromParties: Set<Party>? = null): List<PublicKey>

Generate a transaction that consumes one or more of the given input states to move money to the given pubkey. +fun generateSpend(tx: TransactionBuilder, amount: Amount<Currency>, to: PublicKey, cashStates: List<StateAndRef<State>>, onlyFromParties: Set<Party>? = null): List<PublicKey>

Generate a transaction that consumes one or more of the given input states to move money to the given pubkey. Note that the wallet list is not updated: its up to you to do that.

@@ -100,7 +100,7 @@ Note that the wallet list is not updated: its up to you to do that.

verify -open fun verify(tx: TransactionForVerification): Unit

This is the function EVERYONE runs

+open fun verify(tx: TransactionForVerification): Unit

This is the function EVERYONE runs

diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-cash/legal-contract-reference.html b/docs/build/html/api/com.r3corda.contracts.cash/-cash/legal-contract-reference.html index d6776b7a41..5978af553b 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-cash/legal-contract-reference.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-cash/legal-contract-reference.html @@ -4,10 +4,10 @@ -com.r3corda.contracts.cash / Cash / legalContractReference
+com.r3corda.contracts.asset / Cash / legalContractReference

legalContractReference

- + val legalContractReference: SecureHash
Overrides Contract.legalContractReference

TODO:

diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset-state/amount.html b/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset-state/amount.html index 076438a8cc..40f49864c0 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset-state/amount.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset-state/amount.html @@ -4,10 +4,10 @@ -com.r3corda.contracts.cash / FungibleAssetState / amount
+com.r3corda.contracts.asset / FungibleAssetState / amount

amount

- + abstract val amount: Amount<T>


diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset-state/deposit.html b/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset-state/deposit.html index 299676e75a..3589c82b02 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset-state/deposit.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset-state/deposit.html @@ -4,10 +4,10 @@ -com.r3corda.contracts.cash / FungibleAssetState / deposit
+com.r3corda.contracts.asset / FungibleAssetState / deposit

deposit

- + abstract val deposit: PartyAndReference

Where the underlying currency backing this ledger entry can be found (propagated)


diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset-state/issuance-def.html b/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset-state/issuance-def.html index 8fcf9f7a8b..40ec6c2a50 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset-state/issuance-def.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset-state/issuance-def.html @@ -4,10 +4,10 @@ -com.r3corda.contracts.cash / FungibleAssetState / issuanceDef
+com.r3corda.contracts.asset / FungibleAssetState / issuanceDef

issuanceDef

- + abstract val issuanceDef: I


diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-commands/-exit/amount.html b/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-commands/-exit/amount.html index 481952eaba..cd30f12509 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-commands/-exit/amount.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-commands/-exit/amount.html @@ -4,10 +4,10 @@ -com.r3corda.contracts.cash / FungibleAsset / Commands / Exit / amount
+com.r3corda.contracts.asset / FungibleAsset / Commands / Exit / amount

amount

- + abstract val amount: Amount<T>


diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-commands/-exit/index.html b/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-commands/-exit/index.html index cbf15d9eba..5c7cde8417 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-commands/-exit/index.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-commands/-exit/index.html @@ -4,7 +4,7 @@ -com.r3corda.contracts.cash / FungibleAsset / Commands / Exit
+com.r3corda.contracts.asset / FungibleAsset / Commands / Exit

Exit

interface Exit<T> : Commands
diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-commands/-issue/index.html b/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-commands/-issue/index.html index a044b1f185..90e24de693 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-commands/-issue/index.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-commands/-issue/index.html @@ -4,7 +4,7 @@ -com.r3corda.contracts.cash / FungibleAsset / Commands / Issue
+com.r3corda.contracts.asset / FungibleAsset / Commands / Issue

Issue

interface Issue : Commands
diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-commands/-issue/nonce.html b/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-commands/-issue/nonce.html index e3cdabc6f6..7e9375b9ff 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-commands/-issue/nonce.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-commands/-issue/nonce.html @@ -4,10 +4,10 @@ -com.r3corda.contracts.cash / FungibleAsset / Commands / Issue / nonce
+com.r3corda.contracts.asset / FungibleAsset / Commands / Issue / nonce

nonce

- + abstract val nonce: Long


diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-commands/-move.html b/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-commands/-move.html index 89fda720ff..68c60d51ae 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-commands/-move.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-commands/-move.html @@ -4,7 +4,7 @@ -com.r3corda.contracts.cash / FungibleAsset / Commands / Move
+com.r3corda.contracts.asset / FungibleAsset / Commands / Move

Move

interface Move : Commands
diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-init-.html b/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-init-.html index bf8d4a2cca..0058e07544 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-init-.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-init-.html @@ -4,7 +4,7 @@ -com.r3corda.contracts.cash / FungibleAsset / <init>
+com.r3corda.contracts.asset / FungibleAsset / <init>

<init>

FungibleAsset()
diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-state/amount.html b/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-state/amount.html index 9b942f2354..cc262f412c 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-state/amount.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-state/amount.html @@ -4,10 +4,10 @@ -com.r3corda.contracts.cash / FungibleAsset / State / amount
+com.r3corda.contracts.asset / FungibleAsset / State / amount

amount

- + abstract val amount: Amount<T>
Overrides FungibleAssetState.amount

diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-state/deposit.html b/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-state/deposit.html index 7e8119cf05..5ee95110f0 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-state/deposit.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-state/deposit.html @@ -4,10 +4,10 @@ -com.r3corda.contracts.cash / FungibleAsset / State / deposit
+com.r3corda.contracts.asset / FungibleAsset / State / deposit

deposit

- + abstract val deposit: PartyAndReference
Overrides FungibleAssetState.deposit

Where the underlying asset backing this ledger entry can be found (propagated)

diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-state/index.html b/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-state/index.html index 155a9b194c..adf7971ac1 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-state/index.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-state/index.html @@ -4,7 +4,7 @@ -com.r3corda.contracts.cash / FungibleAsset / State
+com.r3corda.contracts.asset / FungibleAsset / State

State

interface State<T> : FungibleAssetState<T, AssetIssuanceDefinition<T>>
diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-state/notary.html b/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-state/notary.html index b4feb6c780..30ddb54fce 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-state/notary.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-state/notary.html @@ -4,10 +4,10 @@ -com.r3corda.contracts.cash / FungibleAsset / State / notary
+com.r3corda.contracts.asset / FungibleAsset / State / notary

notary

- + abstract val notary: Party
Overrides ContractState.notary

Identity of the notary that ensures this state is not used as an input to a transaction more than once

diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-state/owner.html b/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-state/owner.html index 015df89228..65b4b0cd45 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-state/owner.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/-state/owner.html @@ -4,10 +4,10 @@ -com.r3corda.contracts.cash / FungibleAsset / State / owner
+com.r3corda.contracts.asset / FungibleAsset / State / owner

owner

- + abstract val owner: PublicKey
Overrides OwnableState.owner

There must be a MoveCommand signed by this key to claim the amount

diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/index.html b/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/index.html index ec0662e349..572e123294 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/index.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/index.html @@ -4,7 +4,7 @@ -com.r3corda.contracts.cash / FungibleAsset
+com.r3corda.contracts.asset / FungibleAsset

FungibleAsset

abstract class FungibleAsset<T> : Contract
@@ -78,7 +78,7 @@ the contracts contents).

verify -open fun verify(tx: TransactionForVerification): Unit

This is the function EVERYONE runs

+open fun verify(tx: TransactionForVerification): Unit

This is the function EVERYONE runs

diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/verify.html b/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/verify.html index 8d9a996009..3114c7dda2 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/verify.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-fungible-asset/verify.html @@ -4,11 +4,11 @@ -com.r3corda.contracts.cash / FungibleAsset / verify
+com.r3corda.contracts.asset / FungibleAsset / verify

verify

- -open fun verify(tx: TransactionForVerification): Unit
+ +open fun verify(tx: TransactionForVerification): Unit
Overrides Contract.verify

This is the function EVERYONE runs


diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-insufficient-balance-exception/-init-.html b/docs/build/html/api/com.r3corda.contracts.cash/-insufficient-balance-exception/-init-.html index bc075fdf5e..db5fc3d6c7 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-insufficient-balance-exception/-init-.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-insufficient-balance-exception/-init-.html @@ -4,10 +4,10 @@ -com.r3corda.contracts.cash / InsufficientBalanceException / <init>
+com.r3corda.contracts.asset / InsufficientBalanceException / <init>

<init>

-InsufficientBalanceException(amountMissing: Amount<*>)
+InsufficientBalanceException(amountMissing: Amount<*>)


diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-insufficient-balance-exception/amount-missing.html b/docs/build/html/api/com.r3corda.contracts.cash/-insufficient-balance-exception/amount-missing.html index d24c6f7020..9323ad1b72 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-insufficient-balance-exception/amount-missing.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-insufficient-balance-exception/amount-missing.html @@ -4,10 +4,10 @@ -com.r3corda.contracts.cash / InsufficientBalanceException / amountMissing
+com.r3corda.contracts.asset / InsufficientBalanceException / amountMissing

amountMissing

- + val amountMissing: Amount<*>


diff --git a/docs/build/html/api/com.r3corda.contracts.cash/-insufficient-balance-exception/index.html b/docs/build/html/api/com.r3corda.contracts.cash/-insufficient-balance-exception/index.html index d306f5cc82..6616fccdfd 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/-insufficient-balance-exception/index.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/-insufficient-balance-exception/index.html @@ -4,7 +4,7 @@ -com.r3corda.contracts.cash / InsufficientBalanceException
+com.r3corda.contracts.asset / InsufficientBalanceException

InsufficientBalanceException

class InsufficientBalanceException : Exception
@@ -17,7 +17,7 @@ <init> -InsufficientBalanceException(amountMissing: Amount<*>) +InsufficientBalanceException(amountMissing: Amount<*>) diff --git a/docs/build/html/api/com.r3corda.contracts.cash/index.html b/docs/build/html/api/com.r3corda.contracts.cash/index.html index 80832fa684..333f510d81 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/index.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/index.html @@ -1,12 +1,12 @@ -com.r3corda.contracts.cash - +com.r3corda.contracts.asset - -com.r3corda.contracts.cash
+com.r3corda.contracts.asset

-

Package com.r3corda.contracts.cash

+

Package com.r3corda.contracts.asset

Types

diff --git a/docs/build/html/api/com.r3corda.contracts.cash/kotlin.collections.-iterable/index.html b/docs/build/html/api/com.r3corda.contracts.cash/kotlin.collections.-iterable/index.html index 5b8ca017e8..04ee7fee4f 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/kotlin.collections.-iterable/index.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/kotlin.collections.-iterable/index.html @@ -1,10 +1,10 @@ -com.r3corda.contracts.cash.kotlin.collections.Iterable - +com.r3corda.contracts.asset.kotlin.collections.Iterable - -com.r3corda.contracts.cash / kotlin.collections.Iterable
+com.r3corda.contracts.asset / kotlin.collections.Iterable

Extensions for kotlin.collections.Iterable

@@ -21,7 +21,7 @@ states cannot be added together (i.e. are different currencies).

@@ -37,7 +37,7 @@ different currencies).

@@ -52,7 +52,7 @@ states cannot be added together (i.e. are different tokens).

@@ -68,7 +68,7 @@ different tokens).

diff --git a/docs/build/html/api/com.r3corda.contracts.cash/kotlin.collections.-iterable/sum-cash-by.html b/docs/build/html/api/com.r3corda.contracts.cash/kotlin.collections.-iterable/sum-cash-by.html index 9065fe85d9..94c663004e 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/kotlin.collections.-iterable/sum-cash-by.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/kotlin.collections.-iterable/sum-cash-by.html @@ -4,11 +4,11 @@ -com.r3corda.contracts.cash / kotlin.collections.Iterable / sumCashBy
+com.r3corda.contracts.asset / kotlin.collections.Iterable / sumCashBy

sumCashBy

- -fun Iterable<ContractState>.sumCashBy(owner: PublicKey): <ERROR CLASS>
+ +fun Iterable<ContractState>.sumCashBy(owner: PublicKey): <ERROR CLASS>

Sums the cash states in the list belonging to a single owner, throwing an exception if there are none, or if any of the cash states cannot be added together (i.e. are different currencies).

diff --git a/docs/build/html/api/com.r3corda.contracts.cash/kotlin.collections.-iterable/sum-cash-or-null.html b/docs/build/html/api/com.r3corda.contracts.cash/kotlin.collections.-iterable/sum-cash-or-null.html index 2de2afb815..3503e531b1 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/kotlin.collections.-iterable/sum-cash-or-null.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/kotlin.collections.-iterable/sum-cash-or-null.html @@ -4,10 +4,10 @@ -com.r3corda.contracts.cash / kotlin.collections.Iterable / sumCashOrNull
+com.r3corda.contracts.asset / kotlin.collections.Iterable / sumCashOrNull

sumCashOrNull

- +fun Iterable<ContractState>.sumCashOrNull(): <ERROR CLASS>

Sums the cash states in the list, returning null if there are none.


diff --git a/docs/build/html/api/com.r3corda.contracts.cash/kotlin.collections.-iterable/sum-cash-or-zero.html b/docs/build/html/api/com.r3corda.contracts.cash/kotlin.collections.-iterable/sum-cash-or-zero.html index 306eae07c6..4b2a779908 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/kotlin.collections.-iterable/sum-cash-or-zero.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/kotlin.collections.-iterable/sum-cash-or-zero.html @@ -4,11 +4,11 @@ -com.r3corda.contracts.cash / kotlin.collections.Iterable / sumCashOrZero
+com.r3corda.contracts.asset / kotlin.collections.Iterable / sumCashOrZero

sumCashOrZero

- -fun Iterable<ContractState>.sumCashOrZero(currency: Currency): <ERROR CLASS>
+ +fun Iterable<ContractState>.sumCashOrZero(currency: Currency): <ERROR CLASS>

Sums the cash states in the list, returning zero of the given currency if there are none.



diff --git a/docs/build/html/api/com.r3corda.contracts.cash/kotlin.collections.-iterable/sum-cash.html b/docs/build/html/api/com.r3corda.contracts.cash/kotlin.collections.-iterable/sum-cash.html index 91578aa2fb..6283fb4e19 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/kotlin.collections.-iterable/sum-cash.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/kotlin.collections.-iterable/sum-cash.html @@ -4,10 +4,10 @@ -com.r3corda.contracts.cash / kotlin.collections.Iterable / sumCash
+com.r3corda.contracts.asset / kotlin.collections.Iterable / sumCash

sumCash

- +fun Iterable<ContractState>.sumCash(): <ERROR CLASS>

Sums the cash states in the list, throwing an exception if there are none, or if any of the cash states cannot be added together (i.e. are different currencies).

diff --git a/docs/build/html/api/com.r3corda.contracts.cash/kotlin.collections.-iterable/sum-fungible-by.html b/docs/build/html/api/com.r3corda.contracts.cash/kotlin.collections.-iterable/sum-fungible-by.html index b1d90b04d2..cc0a42b341 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/kotlin.collections.-iterable/sum-fungible-by.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/kotlin.collections.-iterable/sum-fungible-by.html @@ -4,11 +4,11 @@ -com.r3corda.contracts.cash / kotlin.collections.Iterable / sumFungibleBy
+com.r3corda.contracts.asset / kotlin.collections.Iterable / sumFungibleBy

sumFungibleBy

- -fun <T> Iterable<ContractState>.sumFungibleBy(owner: PublicKey): <ERROR CLASS>
+ +fun <T> Iterable<ContractState>.sumFungibleBy(owner: PublicKey): <ERROR CLASS>

Sums the asset states in the list belonging to a single owner, throwing an exception if there are none, or if any of the asset states cannot be added together (i.e. are different tokens).

diff --git a/docs/build/html/api/com.r3corda.contracts.cash/kotlin.collections.-iterable/sum-fungible-or-null.html b/docs/build/html/api/com.r3corda.contracts.cash/kotlin.collections.-iterable/sum-fungible-or-null.html index 31652ff2b0..e2b4162f63 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/kotlin.collections.-iterable/sum-fungible-or-null.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/kotlin.collections.-iterable/sum-fungible-or-null.html @@ -4,10 +4,10 @@ -com.r3corda.contracts.cash / kotlin.collections.Iterable / sumFungibleOrNull
+com.r3corda.contracts.asset / kotlin.collections.Iterable / sumFungibleOrNull

sumFungibleOrNull

- +fun <T> Iterable<ContractState>.sumFungibleOrNull(): <ERROR CLASS>

Sums the asset states in the list, returning null if there are none.


diff --git a/docs/build/html/api/com.r3corda.contracts.cash/kotlin.collections.-iterable/sum-fungible-or-zero.html b/docs/build/html/api/com.r3corda.contracts.cash/kotlin.collections.-iterable/sum-fungible-or-zero.html index 2a2d710875..8b73f5d2b7 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/kotlin.collections.-iterable/sum-fungible-or-zero.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/kotlin.collections.-iterable/sum-fungible-or-zero.html @@ -4,11 +4,11 @@ -com.r3corda.contracts.cash / kotlin.collections.Iterable / sumFungibleOrZero
+com.r3corda.contracts.asset / kotlin.collections.Iterable / sumFungibleOrZero

sumFungibleOrZero

- -fun <T> Iterable<ContractState>.sumFungibleOrZero(token: T): <ERROR CLASS>
+ +fun <T> Iterable<ContractState>.sumFungibleOrZero(token: T): <ERROR CLASS>

Sums the asset states in the list, returning zero of the given token if there are none.



diff --git a/docs/build/html/api/com.r3corda.contracts.cash/kotlin.collections.-iterable/sum-fungible.html b/docs/build/html/api/com.r3corda.contracts.cash/kotlin.collections.-iterable/sum-fungible.html index 52e6305fd7..b594939bb4 100644 --- a/docs/build/html/api/com.r3corda.contracts.cash/kotlin.collections.-iterable/sum-fungible.html +++ b/docs/build/html/api/com.r3corda.contracts.cash/kotlin.collections.-iterable/sum-fungible.html @@ -4,10 +4,10 @@ -com.r3corda.contracts.cash / kotlin.collections.Iterable / sumFungible
+com.r3corda.contracts.asset / kotlin.collections.Iterable / sumFungible

sumFungible

- +fun <T> Iterable<ContractState>.sumFungible(): <ERROR CLASS>

Sums the asset states in the list, throwing an exception if there are none, or if any of the asset states cannot be added together (i.e. are different tokens).

diff --git a/docs/build/html/api/com.r3corda.contracts.testing/index.html b/docs/build/html/api/com.r3corda.contracts.testing/index.html index 0b5757ab5d..6904052376 100644 --- a/docs/build/html/api/com.r3corda.contracts.testing/index.html +++ b/docs/build/html/api/com.r3corda.contracts.testing/index.html @@ -37,13 +37,13 @@ +infix fun State.issued by(party: Party): State diff --git a/docs/build/html/api/com.r3corda.contracts.testing/issued by.html b/docs/build/html/api/com.r3corda.contracts.testing/issued by.html index 22c2c6ca4b..ef47702d38 100644 --- a/docs/build/html/api/com.r3corda.contracts.testing/issued by.html +++ b/docs/build/html/api/com.r3corda.contracts.testing/issued by.html @@ -7,8 +7,8 @@ com.r3corda.contracts.testing / issued by

issued by

- -infix fun State.issued by(party: Party): State
+ +infix fun State.issued by(party: Party): State


diff --git a/docs/build/html/api/com.r3corda.contracts.testing/owned by.html b/docs/build/html/api/com.r3corda.contracts.testing/owned by.html index 2f3420c01e..ed366ba82a 100644 --- a/docs/build/html/api/com.r3corda.contracts.testing/owned by.html +++ b/docs/build/html/api/com.r3corda.contracts.testing/owned by.html @@ -7,8 +7,8 @@ com.r3corda.contracts.testing / owned by

owned by

- -infix fun State.owned by(owner: PublicKey): State
+ +infix fun State.owned by(owner: PublicKey): State
infix fun State.owned by(owner: PublicKey): State
diff --git a/docs/build/html/api/com.r3corda.contracts/-commercial-paper/generate-redeem.html b/docs/build/html/api/com.r3corda.contracts/-commercial-paper/generate-redeem.html index 210b83543f..26faf02ea0 100644 --- a/docs/build/html/api/com.r3corda.contracts/-commercial-paper/generate-redeem.html +++ b/docs/build/html/api/com.r3corda.contracts/-commercial-paper/generate-redeem.html @@ -7,8 +7,8 @@ com.r3corda.contracts / CommercialPaper / generateRedeem

generateRedeem

- -fun generateRedeem(tx: TransactionBuilder, paper: StateAndRef<State>, wallet: List<StateAndRef<State>>): Unit
+ +fun generateRedeem(tx: TransactionBuilder, paper: StateAndRef<State>, wallet: List<StateAndRef<State>>): Unit

Intended to be called by the issuer of some commercial paper, when an owner has notified us that they wish to redeem the paper. We must therefore send enough money to the key that owns the paper to satisfy the face value, and then ensure the paper is removed from the ledger.

diff --git a/docs/build/html/api/com.r3corda.contracts/-commercial-paper/index.html b/docs/build/html/api/com.r3corda.contracts/-commercial-paper/index.html index 953611e3f8..09e0690fa6 100644 --- a/docs/build/html/api/com.r3corda.contracts/-commercial-paper/index.html +++ b/docs/build/html/api/com.r3corda.contracts/-commercial-paper/index.html @@ -74,7 +74,7 @@ at the moment: this restriction is not fundamental and may be lifted later.

diff --git a/docs/build/html/api/index.html b/docs/build/html/api/index.html index 89d4c0fbf7..b1fd259ca0 100644 --- a/docs/build/html/api/index.html +++ b/docs/build/html/api/index.html @@ -17,7 +17,7 @@ +com.r3corda.contracts.asset diff --git a/node/src/main/kotlin/com/r3corda/node/services/wallet/CashBalanceAsMetricsObserver.kt b/node/src/main/kotlin/com/r3corda/node/services/wallet/CashBalanceAsMetricsObserver.kt index 8f0df76574..336b962569 100644 --- a/node/src/main/kotlin/com/r3corda/node/services/wallet/CashBalanceAsMetricsObserver.kt +++ b/node/src/main/kotlin/com/r3corda/node/services/wallet/CashBalanceAsMetricsObserver.kt @@ -1,7 +1,7 @@ package com.r3corda.node.services.wallet import com.codahale.metrics.Gauge -import com.r3corda.contracts.cash.cashBalances +import com.r3corda.contracts.asset.cashBalances import com.r3corda.core.node.services.Wallet import com.r3corda.node.services.api.ServiceHubInternal import java.util.* diff --git a/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt b/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt index 0934eed820..3f3629008b 100644 --- a/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt +++ b/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt @@ -2,7 +2,7 @@ package com.r3corda.node.messaging import com.google.common.util.concurrent.ListenableFuture import com.r3corda.contracts.CommercialPaper -import com.r3corda.contracts.cash.Cash +import com.r3corda.contracts.asset.Cash import com.r3corda.contracts.testing.CASH import com.r3corda.contracts.testing.`issued by` import com.r3corda.contracts.testing.`owned by` diff --git a/node/src/test/kotlin/com/r3corda/node/services/NodeInterestRatesTest.kt b/node/src/test/kotlin/com/r3corda/node/services/NodeInterestRatesTest.kt index 2cb5ba4f38..3e25f4326c 100644 --- a/node/src/test/kotlin/com/r3corda/node/services/NodeInterestRatesTest.kt +++ b/node/src/test/kotlin/com/r3corda/node/services/NodeInterestRatesTest.kt @@ -1,6 +1,6 @@ package com.r3corda.node.services -import com.r3corda.contracts.cash.Cash +import com.r3corda.contracts.asset.Cash import com.r3corda.contracts.testing.CASH import com.r3corda.contracts.testing.`issued by` import com.r3corda.contracts.testing.`owned by` diff --git a/node/src/test/kotlin/com/r3corda/node/services/WalletWithCashTest.kt b/node/src/test/kotlin/com/r3corda/node/services/WalletWithCashTest.kt index 3cfe70e806..ce48cae626 100644 --- a/node/src/test/kotlin/com/r3corda/node/services/WalletWithCashTest.kt +++ b/node/src/test/kotlin/com/r3corda/node/services/WalletWithCashTest.kt @@ -1,7 +1,7 @@ package com.r3corda.node.services -import com.r3corda.contracts.cash.Cash -import com.r3corda.contracts.cash.cashBalances +import com.r3corda.contracts.asset.Cash +import com.r3corda.contracts.asset.cashBalances import com.r3corda.contracts.testing.fillWithSomeTestCash import com.r3corda.core.contracts.* import com.r3corda.core.crypto.SecureHash diff --git a/src/main/kotlin/com/r3corda/demos/RateFixDemo.kt b/src/main/kotlin/com/r3corda/demos/RateFixDemo.kt index e795510e85..96473b033c 100644 --- a/src/main/kotlin/com/r3corda/demos/RateFixDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/RateFixDemo.kt @@ -1,7 +1,7 @@ package com.r3corda.demos import com.google.common.net.HostAndPort -import com.r3corda.contracts.cash.Cash +import com.r3corda.contracts.asset.Cash import com.r3corda.core.contracts.* import com.r3corda.core.crypto.Party import com.r3corda.core.hours diff --git a/src/main/kotlin/com/r3corda/demos/TraderDemo.kt b/src/main/kotlin/com/r3corda/demos/TraderDemo.kt index c15bfd82e7..0d29284155 100644 --- a/src/main/kotlin/com/r3corda/demos/TraderDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/TraderDemo.kt @@ -3,7 +3,7 @@ package com.r3corda.demos import co.paralleluniverse.fibers.Suspendable import com.google.common.net.HostAndPort import com.r3corda.contracts.CommercialPaper -import com.r3corda.contracts.cash.cashBalances +import com.r3corda.contracts.asset.cashBalances import com.r3corda.contracts.testing.fillWithSomeTestCash import com.r3corda.core.contracts.* import com.r3corda.core.crypto.Party From 4356cef1cd811cb3b44b2a9b87ceb955d7d8263e Mon Sep 17 00:00:00 2001 From: Mike Hearn Date: Thu, 30 Jun 2016 14:49:28 +0200 Subject: [PATCH 071/114] Regen docsite --- docs/build/html/_sources/codestyle.txt | 35 + docs/build/html/_sources/consensus.txt | 147 +- docs/build/html/_sources/event-scheduling.txt | 102 + docs/build/html/_sources/index.txt | 1 + docs/build/html/_sources/inthebox.txt | 45 +- docs/build/html/_sources/release-notes.txt | 67 +- .../build/html/_sources/running-the-demos.txt | 4 +- .../html/_sources/transaction-data-types.txt | 19 +- docs/build/html/api/alltypes/index.html | 438 +- .../-c-a-s-h_-p-r-o-g-r-a-m_-i-d.html | 15 + .../-cash/-commands/-exit/-init-.html | 16 + .../-cash/-commands/-exit/amount.html | 16 + .../-cash/-commands/-exit/index.html | 40 + .../-cash/-commands/-issue/-init-.html | 16 + .../-cash/-commands/-issue/index.html | 40 + .../-cash/-commands/-issue/nonce.html | 16 + .../-cash/-commands/-move/-init-.html | 20 + .../-cash/-commands/-move/contract-hash.html | 18 + .../-cash/-commands/-move/index.html | 45 + .../-cash/-commands/index.html | 70 + .../-cash/-init-.html | 25 + .../-cash/-state/-init-.html | 18 + .../-cash/-state/amount.html | 16 + .../-cash/-state/contract.html | 43 + .../-cash/-state/deposit.html | 20 + .../-cash/-state/index.html | 132 + .../-cash/-state/issuance-def.html | 16 + .../-cash/-state/move.html | 15 + .../-cash/-state/owner.html | 17 + .../-cash/-state/participants.html | 34 + .../-cash/-state/product-amount.html | 16 + .../-cash/-state/to-string.html | 15 + .../-cash/-state/with-new-owner.html | 17 + .../-cash/generate-issue.html | 21 + .../-cash/generate-spend.html | 28 + .../-cash/index.html | 104 + .../-cash/legal-contract-reference.html | 25 + .../-fungible-asset-state/index.html | 106 + .../-fungible-asset-state/issuance-def.html | 15 + .../-fungible-asset-state/move.html | 15 + .../-fungible-asset-state/product-amount.html | 15 + .../-commands/-exit/amount.html | 15 + .../-commands/-exit/index.html | 40 + .../-fungible-asset/-commands/-issue.html | 40 + .../-fungible-asset/-commands/-move.html | 39 + .../-fungible-asset/-commands/index.html | 68 + .../-fungible-asset/-init-.html | 27 + .../-fungible-asset/-state/amount.html | 15 + .../-fungible-asset/-state/deposit.html | 16 + .../-fungible-asset/-state/index.html | 69 + .../-fungible-asset/-state/owner.html | 17 + .../-fungible-asset/index.html | 102 + .../-fungible-asset/verify.html | 17 + .../-init-.html | 14 + .../amount-missing.html | 15 + .../index.html | 36 + ...b-l-i-g-a-t-i-o-n_-p-r-o-g-r-a-m_-i-d.html | 15 + .../-bilateral-net-state/-init-.html | 17 + .../-bilateral-net-state/index.html | 48 + .../-bilateral-net-state/party-keys.html | 15 + .../-bilateral-net-state/template.html | 16 + .../-obligation/-commands/-exit/-init-.html | 16 + .../-commands/-exit/aggregate-state.html | 16 + .../-obligation/-commands/-exit/amount.html | 15 + .../-obligation/-commands/-exit/index.html | 46 + .../-obligation/-commands/-issue/-init-.html | 16 + .../-commands/-issue/aggregate-state.html | 16 + .../-obligation/-commands/-issue/index.html | 46 + .../-obligation/-commands/-issue/nonce.html | 15 + .../-obligation/-commands/-move/-init-.html | 20 + .../-commands/-move/aggregate-state.html | 16 + .../-commands/-move/contract-hash.html | 18 + .../-obligation/-commands/-move/index.html | 51 + .../-obligation/-commands/-net/-init-.html | 16 + .../-obligation/-commands/-net/index.html | 40 + .../-obligation/-commands/-net/type.html | 15 + .../-commands/-set-lifecycle/-init-.html | 16 + .../-set-lifecycle/aggregate-state.html | 16 + .../-commands/-set-lifecycle/index.html | 52 + .../-commands/-set-lifecycle/inverse.html | 15 + .../-commands/-set-lifecycle/lifecycle.html | 15 + .../-obligation/-commands/-settle/-init-.html | 19 + .../-commands/-settle/aggregate-state.html | 16 + .../-obligation/-commands/-settle/amount.html | 15 + .../-obligation/-commands/-settle/index.html | 49 + .../-obligation/-commands/index.html | 118 + .../-obligation/-init-.html | 21 + .../-issuance-commands/aggregate-state.html | 15 + .../-obligation/-issuance-commands/index.html | 70 + .../-issuance-definition/-init-.html | 20 + .../-issuance-definition/index.html | 62 + .../-issuance-definition/obligor.html | 15 + .../-issuance-definition/template.html | 15 + .../-lifecycle/-d-e-f-a-u-l-t-e-d.html | 16 + .../-obligation/-lifecycle/-n-o-r-m-a-l.html | 15 + .../-obligation/-lifecycle/index.html | 37 + .../-multilateral-net-state/-init-.html | 20 + .../-multilateral-net-state/index.html | 48 + .../-multilateral-net-state/template.html | 16 + .../-obligation/-net-state/index.html | 53 + .../-obligation/-net-state/template.html | 15 + .../-obligation/-state-template/-init-.html | 18 + .../-state-template/acceptable-contracts.html | 16 + .../acceptable-issued-products.html | 16 + .../-state-template/due-before.html | 16 + .../-obligation/-state-template/index.html | 68 + .../-obligation/-state-template/product.html | 15 + .../-state-template/time-tolerance.html | 15 + .../-obligation/-state/-init-.html | 20 + .../-state/acceptable-contracts.html | 15 + .../acceptable-issuance-definitions.html | 15 + .../-obligation/-state/aggregate-state.html | 15 + .../-obligation/-state/amount.html | 15 + .../-obligation/-state/beneficiary.html | 16 + .../-state/bilateral-net-state.html | 22 + .../-obligation/-state/contract.html | 43 + .../-obligation/-state/due-before.html | 15 + .../-obligation/-state/index.html | 209 + .../-obligation/-state/issuance-def.html | 16 + .../-obligation/-state/lifecycle.html | 15 + .../-obligation/-state/move.html | 15 + .../-state/multilateral-net-state.html | 15 + .../-obligation/-state/net.html | 17 + .../-obligation/-state/obligor.html | 16 + .../-obligation/-state/owner.html | 20 + .../-obligation/-state/participants.html | 34 + .../-obligation/-state/product-amount.html | 16 + .../-obligation/-state/quantity.html | 15 + .../-obligation/-state/template.html | 15 + .../-obligation/-state/to-string.html | 15 + .../-obligation/-state/with-new-owner.html | 17 + .../generate-close-out-netting.html | 23 + .../-obligation/generate-issue.html | 16 + .../-obligation/generate-payment-netting.html | 15 + .../-obligation/generate-set-lifecycle.html | 20 + .../-obligation/generate-settle.html | 27 + .../-obligation/index.html | 194 + .../-obligation/legal-contract-reference.html | 25 + .../-obligation/verify-issue-command.html | 15 + .../-obligation/verify-net-command.html | 16 + .../verify-set-lifecycle-command.html | 16 + .../-obligation/verify.html | 17 + .../cash-balances.html | 17 + .../extract-amounts-due.html | 18 + .../com.r3corda.contracts.asset/index.html | 129 + .../kotlin.collections.-iterable/index.html | 98 + .../sum-cash-by.html | 18 + .../sum-cash-or-null.html | 16 + .../sum-cash-or-zero.html | 16 + .../sum-cash.html | 17 + .../sum-fungible-by.html | 18 + .../sum-fungible-or-null.html | 16 + .../sum-fungible-or-zero.html | 16 + .../sum-fungible.html | 17 + .../sum-obligations-or-null.html | 16 + .../sum-obligations-or-zero.html | 16 + .../sum-obligations.html | 16 + .../net-amounts-due.html | 16 + .../sum-amounts-due.html | 21 + .../-c-a-s-h.html | 3 +- .../-d-u-m-m-y_-c-a-s-h_-i-s-s-u-e-r.html | 15 + ...-u-m-m-y_-c-a-s-h_-i-s-s-u-e-r_-k-e-y.html | 15 + .../-java-test-helpers/-c-a-s-h.html | 15 + .../-o-b-l-i-g-a-t-i-o-n.html | 15 + .../-o-b-l-i-g-a-t-i-o-n_-d-e-f.html | 15 + .../-java-test-helpers/-s-t-a-t-e.html | 15 + .../-java-test-helpers/at.html | 17 + .../-java-test-helpers/between.html | 15 + .../-java-test-helpers/index.html | 87 + .../-java-test-helpers/issued-by.html | 19 + .../-java-test-helpers/owned-by.html | 21 + .../-java-test-helpers/with-deposit.html | 15 + .../-java-test-helpers/with-notary.html | 19 + .../-o-b-l-i-g-a-t-i-o-n.html | 15 + .../-o-b-l-i-g-a-t-i-o-n_-d-e-f.html | 16 + .../-s-t-a-t-e.html | 15 + .../api/com.r3corda.contracts.testing/at.html | 17 + .../between.html | 15 + .../fill-with-some-test-cash.html | 25 + .../generate-state.html | 4 +- .../com.r3corda.contracts.testing/index.html | 91 +- .../issued by.html | 6 +- .../owned by.html | 6 +- .../with deposit.html | 15 + .../with notary.html | 19 + .../-commercial-paper/-state/-init-.html | 2 +- .../-commercial-paper/-state/contract.html | 28 +- .../-commercial-paper/-state/face-value.html | 2 +- .../-commercial-paper/-state/index.html | 24 +- .../-state/participants.html | 34 + .../-state/with-face-value.html | 4 +- .../-commercial-paper/generate-issue.html | 4 +- .../-commercial-paper/generate-redeem.html | 2 +- .../-commercial-paper/index.html | 6 +- .../-commercial-paper/verify.html | 4 +- .../-fixed-rate/hash-code.html | 4 +- .../-calculation/next-fixing-date.html | 4 +- .../-floating-leg/-init-.html | 2 +- .../-floating-leg/copy.html | 4 +- .../-floating-leg/fixing-period-offset.html | 15 + .../-floating-leg/index.html | 8 +- .../-interest-rate-swap/-state/-init-.html | 2 +- .../-interest-rate-swap/-state/contract.html | 28 +- .../-state/generate-agreement.html | 4 +- .../-state/generate-fix.html | 4 +- .../-interest-rate-swap/-state/index.html | 23 +- .../-state/next-fixing-of.html | 3 - .../-state/next-scheduled-activity.html | 24 + .../-state/participants.html | 34 + .../-interest-rate-swap/-state/parties.html | 4 +- .../-interest-rate-swap/index.html | 4 +- .../-interest-rate-swap/verify.html | 4 +- .../-rate/hash-code.html | 4 +- .../-amount/index.html | 21 +- .../bilateral-net-state.html | 17 + .../-bilateral-nettable-state/index.html | 55 + .../-bilateral-nettable-state/net.html | 17 + .../-command-data.html | 31 +- .../-contract-state/contract.html | 28 +- .../-contract-state/index.html | 38 +- .../-contract-state/participants.html | 24 + .../-contract/index.html | 20 +- .../-contract/verify.html | 4 +- .../-deal-state/generate-agreement.html | 4 +- .../-deal-state/index.html | 6 +- .../-commands/-move/-init-.html | 14 + .../-commands/-move/index.html | 42 + .../-dummy-contract/-commands/index.html | 12 + .../-multi-owner-state/-init-.html | 17 + .../-multi-owner-state/contract.html | 43 + .../-multi-owner-state/index.html | 62 + .../-multi-owner-state/magic-number.html | 16 + .../-multi-owner-state/owners.html | 15 + .../-multi-owner-state/participants.html | 34 + .../-single-owner-state/-init-.html | 14 + .../-single-owner-state/contract.html | 43 + .../-single-owner-state/index.html | 69 + .../-single-owner-state/magic-number.html | 16 + .../-single-owner-state/owner.html | 17 + .../-single-owner-state/participants.html | 34 + .../-single-owner-state/with-new-owner.html | 17 + .../-dummy-contract/-state/index.html | 58 +- .../-dummy-contract/-state/magic-number.html | 2 +- .../-dummy-contract/index.html | 19 +- .../-dummy-contract/verify.html | 4 +- .../-dummy-state/-init-.html | 15 + .../-dummy-state/contract.html | 43 + .../-dummy-state/index.html | 70 + .../-dummy-state/magic-number.html | 15 + .../-dummy-state/participants.html | 34 + .../-fixable-deal-state/generate-fix.html | 4 +- .../-fixable-deal-state/index.html | 10 +- .../-fixable-deal-state/next-fixing-of.html | 3 - .../-issuance-definition.html | 13 - .../-issue-command/index.html | 39 + .../-issue-command/nonce.html | 15 + .../-issued/-init-.html | 19 + .../-issued/index.html | 61 + .../-issued/issuer.html | 15 + .../-issued/product.html | 15 + .../-java-test-helpers/-c-h-f.html | 15 + .../-java-test-helpers/-d-o-l-l-a-r-s.html | 17 + .../-java-test-helpers/-g-b-p.html | 15 + .../-java-test-helpers/-p-o-u-n-d-s.html | 15 + .../-s-w-i-s-s_-f-r-a-n-c-s.html | 15 + .../-java-test-helpers/-u-s-d.html | 15 + .../-java-test-helpers/index.html | 68 + .../-java-test-helpers/issued-by.html | 17 + .../-ledger-transaction/-init-.html | 2 +- .../-ledger-transaction/index.html | 16 +- .../-ledger-transaction/outputs.html | 2 +- .../-ledger-transaction/signers.html | 15 + .../-ledger-transaction/type.html | 15 + .../-linear-state/index.html | 16 +- .../-move-command/contract-hash.html | 17 + .../-move-command/index.html | 46 + .../-net-type/-c-l-o-s-e_-o-u-t.html | 20 + .../-net-type/-p-a-y-m-e-n-t.html | 16 + .../-net-type/index.html | 41 + .../-ownable-state/index.html | 20 +- .../-schedulable-state/index.html | 77 + .../next-scheduled-activity.html | 23 + .../-scheduled-activity/-init-.html | 23 + .../-scheduled-activity/index.html | 53 + .../-scheduled-activity/logic-ref.html | 15 + .../-scheduled-activity/scheduled-at.html | 16 + .../-scheduled-state-ref/-init-.html | 20 + .../-scheduled-state-ref/index.html | 50 + .../-scheduled-state-ref/ref.html | 15 + .../-scheduled-state-ref/scheduled-at.html | 16 + .../-scheduled/index.html | 47 + .../-scheduled/scheduled-at.html | 15 + .../get-missing-signatures.html | 3 +- .../-signed-transaction/index.html | 13 +- .../-signed-transaction/plus.html | 4 + .../-signed-transaction/tx.html | 4 +- .../-signed-transaction/verify.html | 2 +- .../with-additional-signatures.html | 15 + .../-state-and-ref/-init-.html | 2 +- .../-state-and-ref/index.html | 4 +- .../-state-and-ref/state.html | 2 +- .../-transaction-builder/-init-.html | 16 +- .../-transaction-builder/add-input-state.html | 4 +- .../add-output-state.html | 7 + .../-transaction-builder/attachments.html | 2 + .../-transaction-builder/commands.html | 2 + .../-transaction-builder/current-sigs.html | 16 + .../-transaction-builder/index.html | 100 +- .../-transaction-builder/inputs.html | 15 + .../-transaction-builder/notary.html | 15 + .../-transaction-builder/output-states.html | 2 +- .../-transaction-builder/outputs.html | 15 + .../-transaction-builder/signers.html | 15 + .../-transaction-builder/type.html | 15 + .../-in-out-group/-init-.html | 19 + .../-in-out-group/grouping-key.html | 15 + .../-in-out-group/index.html | 58 + .../-in-out-group/inputs.html | 15 + .../-in-out-group/outputs.html | 15 + .../-transaction-for-contract/-init-.html | 16 + .../attachments.html | 15 + .../-transaction-for-contract/commands.html | 15 + .../-transaction-for-contract/equals.html | 15 + .../get-timestamp-by-name.html | 16 + .../get-timestamp-by.html | 16 + .../group-commands.html | 15 + .../group-states-internal.html | 17 + .../group-states.html | 33 + .../-transaction-for-contract/hash-code.html | 15 + .../-transaction-for-contract/in-states.html | 17 + .../-transaction-for-contract/index.html | 145 + .../-transaction-for-contract/inputs.html | 15 + .../-transaction-for-contract/orig-hash.html | 15 + .../-transaction-for-contract/out-states.html | 17 + .../-transaction-for-contract/outputs.html | 15 + .../-transaction-for-verification/-init-.html | 2 +- .../-transaction-for-verification/index.html | 76 +- .../-transaction-for-verification/inputs.html | 15 + .../outputs.html | 15 + .../signers.html | 15 + .../to-transaction-for-contract.html | 15 + .../-transaction-for-verification/type.html | 15 + .../-transaction-for-verification/verify.html | 11 +- .../-transaction-graph-search/-init-.html | 2 +- .../-transaction-graph-search/index.html | 4 +- .../transactions.html | 2 +- .../-transaction-state/-init-.html | 16 + .../-transaction-state/data.html | 16 + .../-transaction-state/index.html | 72 + .../-transaction-state/notary.html | 16 + .../-transaction-state/with-new-notary.html | 17 + .../-general/-builder/-init-.html | 15 + .../-general/-builder/index.html | 200 + .../-transaction-type/-general/-init-.html | 15 + .../-general/get-required-signers.html | 18 + .../-transaction-type/-general/index.html | 91 + .../-general/verify-transaction.html | 18 + .../-notary-change/-builder/-init-.html | 16 + .../-builder/add-input-state.html | 16 + .../-notary-change/-builder/index.html | 207 + .../-notary-change/-init-.html | 16 + .../-notary-change/get-required-signers.html | 18 + .../-notary-change/index.html | 94 + .../-notary-change/verify-transaction.html | 18 + .../-transaction-type/equals.html | 15 + .../get-required-signers.html | 17 + .../-transaction-type/hash-code.html | 15 + .../-transaction-type/index.html | 101 + .../-transaction-type/verify-signers.html | 16 + .../-transaction-type/verify-transaction.html | 16 + .../-transaction-type/verify.html | 21 + .../-invalid-notary-change/-init-.html | 14 + .../-invalid-notary-change/index.html | 36 + .../-signers-missing/-init-.html | 14 + .../-signers-missing/index.html | 36 + .../index.html | 24 + .../-type-only-command-data/index.html | 4 +- .../-wire-transaction/-init-.html | 2 +- .../-wire-transaction/index.html | 16 +- .../-wire-transaction/outputs.html | 2 +- .../-wire-transaction/signers.html | 15 + .../-wire-transaction/type.html | 15 + .../com.r3corda.core.contracts/currency.html | 2 +- .../api/com.r3corda.core.contracts/index.html | 140 +- .../com.r3corda.core.contracts/issued by.html | 15 + .../java.util.-currency/index.html | 21 + .../java.util.-currency/issued by.html | 15 + .../verify-move-command.html | 21 + .../generate-key-pair.html | 2 +- .../api/com.r3corda.core.crypto/index.html | 8 +- .../new-secure-random.html | 15 + .../api/com.r3corda.core.messaging/-ack.html | 16 + .../api/com.r3corda.core.messaging/index.html | 8 + .../-mock-attachment-storage/index.html | 6 +- .../open-attachment.html | 6 +- .../-mock-storage-service/index.html | 2 +- .../validated-transactions.html | 2 +- .../get-transaction.html | 2 +- .../index.html | 2 +- .../-attachment-storage/index.html | 9 +- .../-attachment-storage/open-attachment.html | 6 +- .../get-transaction.html | 16 + .../-read-only-transaction-storage/index.html | 39 + .../-scheduler-service/index.html | 53 + .../schedule-state-activity.html | 20 + .../unschedule-state-activity.html | 16 + .../-storage-service/index.html | 13 +- .../validated-transactions.html | 2 +- .../-transaction-storage/index.html | 11 +- .../-tx-writable-storage-service/index.html | 72 + .../validated-transactions.html | 19 + .../-uniqueness-provider/commit.html | 4 +- .../-uniqueness-provider/index.html | 2 +- .../-wallet-service/index.html | 21 +- .../-wallet-service/states-for-refs.html | 2 +- .../-wallet-service/when-consumed.html | 16 + .../-wallet/-init-.html | 7 +- .../-wallet/index.html | 40 +- .../-wallet/states.html | 2 +- .../com.r3corda.core.node.services/index.html | 29 +- .../-service-hub/index.html | 27 +- .../-service-hub/load-state.html | 2 +- .../-service-hub/record-transactions.html | 12 +- .../-service-hub/scheduler-service.html | 15 + .../-app-context/-init-.html | 16 + .../-app-context/attachments.html | 15 + .../-app-context/class-loader.html | 15 + .../-app-context/index.html | 46 + .../-init-.html | 14 + .../index.html | 25 + .../-protocol-logic-ref-factory/-init-.html | 26 + .../create-kotlin.html | 19 + .../-protocol-logic-ref-factory/create.html | 16 + .../-protocol-logic-ref-factory/index.html | 71 + .../to-protocol-logic.html | 15 + .../-protocol-logic-ref/app-context.html | 15 + .../-protocol-logic-ref/args.html | 15 + .../-protocol-logic-ref/index.html | 41 + .../protocol-logic-class-name.html | 15 + .../-protocol-logic/index.html | 49 +- .../-protocol-logic/send-and-receive.html | 4 +- .../-protocol-logic/send.html | 4 +- .../-protocol-logic/service-hub.html | 4 +- .../-protocol-state-machine/index.html | 4 +- .../send-and-receive.html | 4 +- .../-protocol-state-machine/send.html | 4 +- .../api/com.r3corda.core.protocols/index.html | 33 + .../-deserialize-as-kotlin-object-def.html | 28 + .../ed25519-curve.html | 15 + .../index.html | 43 + .../-ed25519-private-key-serializer/read.html | 15 + .../write.html | 15 + .../ed25519-curve.html | 15 + .../-ed25519-public-key-serializer/index.html | 43 + .../-ed25519-public-key-serializer/read.html | 15 + .../-ed25519-public-key-serializer/write.html | 15 + .../-kotlin-object-serializer/index.html | 32 + .../-kotlin-object-serializer/read.html | 15 + .../-kotlin-object-serializer/write.html | 15 + .../-serialize-as-token/index.html | 7 + .../-singleton-serialize-as-token/index.html | 34 +- .../com.r3corda.core.serialization/index.html | 40 + .../read-bytes-with-length.html | 15 + .../write-bytes-with-length.html | 15 + .../-a-l-l_-t-e-s-t_-k-e-y-s.html | 2 +- .../add-command.html | 15 + .../-abstract-transaction-for-test/arg.html | 4 +- .../-abstract-transaction-for-test/index.html | 26 +- .../output.html | 2 + .../signers.html | 15 + .../transaction.html | 4 +- .../-abstract-transaction-for-test/type.html | 15 + .../-always-succeed-contract/-init-.html | 14 + .../-always-succeed-contract/index.html | 53 + .../legal-contract-reference.html | 18 + .../-always-succeed-contract/verify.html | 20 + .../-d-u-m-m-y_-p-u-b-k-e-y_1.html | 2 +- .../-d-u-m-m-y_-p-u-b-k-e-y_2.html | 2 +- .../-dummy-linear-state/-init-.html | 14 + .../-dummy-linear-state/contract.html | 43 + .../-dummy-linear-state/index.html | 87 + .../-dummy-linear-state/is-relevant.html | 17 + .../-dummy-linear-state/nonce.html | 15 + .../-dummy-linear-state/participants.html | 25 + .../-dummy-linear-state/thread.html | 17 + .../-clashing-threads/-init-.html | 14 + .../-clashing-threads/index.html | 25 + .../-in-memory-wallet-service/-init-.html | 17 + .../clashing-threads.html | 15 + .../current-wallet.html | 22 + .../-in-memory-wallet-service/index.html | 156 + .../linear-heads.html | 20 + .../-in-memory-wallet-service/notify-all.html | 22 + .../-in-memory-wallet-service/updates.html | 22 + .../-java-test-helpers/-a-l-i-c-e.html | 15 + .../-java-test-helpers/-a-l-i-c-e_-k-e-y.html | 15 + .../-a-l-i-c-e_-p-u-b-k-e-y.html | 15 + .../-a-l-l_-t-e-s-t_-k-e-y-s.html | 15 + .../-java-test-helpers/-b-o-b.html | 15 + .../-java-test-helpers/-b-o-b_-k-e-y.html | 15 + .../-b-o-b_-p-u-b-k-e-y.html | 15 + .../-d-u-m-m-y_-n-o-t-a-r-y.html | 15 + .../-d-u-m-m-y_-n-o-t-a-r-y_-k-e-y.html | 15 + .../-d-u-m-m-y_-p-u-b-k-e-y_1.html | 15 + .../-d-u-m-m-y_-p-u-b-k-e-y_2.html | 15 + .../-java-test-helpers/-m-e-g-a_-c-o-r-p.html | 15 + .../-m-e-g-a_-c-o-r-p_-k-e-y.html | 15 + .../-m-e-g-a_-c-o-r-p_-p-u-b-k-e-y.html | 15 + .../-java-test-helpers/-m-i-n-i_-c-o-r-p.html | 15 + .../-m-i-n-i_-c-o-r-p_-k-e-y.html | 15 + .../-m-i-n-i_-c-o-r-p_-p-u-b-k-e-y.html | 15 + ...o-c-k_-i-d-e-n-t-i-t-y_-s-e-r-v-i-c-e.html | 15 + .../-o-r-a-c-l-e_-k-e-y.html | 15 + .../-o-r-a-c-l-e_-p-u-b-k-e-y.html | 15 + .../-t-e-s-t_-t-x_-t-i-m-e.html | 15 + .../generate-state-ref.html | 15 + .../-java-test-helpers/index.html | 179 + .../-java-test-helpers/transaction.html | 15 + .../-labeled-output/-init-.html | 2 +- .../-labeled-output/index.html | 4 +- .../-labeled-output/state.html | 2 +- ...ine-should-test-for-accept-or-failure.html | 18 + .../-test-utils/index.html | 6 +- .../-test-utils/keypair.html | 2 +- .../-test-utils/keypair2.html | 2 +- .../-test-utils/keypair3.html | 2 +- .../-transaction-for-test/accepts.html | 2 +- .../-transaction-for-test/chain.html | 4 +- .../fails requirement.html | 2 +- .../fails-requirement.html | 15 + .../-transaction-for-test/index.html | 43 +- .../-transaction-for-test/input.html | 4 +- .../-transaction-for-test/rejects.html | 2 +- .../-transaction-for-test/tweak.html | 4 +- .../-roots/index.html | 7 +- .../-roots/roots.html | 1 + .../-roots/transaction.html | 5 +- .../-wire-transaction-d-s-l/index.html | 26 +- .../-transaction-group-d-s-l/index.html | 7 +- .../label-for-state.html | 4 +- .../-transaction-group-d-s-l/output.html | 2 +- .../transaction-group.html | 1 + .../api/com.r3corda.core.testing/index.html | 48 +- .../api/com.r3corda.core.testing/label.html | 4 +- .../com.r3corda.core.testing/transaction.html | 4 +- .../-non-empty-set-serializer/index.html | 33 + .../-non-empty-set-serializer/read.html | 15 + .../-non-empty-set-serializer/write.html | 15 + .../-non-empty-set/-init-.html | 5 +- .../-non-empty-set/index.html | 22 +- .../-progress-tracker/-step/index.html | 66 +- .../-time-window/-init-.html | 15 + .../-time-window/duration.html | 15 + .../-time-window/end.html | 15 + .../-time-window/index.html | 50 + .../-time-window/start.html | 15 + .../api/com.r3corda.core.utilities/index.html | 27 +- ...nterest-rate-announcement-time-window.html | 18 + .../-retryable-exception/index.html | 11 + .../com.r3corda.core/-thread-box/-init-.html | 2 +- .../-thread-box/already-locked.html | 15 + .../com.r3corda.core/-thread-box/index.html | 10 +- .../com.r3corda.core/-thread-box/lock.html | 2 +- .../-auto-offer-message/-init-.html | 2 +- .../-auto-offer-message/index.html | 10 +- .../-auto-offer-message/notary.html | 15 + .../-auto-offer-message/other-side.html | 2 +- .../-requester/index.html | 10 +- .../-auto-offer-protocol/index.html | 2 +- .../-broadcast/index.html | 8 +- .../-broadcast/call.html | 2 +- .../-broadcast/index.html | 18 +- .../-update-business-day-message/-init-.html | 2 +- .../-update-business-day-message/index.html | 8 +- .../-update-business-day-protocol/index.html | 11 +- .../com.r3corda.demos.protocols/index.html | 3 +- .../-cli-params-spec/api-address-arg.html | 15 + .../-cli-params-spec/base-directory-arg.html | 15 + .../fake-trade-with-addr.html | 15 + .../fake-trade-with-identity-file.html | 15 + .../-cli-params-spec/index.html | 79 + .../-cli-params-spec/network-address-arg.html | 15 + .../network-map-identity-file.html | 15 + .../network-map-net-addr.html | 15 + .../-cli-params-spec/non-options.html | 15 + .../-cli-params-spec/parser.html | 15 + .../-cli-params-spec/role-arg.html | 15 + .../-cli-params/-date-change/-init-.html | 15 + .../-cli-params/-date-change/api-address.html | 15 + .../-cli-params/-date-change/date-string.html | 15 + .../-cli-params/-date-change/index.html | 44 + .../-cli-params/-run-node/-init-.html | 15 + .../-cli-params/-run-node/api-address.html | 15 + .../-cli-params/-run-node/auto-setup.html | 15 + .../-run-node/default-legal-name.html | 15 + .../-cli-params/-run-node/dir.html | 15 + .../-cli-params/-run-node/identity-file.html | 15 + .../-cli-params/-run-node/index.html | 98 + .../-cli-params/-run-node/map-address.html | 15 + .../-run-node/network-address.html | 15 + .../-cli-params/-run-node/node.html | 15 + .../-run-node/trade-with-addrs.html | 15 + .../-run-node/trade-with-identities.html | 15 + .../-cli-params/-run-node/upload-rates.html | 15 + .../-cli-params/-setup-node/-init-.html | 15 + .../-setup-node/default-legal-name.html | 15 + .../-cli-params/-setup-node/dir.html | 15 + .../-cli-params/-setup-node/index.html | 50 + .../-cli-params/-setup-node/node.html | 15 + .../-cli-params/-trade/-init-.html | 15 + .../-cli-params/-trade/api-address.html | 15 + .../-cli-params/-trade/index.html | 44 + .../-cli-params/-trade/trade-id.html | 15 + .../-cli-params/default-base-directory.html | 15 + .../com.r3corda.demos/-cli-params/index.html | 109 + .../-cli-params/legal-name.html | 15 + .../com.r3corda.demos/-cli-params/parse.html | 15 + ...f-a-u-l-t_-b-a-s-e_-d-i-r-e-c-t-o-r-y.html | 15 + .../-i-r-s-demo-node/-node-a.html | 25 + .../-i-r-s-demo-node/-node-b.html | 25 + .../-i-r-s-demo-node/index.html | 42 + .../-i-r-s-demo-node/other.html | 15 + .../-i-r-s-demo-role/index.html | 7 + .../html/api/com.r3corda.demos/index.html | 62 +- .../api/com.r3corda.demos/run-i-r-s-demo.html | 15 + .../com.r3corda.demos/run-trader-demo.html | 15 + .../-a-p-i-server/fetch-states.html | 2 +- .../-a-p-i-server/fetch-transactions.html | 4 +- .../-a-p-i-server/index.html | 9 +- .../-a-p-i-server/query-states.html | 4 +- .../-a-p-i-server/status.html | 16 + .../-i-r-s-simulation/-init-.html | 2 +- .../-i-r-s-simulation/index.html | 30 +- .../-i-r-s-simulation/iterate.html | 4 +- .../-mock-network/-init-.html | 2 +- .../-mock-network/-mock-node/index.html | 23 +- .../-mock-network/index.html | 2 +- .../-simulation/-init-.html | 2 +- .../-simulation/clocks.html | 15 + .../-simulation/current-date-and-time.html | 17 + .../-simulation/date-changes.html | 2 +- .../-simulation/index.html | 30 +- .../-simulation/iterate.html | 4 +- .../network-send-manually-pumped.html | 15 + .../-simulation/show-consensus-for.html | 15 + .../-simulation/show-progress-for.html | 15 + .../-simulation/start-trading-circle.html | 4 +- .../-test-clock/advance-by.html | 3 +- .../-test-clock/index.html | 20 +- .../-test-clock/set-to.html | 19 + .../-test-clock/to-token.html | 16 + .../-test-clock/with-zone.html | 4 +- .../-trade-simulation/index.html | 28 +- .../index.html | 21 +- .../issue-invalid-state.html | 2 +- .../issue-multi-party-state.html | 15 + .../issue-state.html | 4 +- .../kotlin.collections.-iterable/index.html | 23 + .../kotlin.collections.-iterable/set-to.html | 17 + .../-a-p-i-server-impl/fetch-states.html | 2 +- .../fetch-transactions.html | 4 +- .../-a-p-i-server-impl/index.html | 9 +- .../-a-p-i-server-impl/query-states.html | 4 +- .../-a-p-i-server-impl/status.html | 17 + .../-abstract-node/create-node-dir.html | 15 + .../-abstract-node/generate-key-pair.html | 2 +- .../-abstract-node/index.html | 25 +- .../initialise-storage-service.html | 2 +- .../-abstract-node/scheduler.html | 15 + .../-abstract-node/setup.html | 16 + .../-abstract-node/storage.html | 2 +- .../-node/-init-.html | 2 +- .../-node/index.html | 33 +- .../-node/setup.html | 17 + .../-node/web-server-addr.html | 15 + .../-abstract-node-service/-init-.html | 2 +- .../add-message-handler.html | 14 +- .../-abstract-node-service/index.html | 39 +- .../network-map-cache.html | 15 + .../-service-hub-internal/-init-.html | 14 + .../-service-hub-internal/index.html | 58 +- .../protocol-logic-ref-factory.html | 15 + .../-service-hub-internal/start-protocol.html | 18 + .../com.r3corda.node.services.api/index.html | 4 +- .../-node-interest-rates/-oracle/-init-.html | 2 +- .../-node-interest-rates/-oracle/clock.html | 15 + .../-node-interest-rates/-oracle/index.html | 13 +- .../-node-interest-rates/-oracle/query.html | 7 +- .../-node-interest-rates/-service/index.html | 16 +- .../-unknown-fix/index.html | 13 +- .../-node-interest-rates/index.html | 2 +- .../-node-scheduler-service/-init-.html | 35 + .../-node-scheduler-service/index.html | 78 + .../schedule-state-activity.html | 21 + .../unschedule-state-activity.html | 17 + .../-scheduled-activity-observer/-init-.html | 16 + .../-scheduled-activity-observer/index.html | 40 + .../services.html | 15 + .../index.html | 32 + .../-init-.html | 2 +- .../index.html | 2 +- .../keys.html | 4 +- .../-in-memory-messaging/index.html | 4 +- .../-in-memory-messaging/pump-receive.html | 20 + .../-in-memory-messaging-network/-init-.html | 2 +- .../create-node.html | 2 +- .../-in-memory-messaging-network/index.html | 41 +- .../pump-send-internal.html | 15 + .../pump-send.html | 15 + .../received-messages.html | 16 + .../send-manually-pumped.html | 15 + .../sent-messages.html | 16 + .../network-map-nodes.html | 4 +- .../notary-nodes.html | 4 +- .../party-nodes.html | 4 +- .../rates-oracle-nodes.html | 4 +- .../regulators.html | 4 +- .../-in-memory-network-map-service/index.html | 16 +- .../-fetch-map-request/index.html | 19 +- .../-fetch-map-request/session-i-d.html | 16 + .../-network-map-request-message/-init-.html | 14 + .../get-reply-to.html | 16 + .../-network-map-request-message/index.html | 87 + .../reply-to.html | 15 + .../-query-identity-request/index.html | 19 +- .../-query-identity-request/session-i-d.html | 16 + .../-registration-request/index.html | 19 +- .../-registration-request/session-i-d.html | 16 + .../-subscribe-request/index.html | 19 +- .../-subscribe-request/session-i-d.html | 16 + .../-network-map-service/index.html | 14 +- .../-data-vending-service/-init-.html | 2 +- .../-data-vending-service/index.html | 18 +- .../-node-attachment-service/index.html | 6 +- .../open-attachment.html | 6 +- .../checkpoints.html | 4 +- .../get-transaction.html | 2 +- .../-storage-service-impl/index.html | 2 +- .../validated-transactions.html | 2 +- .../index.html | 2 +- .../-protocol-state-machine-impl/index.html | 10 +- .../send-and-receive.html | 4 +- .../-protocol-state-machine-impl/send.html | 4 +- .../-expecting-response/-init-.html | 2 +- .../-expecting-response/index.html | 4 +- .../-fiber-request/-init-.html | 2 +- .../-not-expecting-response/-init-.html | 2 +- .../-not-expecting-response/index.html | 4 +- .../-fiber-request/destination.html | 2 +- .../-fiber-request/index.html | 4 +- .../commit.html | 4 +- .../-in-memory-uniqueness-provider/index.html | 2 +- .../-notary-service/-init-.html | 2 +- .../-notary-service/index.html | 18 +- .../-simple-notary-service/-init-.html | 2 +- .../-simple-notary-service/index.html | 2 +- .../-validating-notary-service/-init-.html | 2 +- .../-validating-notary-service/index.html | 2 +- .../-node-wallet-service/-init-.html | 7 +- .../-node-wallet-service/index.html | 71 +- .../index.html | 15 +- .../index.html | 30 + .../register.html | 15 + .../-notary-change-service/-init-.html | 16 + .../-notary-change-service/index.html | 74 + .../-notary-change-service/smm.html | 15 + .../api/com.r3corda.node.services/index.html | 32 + .../-gate/is-on-thread.html | 4 +- .../is-on-thread.html | 4 +- .../-public-key-deserializer/deserialize.html | 15 + .../-public-key-deserializer/index.html | 25 + .../-public-key-serializer/index.html | 25 + .../-public-key-serializer/serialize.html | 15 + .../-json-support/index.html | 12 + .../-mutable-clock/index.html | 2 +- .../-mutable-clock/mutations.html | 4 +- .../java.time.-clock/await-with-deadline.html | 4 +- .../-abstract-request-message/-init-.html | 4 +- .../get-reply-to.html | 16 + .../-abstract-request-message/index.html | 54 +- .../reply-to-party.html | 15 + .../-fetch-attachments-protocol/-init-.html | 2 +- .../-fetch-attachments-protocol/index.html | 4 +- .../-fetch-data-protocol/-init-.html | 2 +- .../-fetch-data-protocol/-request/-init-.html | 2 +- .../-fetch-data-protocol/-request/index.html | 21 +- .../-request/session-i-d.html | 16 + .../-fetch-data-protocol/index.html | 12 +- .../-fetch-data-protocol/other-side.html | 2 +- .../-fetch-transactions-protocol/-init-.html | 2 +- .../-fetch-transactions-protocol/index.html | 4 +- .../-signatures-missing/-init-.html | 14 + .../-signatures-missing/index.html | 36 + .../-signatures-missing/missing-signers.html | 15 + .../-notary-error/index.html | 12 + .../-notary-protocol/-client/-init-.html | 2 +- .../-notary-protocol/-client/index.html | 18 +- .../-client/notary-party.html | 15 + .../-default-factory/create.html | 4 +- .../-default-factory/index.html | 2 +- .../-notary-protocol/-factory/create.html | 4 +- .../-notary-protocol/-factory/index.html | 2 +- .../-notary-protocol/-handshake/-init-.html | 2 +- .../-notary-protocol/-handshake/index.html | 21 +- .../-handshake/session-i-d.html | 16 + .../-notary-protocol/-service/-init-.html | 2 +- .../-service/before-commit.html | 4 +- .../-notary-protocol/-service/index.html | 14 +- .../-notary-protocol/-service/other-side.html | 2 +- .../-sign-request/-init-.html | 2 +- .../-notary-protocol/-sign-request/index.html | 6 +- .../-notary-protocol/-sign-request/tx.html | 15 + .../-rates-fix-protocol/-init-.html | 2 +- .../-query-request/-init-.html | 2 +- .../-query-request/deadline.html | 15 + .../-query-request/index.html | 27 +- .../-query-request/session-i-d.html | 16 + .../-sign-request/-init-.html | 2 +- .../-sign-request/index.html | 21 +- .../-sign-request/session-i-d.html | 16 + .../-rates-fix-protocol/index.html | 14 +- .../-init-.html | 6 +- .../-resolve-transactions-protocol/index.html | 16 +- .../get-reply-to.html | 15 + .../-service-request-message/index.html | 55 + .../-service-request-message/session-i-d.html | 15 + .../-acceptor/-init-.html | 2 +- .../-acceptor/index.html | 35 +- .../-acceptor/notary.html | 15 + .../-acceptor/other-side.html | 16 + .../-acceptor/session-i-d.html | 16 + .../-f-i-x_-i-n-i-t-i-a-t-e_-t-o-p-i-c.html | 16 + .../-fixer/-init-.html | 4 +- .../-fixer/assemble-shared-t-x.html | 2 +- .../-fixer/index.html | 53 +- .../-fixer/initiation.html | 15 + .../-fixer/other-side.html | 16 + .../-fixer/progress-tracker.html | 2 +- .../-fixer/session-i-d.html | 16 + .../-fixer/validate-handshake.html | 2 +- .../-fixing-role-decider/-init-.html | 21 + .../-l-o-a-d-i-n-g/-init-.html | 14 + .../-l-o-a-d-i-n-g/index.html | 53 + .../-fixing-role-decider/call.html | 17 + .../-fixing-role-decider/index.html | 154 + .../progress-tracker.html | 24 + .../-fixing-role-decider/ref.html | 15 + .../-fixing-role-decider/timeout.html | 15 + .../-fixing-role-decider/tracker.html | 15 + .../-fixing-session-initiation/-init-.html | 15 + .../-fixing-session-initiation/index.html | 56 + .../-fixing-session-initiation/party.html | 15 + .../-fixing-session-initiation/sender.html | 15 + .../session-i-d.html | 15 + .../-fixing-session-initiation/timeout.html | 15 + .../-floater/-init-.html | 2 +- .../-floater/index.html | 49 +- .../-floater/my-key-pair.html | 16 + .../-floater/notary-node.html | 16 + .../-floater/other-session-i-d.html | 16 + .../-floater/other-side.html | 16 + .../-floater/payload.html | 16 + .../-floater/progress-tracker.html | 2 +- .../-instigator/-init-.html | 2 +- .../-instigator/index.html | 73 +- .../-instigator/my-key-pair.html | 16 + .../-instigator/notary-node.html | 16 + .../-instigator/notary.html | 15 + .../-instigator/other-session-i-d.html | 16 + .../-instigator/other-side.html | 16 + .../-instigator/payload.html | 16 + .../-primary/-init-.html | 2 +- .../-primary/index.html | 26 +- .../-primary/my-key-pair.html | 2 +- .../-primary/notary-node.html | 2 +- .../-primary/other-session-i-d.html | 2 +- .../-primary/other-side.html | 2 +- .../-primary/payload.html | 2 +- .../-secondary/-init-.html | 2 +- .../-secondary/index.html | 22 +- .../-secondary/other-side.html | 2 +- .../-secondary/session-i-d.html | 2 +- .../-two-party-deal-protocol/index.html | 26 +- .../-buyer/-init-.html | 2 +- .../-buyer/acceptable-price.html | 2 +- .../-buyer/index.html | 14 +- .../-buyer/other-side.html | 2 +- .../-seller-trade-info/-init-.html | 2 +- .../-seller-trade-info/index.html | 4 +- .../-seller-trade-info/price.html | 2 +- .../-seller/-init-.html | 2 +- .../-seller/index.html | 14 +- .../-seller/other-side.html | 2 +- .../-seller/price.html | 2 +- .../-unacceptable-price-exception/-init-.html | 2 +- .../given-price.html | 2 +- .../-unacceptable-price-exception/index.html | 4 +- .../-validating-notary-protocol/-init-.html | 2 +- .../before-commit.html | 4 +- .../-validating-notary-protocol/index.html | 6 +- .../html/api/com.r3corda.protocols/index.html | 12 +- docs/build/html/api/index-outline.html | 4341 +++++++++++++---- docs/build/html/api/index.html | 20 +- .../-acceptor/-a-p-p-r-o-v-i-n-g.html | 42 + .../-acceptor/-init-.html | 14 + .../-acceptor/-r-e-j-e-c-t-i-n-g.html | 42 + .../-acceptor/-t-o-p-i-c_-c-h-a-n-g-e.html | 15 + .../-t-o-p-i-c_-i-n-i-t-i-a-t-e.html | 15 + .../-acceptor/-v-e-r-i-f-y-i-n-g.html | 42 + .../-acceptor/call.html | 17 + .../-acceptor/index.html | 187 + .../-acceptor/other-side.html | 15 + .../-acceptor/progress-tracker.html | 24 + .../-acceptor/session-id-for-receive.html | 15 + .../-acceptor/session-id-for-send.html | 15 + .../-acceptor/tracker.html | 15 + .../-handshake/-init-.html | 14 + .../-handshake/index.html | 64 + .../-handshake/session-i-d.html | 16 + .../-handshake/session-id-for-send.html | 15 + .../-init-.html | 23 + .../-instigator/-init-.html | 14 + .../-instigator/-n-o-t-a-r-y.html | 42 + .../-instigator/-s-i-g-n-i-n-g.html | 42 + .../-instigator/-t-o-p-i-c_-c-h-a-n-g-e.html | 15 + .../-t-o-p-i-c_-i-n-i-t-i-a-t-e.html | 15 + .../-instigator/call.html | 17 + .../-instigator/index.html | 175 + .../-instigator/modification.html | 15 + .../-instigator/original-state.html | 15 + .../-instigator/progress-tracker.html | 24 + .../-instigator/tracker.html | 15 + .../-proposal/index.html | 48 + .../-proposal/modification.html | 15 + .../-proposal/state-ref.html | 15 + .../-proposal/stx.html | 15 + .../-result/error.html | 15 + .../-result/index.html | 48 + .../-result/no-error.html | 15 + .../-result/sig.html | 15 + .../-result/with-error.html | 15 + .../index.html | 85 + .../-acceptor/-init-.html | 14 + .../-acceptor/-t-o-p-i-c_-c-h-a-n-g-e.html | 16 + .../-t-o-p-i-c_-i-n-i-t-i-a-t-e.html | 16 + .../-acceptor/index.html | 87 + .../-acceptor/progress-tracker.html | 24 + .../-instigator/-init-.html | 14 + .../-instigator/-t-o-p-i-c_-c-h-a-n-g-e.html | 16 + .../-t-o-p-i-c_-i-n-i-t-i-a-t-e.html | 16 + .../-instigator/index.html | 81 + .../-proposal/-init-.html | 14 + .../-proposal/index.html | 48 + .../-proposal/modification.html | 16 + .../-proposal/state-ref.html | 16 + .../-proposal/stx.html | 16 + .../-t-o-p-i-c_-c-h-a-n-g-e.html | 15 + .../-t-o-p-i-c_-i-n-i-t-i-a-t-e.html | 15 + .../-notary-change-protocol/index.html | 62 + .../-state-replacement-exception/-init-.html | 14 + .../-state-replacement-exception/error.html | 15 + .../-state-replacement-exception/index.html | 36 + .../-state-replacement-refused/-init-.html | 15 + .../-state-replacement-refused/detail.html | 15 + .../-state-replacement-refused/identity.html | 15 + .../-state-replacement-refused/index.html | 61 + .../-state-replacement-refused/state.html | 15 + .../-state-replacement-refused/to-string.html | 15 + docs/build/html/api/protocols/index.html | 51 + docs/build/html/building-the-docs.html | 5 +- docs/build/html/codestyle.html | 39 +- docs/build/html/consensus.html | 160 +- docs/build/html/data-model.html | 9 +- docs/build/html/event-scheduling.html | 326 ++ docs/build/html/genindex.html | 5 +- docs/build/html/getting-set-up.html | 5 +- docs/build/html/index.html | 30 +- docs/build/html/inthebox.html | 63 +- docs/build/html/irs.html | 5 +- docs/build/html/messaging.html | 9 +- docs/build/html/node-administration.html | 5 +- docs/build/html/objects.inv | Bin 658 -> 671 bytes docs/build/html/oracles.html | 9 +- docs/build/html/protocol-state-machines.html | 5 +- docs/build/html/release-notes.html | 100 +- docs/build/html/release-process.html | 9 +- docs/build/html/robots.txt | 2 + docs/build/html/running-the-demos.html | 9 +- docs/build/html/search.html | 5 +- docs/build/html/searchindex.js | 2 +- docs/build/html/transaction-data-types.html | 37 +- docs/build/html/tutorial-contract.html | 5 +- docs/build/html/visualiser.html | 5 +- docs/build/html/where-to-start.html | 5 +- 994 files changed, 23519 insertions(+), 2434 deletions(-) create mode 100644 docs/build/html/_sources/event-scheduling.txt create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-c-a-s-h_-p-r-o-g-r-a-m_-i-d.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/-exit/-init-.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/-exit/amount.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/-exit/index.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/-issue/-init-.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/-issue/index.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/-issue/nonce.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/-move/-init-.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/-move/contract-hash.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/-move/index.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/index.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-cash/-init-.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/-init-.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/amount.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/contract.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/deposit.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/index.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/issuance-def.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/move.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/owner.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/participants.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/product-amount.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/to-string.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/with-new-owner.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-cash/generate-issue.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-cash/generate-spend.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-cash/index.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-cash/legal-contract-reference.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset-state/index.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset-state/issuance-def.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset-state/move.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset-state/product-amount.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-commands/-exit/amount.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-commands/-exit/index.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-commands/-issue.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-commands/-move.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-commands/index.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-init-.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-state/amount.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-state/deposit.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-state/index.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-state/owner.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/index.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/verify.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-insufficient-balance-exception/-init-.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-insufficient-balance-exception/amount-missing.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-insufficient-balance-exception/index.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-o-b-l-i-g-a-t-i-o-n_-p-r-o-g-r-a-m_-i-d.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-bilateral-net-state/-init-.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-bilateral-net-state/index.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-bilateral-net-state/party-keys.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-bilateral-net-state/template.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-exit/-init-.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-exit/aggregate-state.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-exit/amount.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-exit/index.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-issue/-init-.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-issue/aggregate-state.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-issue/index.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-issue/nonce.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-move/-init-.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-move/aggregate-state.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-move/contract-hash.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-move/index.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-net/-init-.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-net/index.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-net/type.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-set-lifecycle/-init-.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-set-lifecycle/aggregate-state.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-set-lifecycle/index.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-set-lifecycle/inverse.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-set-lifecycle/lifecycle.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-settle/-init-.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-settle/aggregate-state.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-settle/amount.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-settle/index.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/index.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-init-.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-issuance-commands/aggregate-state.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-issuance-commands/index.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-issuance-definition/-init-.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-issuance-definition/index.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-issuance-definition/obligor.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-issuance-definition/template.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-lifecycle/-d-e-f-a-u-l-t-e-d.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-lifecycle/-n-o-r-m-a-l.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-lifecycle/index.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-multilateral-net-state/-init-.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-multilateral-net-state/index.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-multilateral-net-state/template.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-net-state/index.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-net-state/template.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state-template/-init-.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state-template/acceptable-contracts.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state-template/acceptable-issued-products.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state-template/due-before.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state-template/index.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state-template/product.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state-template/time-tolerance.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/-init-.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/acceptable-contracts.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/acceptable-issuance-definitions.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/aggregate-state.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/amount.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/beneficiary.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/bilateral-net-state.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/contract.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/due-before.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/index.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/issuance-def.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/lifecycle.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/move.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/multilateral-net-state.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/net.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/obligor.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/owner.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/participants.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/product-amount.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/quantity.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/template.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/to-string.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/with-new-owner.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/generate-close-out-netting.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/generate-issue.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/generate-payment-netting.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/generate-set-lifecycle.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/generate-settle.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/index.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/legal-contract-reference.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/verify-issue-command.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/verify-net-command.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/verify-set-lifecycle-command.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/-obligation/verify.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/cash-balances.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/extract-amounts-due.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/index.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/index.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-cash-by.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-cash-or-null.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-cash-or-zero.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-cash.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-fungible-by.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-fungible-or-null.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-fungible-or-zero.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-fungible.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-obligations-or-null.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-obligations-or-zero.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-obligations.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/net-amounts-due.html create mode 100644 docs/build/html/api/com.r3corda.contracts.asset/sum-amounts-due.html create mode 100644 docs/build/html/api/com.r3corda.contracts.testing/-d-u-m-m-y_-c-a-s-h_-i-s-s-u-e-r.html create mode 100644 docs/build/html/api/com.r3corda.contracts.testing/-d-u-m-m-y_-c-a-s-h_-i-s-s-u-e-r_-k-e-y.html create mode 100644 docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/-c-a-s-h.html create mode 100644 docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/-o-b-l-i-g-a-t-i-o-n.html create mode 100644 docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/-o-b-l-i-g-a-t-i-o-n_-d-e-f.html create mode 100644 docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/-s-t-a-t-e.html create mode 100644 docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/at.html create mode 100644 docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/between.html create mode 100644 docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/index.html create mode 100644 docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/issued-by.html create mode 100644 docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/owned-by.html create mode 100644 docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/with-deposit.html create mode 100644 docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/with-notary.html create mode 100644 docs/build/html/api/com.r3corda.contracts.testing/-o-b-l-i-g-a-t-i-o-n.html create mode 100644 docs/build/html/api/com.r3corda.contracts.testing/-o-b-l-i-g-a-t-i-o-n_-d-e-f.html create mode 100644 docs/build/html/api/com.r3corda.contracts.testing/-s-t-a-t-e.html create mode 100644 docs/build/html/api/com.r3corda.contracts.testing/at.html create mode 100644 docs/build/html/api/com.r3corda.contracts.testing/between.html create mode 100644 docs/build/html/api/com.r3corda.contracts.testing/fill-with-some-test-cash.html create mode 100644 docs/build/html/api/com.r3corda.contracts.testing/with deposit.html create mode 100644 docs/build/html/api/com.r3corda.contracts.testing/with notary.html create mode 100644 docs/build/html/api/com.r3corda.contracts/-commercial-paper/-state/participants.html create mode 100644 docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-floating-leg/fixing-period-offset.html create mode 100644 docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-state/next-scheduled-activity.html create mode 100644 docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-state/participants.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-bilateral-nettable-state/bilateral-net-state.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-bilateral-nettable-state/index.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-bilateral-nettable-state/net.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-contract-state/participants.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-commands/-move/-init-.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-commands/-move/index.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-multi-owner-state/-init-.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-multi-owner-state/contract.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-multi-owner-state/index.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-multi-owner-state/magic-number.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-multi-owner-state/owners.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-multi-owner-state/participants.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-single-owner-state/-init-.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-single-owner-state/contract.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-single-owner-state/index.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-single-owner-state/magic-number.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-single-owner-state/owner.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-single-owner-state/participants.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-single-owner-state/with-new-owner.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-dummy-state/-init-.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-dummy-state/contract.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-dummy-state/index.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-dummy-state/magic-number.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-dummy-state/participants.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-issue-command/index.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-issue-command/nonce.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-issued/-init-.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-issued/index.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-issued/issuer.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-issued/product.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-java-test-helpers/-c-h-f.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-java-test-helpers/-d-o-l-l-a-r-s.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-java-test-helpers/-g-b-p.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-java-test-helpers/-p-o-u-n-d-s.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-java-test-helpers/-s-w-i-s-s_-f-r-a-n-c-s.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-java-test-helpers/-u-s-d.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-java-test-helpers/index.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-java-test-helpers/issued-by.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-ledger-transaction/signers.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-ledger-transaction/type.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-move-command/contract-hash.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-move-command/index.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-net-type/-c-l-o-s-e_-o-u-t.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-net-type/-p-a-y-m-e-n-t.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-net-type/index.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-schedulable-state/index.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-schedulable-state/next-scheduled-activity.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-scheduled-activity/-init-.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-scheduled-activity/index.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-scheduled-activity/logic-ref.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-scheduled-activity/scheduled-at.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-scheduled-state-ref/-init-.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-scheduled-state-ref/index.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-scheduled-state-ref/ref.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-scheduled-state-ref/scheduled-at.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-scheduled/index.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-scheduled/scheduled-at.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-signed-transaction/with-additional-signatures.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/current-sigs.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/inputs.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/notary.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/outputs.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/signers.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/type.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/-in-out-group/-init-.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/-in-out-group/grouping-key.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/-in-out-group/index.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/-in-out-group/inputs.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/-in-out-group/outputs.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/-init-.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/attachments.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/commands.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/equals.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/get-timestamp-by-name.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/get-timestamp-by.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/group-commands.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/group-states-internal.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/group-states.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/hash-code.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/in-states.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/index.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/inputs.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/orig-hash.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/out-states.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/outputs.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-for-verification/inputs.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-for-verification/outputs.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-for-verification/signers.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-for-verification/to-transaction-for-contract.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-for-verification/type.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-state/-init-.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-state/data.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-state/index.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-state/notary.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-state/with-new-notary.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-general/-builder/-init-.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-general/-builder/index.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-general/-init-.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-general/get-required-signers.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-general/index.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-general/verify-transaction.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-notary-change/-builder/-init-.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-notary-change/-builder/add-input-state.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-notary-change/-builder/index.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-notary-change/-init-.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-notary-change/get-required-signers.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-notary-change/index.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-notary-change/verify-transaction.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-type/equals.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-type/get-required-signers.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-type/hash-code.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-type/index.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-type/verify-signers.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-type/verify-transaction.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-type/verify.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-verification-exception/-invalid-notary-change/-init-.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-verification-exception/-invalid-notary-change/index.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-verification-exception/-signers-missing/-init-.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-transaction-verification-exception/-signers-missing/index.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-wire-transaction/signers.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/-wire-transaction/type.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/issued by.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/java.util.-currency/index.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/java.util.-currency/issued by.html create mode 100644 docs/build/html/api/com.r3corda.core.contracts/verify-move-command.html create mode 100644 docs/build/html/api/com.r3corda.core.crypto/new-secure-random.html create mode 100644 docs/build/html/api/com.r3corda.core.messaging/-ack.html create mode 100644 docs/build/html/api/com.r3corda.core.node.services/-read-only-transaction-storage/get-transaction.html create mode 100644 docs/build/html/api/com.r3corda.core.node.services/-read-only-transaction-storage/index.html create mode 100644 docs/build/html/api/com.r3corda.core.node.services/-scheduler-service/index.html create mode 100644 docs/build/html/api/com.r3corda.core.node.services/-scheduler-service/schedule-state-activity.html create mode 100644 docs/build/html/api/com.r3corda.core.node.services/-scheduler-service/unschedule-state-activity.html create mode 100644 docs/build/html/api/com.r3corda.core.node.services/-tx-writable-storage-service/index.html create mode 100644 docs/build/html/api/com.r3corda.core.node.services/-tx-writable-storage-service/validated-transactions.html create mode 100644 docs/build/html/api/com.r3corda.core.node.services/-wallet-service/when-consumed.html create mode 100644 docs/build/html/api/com.r3corda.core.node/-service-hub/scheduler-service.html create mode 100644 docs/build/html/api/com.r3corda.core.protocols/-app-context/-init-.html create mode 100644 docs/build/html/api/com.r3corda.core.protocols/-app-context/attachments.html create mode 100644 docs/build/html/api/com.r3corda.core.protocols/-app-context/class-loader.html create mode 100644 docs/build/html/api/com.r3corda.core.protocols/-app-context/index.html create mode 100644 docs/build/html/api/com.r3corda.core.protocols/-illegal-protocol-logic-exception/-init-.html create mode 100644 docs/build/html/api/com.r3corda.core.protocols/-illegal-protocol-logic-exception/index.html create mode 100644 docs/build/html/api/com.r3corda.core.protocols/-protocol-logic-ref-factory/-init-.html create mode 100644 docs/build/html/api/com.r3corda.core.protocols/-protocol-logic-ref-factory/create-kotlin.html create mode 100644 docs/build/html/api/com.r3corda.core.protocols/-protocol-logic-ref-factory/create.html create mode 100644 docs/build/html/api/com.r3corda.core.protocols/-protocol-logic-ref-factory/index.html create mode 100644 docs/build/html/api/com.r3corda.core.protocols/-protocol-logic-ref-factory/to-protocol-logic.html create mode 100644 docs/build/html/api/com.r3corda.core.protocols/-protocol-logic-ref/app-context.html create mode 100644 docs/build/html/api/com.r3corda.core.protocols/-protocol-logic-ref/args.html create mode 100644 docs/build/html/api/com.r3corda.core.protocols/-protocol-logic-ref/index.html create mode 100644 docs/build/html/api/com.r3corda.core.protocols/-protocol-logic-ref/protocol-logic-class-name.html create mode 100644 docs/build/html/api/com.r3corda.core.serialization/-deserialize-as-kotlin-object-def.html create mode 100644 docs/build/html/api/com.r3corda.core.serialization/-ed25519-private-key-serializer/ed25519-curve.html create mode 100644 docs/build/html/api/com.r3corda.core.serialization/-ed25519-private-key-serializer/index.html create mode 100644 docs/build/html/api/com.r3corda.core.serialization/-ed25519-private-key-serializer/read.html create mode 100644 docs/build/html/api/com.r3corda.core.serialization/-ed25519-private-key-serializer/write.html create mode 100644 docs/build/html/api/com.r3corda.core.serialization/-ed25519-public-key-serializer/ed25519-curve.html create mode 100644 docs/build/html/api/com.r3corda.core.serialization/-ed25519-public-key-serializer/index.html create mode 100644 docs/build/html/api/com.r3corda.core.serialization/-ed25519-public-key-serializer/read.html create mode 100644 docs/build/html/api/com.r3corda.core.serialization/-ed25519-public-key-serializer/write.html create mode 100644 docs/build/html/api/com.r3corda.core.serialization/-kotlin-object-serializer/index.html create mode 100644 docs/build/html/api/com.r3corda.core.serialization/-kotlin-object-serializer/read.html create mode 100644 docs/build/html/api/com.r3corda.core.serialization/-kotlin-object-serializer/write.html create mode 100644 docs/build/html/api/com.r3corda.core.serialization/read-bytes-with-length.html create mode 100644 docs/build/html/api/com.r3corda.core.serialization/write-bytes-with-length.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-abstract-transaction-for-test/add-command.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-abstract-transaction-for-test/signers.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-abstract-transaction-for-test/type.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-always-succeed-contract/-init-.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-always-succeed-contract/index.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-always-succeed-contract/legal-contract-reference.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-always-succeed-contract/verify.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-dummy-linear-state/-init-.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-dummy-linear-state/contract.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-dummy-linear-state/index.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-dummy-linear-state/is-relevant.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-dummy-linear-state/nonce.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-dummy-linear-state/participants.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-dummy-linear-state/thread.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-in-memory-wallet-service/-clashing-threads/-init-.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-in-memory-wallet-service/-clashing-threads/index.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-in-memory-wallet-service/-init-.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-in-memory-wallet-service/clashing-threads.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-in-memory-wallet-service/current-wallet.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-in-memory-wallet-service/index.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-in-memory-wallet-service/linear-heads.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-in-memory-wallet-service/notify-all.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-in-memory-wallet-service/updates.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-a-l-i-c-e.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-a-l-i-c-e_-k-e-y.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-a-l-i-c-e_-p-u-b-k-e-y.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-a-l-l_-t-e-s-t_-k-e-y-s.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-b-o-b.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-b-o-b_-k-e-y.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-b-o-b_-p-u-b-k-e-y.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-d-u-m-m-y_-n-o-t-a-r-y.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-d-u-m-m-y_-n-o-t-a-r-y_-k-e-y.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-d-u-m-m-y_-p-u-b-k-e-y_1.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-d-u-m-m-y_-p-u-b-k-e-y_2.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-m-e-g-a_-c-o-r-p.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-m-e-g-a_-c-o-r-p_-k-e-y.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-m-e-g-a_-c-o-r-p_-p-u-b-k-e-y.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-m-i-n-i_-c-o-r-p.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-m-i-n-i_-c-o-r-p_-k-e-y.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-m-i-n-i_-c-o-r-p_-p-u-b-k-e-y.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-m-o-c-k_-i-d-e-n-t-i-t-y_-s-e-r-v-i-c-e.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-o-r-a-c-l-e_-k-e-y.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-o-r-a-c-l-e_-p-u-b-k-e-y.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-t-e-s-t_-t-x_-t-i-m-e.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/generate-state-ref.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/index.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/transaction.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-last-line-should-test-for-accept-or-failure.html create mode 100644 docs/build/html/api/com.r3corda.core.testing/-transaction-for-test/fails-requirement.html create mode 100644 docs/build/html/api/com.r3corda.core.utilities/-non-empty-set-serializer/index.html create mode 100644 docs/build/html/api/com.r3corda.core.utilities/-non-empty-set-serializer/read.html create mode 100644 docs/build/html/api/com.r3corda.core.utilities/-non-empty-set-serializer/write.html create mode 100644 docs/build/html/api/com.r3corda.core.utilities/-time-window/-init-.html create mode 100644 docs/build/html/api/com.r3corda.core.utilities/-time-window/duration.html create mode 100644 docs/build/html/api/com.r3corda.core.utilities/-time-window/end.html create mode 100644 docs/build/html/api/com.r3corda.core.utilities/-time-window/index.html create mode 100644 docs/build/html/api/com.r3corda.core.utilities/-time-window/start.html create mode 100644 docs/build/html/api/com.r3corda.core.utilities/suggest-interest-rate-announcement-time-window.html create mode 100644 docs/build/html/api/com.r3corda.core/-thread-box/already-locked.html create mode 100644 docs/build/html/api/com.r3corda.demos.protocols/-auto-offer-protocol/-auto-offer-message/notary.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params-spec/api-address-arg.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params-spec/base-directory-arg.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params-spec/fake-trade-with-addr.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params-spec/fake-trade-with-identity-file.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params-spec/index.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params-spec/network-address-arg.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params-spec/network-map-identity-file.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params-spec/network-map-net-addr.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params-spec/non-options.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params-spec/parser.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params-spec/role-arg.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params/-date-change/-init-.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params/-date-change/api-address.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params/-date-change/date-string.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params/-date-change/index.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/-init-.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/api-address.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/auto-setup.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/default-legal-name.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/dir.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/identity-file.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/index.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/map-address.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/network-address.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/node.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/trade-with-addrs.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/trade-with-identities.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/upload-rates.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params/-setup-node/-init-.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params/-setup-node/default-legal-name.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params/-setup-node/dir.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params/-setup-node/index.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params/-setup-node/node.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params/-trade/-init-.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params/-trade/api-address.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params/-trade/index.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params/-trade/trade-id.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params/default-base-directory.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params/index.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params/legal-name.html create mode 100644 docs/build/html/api/com.r3corda.demos/-cli-params/parse.html create mode 100644 docs/build/html/api/com.r3corda.demos/-d-e-f-a-u-l-t_-b-a-s-e_-d-i-r-e-c-t-o-r-y.html create mode 100644 docs/build/html/api/com.r3corda.demos/-i-r-s-demo-node/-node-a.html create mode 100644 docs/build/html/api/com.r3corda.demos/-i-r-s-demo-node/-node-b.html create mode 100644 docs/build/html/api/com.r3corda.demos/-i-r-s-demo-node/index.html create mode 100644 docs/build/html/api/com.r3corda.demos/-i-r-s-demo-node/other.html create mode 100644 docs/build/html/api/com.r3corda.demos/run-i-r-s-demo.html create mode 100644 docs/build/html/api/com.r3corda.demos/run-trader-demo.html create mode 100644 docs/build/html/api/com.r3corda.node.api/-a-p-i-server/status.html create mode 100644 docs/build/html/api/com.r3corda.node.internal.testing/-simulation/clocks.html create mode 100644 docs/build/html/api/com.r3corda.node.internal.testing/-simulation/current-date-and-time.html create mode 100644 docs/build/html/api/com.r3corda.node.internal.testing/-simulation/network-send-manually-pumped.html create mode 100644 docs/build/html/api/com.r3corda.node.internal.testing/-simulation/show-consensus-for.html create mode 100644 docs/build/html/api/com.r3corda.node.internal.testing/-simulation/show-progress-for.html create mode 100644 docs/build/html/api/com.r3corda.node.internal.testing/-test-clock/set-to.html create mode 100644 docs/build/html/api/com.r3corda.node.internal.testing/-test-clock/to-token.html create mode 100644 docs/build/html/api/com.r3corda.node.internal.testing/issue-multi-party-state.html create mode 100644 docs/build/html/api/com.r3corda.node.internal.testing/kotlin.collections.-iterable/index.html create mode 100644 docs/build/html/api/com.r3corda.node.internal.testing/kotlin.collections.-iterable/set-to.html create mode 100644 docs/build/html/api/com.r3corda.node.internal/-a-p-i-server-impl/status.html create mode 100644 docs/build/html/api/com.r3corda.node.internal/-abstract-node/create-node-dir.html create mode 100644 docs/build/html/api/com.r3corda.node.internal/-abstract-node/scheduler.html create mode 100644 docs/build/html/api/com.r3corda.node.internal/-abstract-node/setup.html create mode 100644 docs/build/html/api/com.r3corda.node.internal/-node/setup.html create mode 100644 docs/build/html/api/com.r3corda.node.internal/-node/web-server-addr.html create mode 100644 docs/build/html/api/com.r3corda.node.services.api/-abstract-node-service/network-map-cache.html create mode 100644 docs/build/html/api/com.r3corda.node.services.api/-service-hub-internal/-init-.html create mode 100644 docs/build/html/api/com.r3corda.node.services.api/-service-hub-internal/protocol-logic-ref-factory.html create mode 100644 docs/build/html/api/com.r3corda.node.services.api/-service-hub-internal/start-protocol.html create mode 100644 docs/build/html/api/com.r3corda.node.services.clientapi/-node-interest-rates/-oracle/clock.html create mode 100644 docs/build/html/api/com.r3corda.node.services.events/-node-scheduler-service/-init-.html create mode 100644 docs/build/html/api/com.r3corda.node.services.events/-node-scheduler-service/index.html create mode 100644 docs/build/html/api/com.r3corda.node.services.events/-node-scheduler-service/schedule-state-activity.html create mode 100644 docs/build/html/api/com.r3corda.node.services.events/-node-scheduler-service/unschedule-state-activity.html create mode 100644 docs/build/html/api/com.r3corda.node.services.events/-scheduled-activity-observer/-init-.html create mode 100644 docs/build/html/api/com.r3corda.node.services.events/-scheduled-activity-observer/index.html create mode 100644 docs/build/html/api/com.r3corda.node.services.events/-scheduled-activity-observer/services.html create mode 100644 docs/build/html/api/com.r3corda.node.services.events/index.html create mode 100644 docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/-in-memory-messaging/pump-receive.html create mode 100644 docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/pump-send-internal.html create mode 100644 docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/pump-send.html create mode 100644 docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/received-messages.html create mode 100644 docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/send-manually-pumped.html create mode 100644 docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/sent-messages.html create mode 100644 docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-fetch-map-request/session-i-d.html create mode 100644 docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-network-map-request-message/-init-.html create mode 100644 docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-network-map-request-message/get-reply-to.html create mode 100644 docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-network-map-request-message/index.html create mode 100644 docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-network-map-request-message/reply-to.html create mode 100644 docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-query-identity-request/session-i-d.html create mode 100644 docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-registration-request/session-i-d.html create mode 100644 docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-subscribe-request/session-i-d.html create mode 100644 docs/build/html/api/com.r3corda.node.services/-fixing-session-initiation-handler/index.html create mode 100644 docs/build/html/api/com.r3corda.node.services/-fixing-session-initiation-handler/register.html create mode 100644 docs/build/html/api/com.r3corda.node.services/-notary-change-service/-init-.html create mode 100644 docs/build/html/api/com.r3corda.node.services/-notary-change-service/index.html create mode 100644 docs/build/html/api/com.r3corda.node.services/-notary-change-service/smm.html create mode 100644 docs/build/html/api/com.r3corda.node.services/index.html create mode 100644 docs/build/html/api/com.r3corda.node.utilities/-json-support/-public-key-deserializer/deserialize.html create mode 100644 docs/build/html/api/com.r3corda.node.utilities/-json-support/-public-key-deserializer/index.html create mode 100644 docs/build/html/api/com.r3corda.node.utilities/-json-support/-public-key-serializer/index.html create mode 100644 docs/build/html/api/com.r3corda.node.utilities/-json-support/-public-key-serializer/serialize.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-abstract-request-message/get-reply-to.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-abstract-request-message/reply-to-party.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-fetch-data-protocol/-request/session-i-d.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-notary-error/-signatures-missing/-init-.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-notary-error/-signatures-missing/index.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-notary-error/-signatures-missing/missing-signers.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-notary-protocol/-client/notary-party.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-notary-protocol/-handshake/session-i-d.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-notary-protocol/-sign-request/tx.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-rates-fix-protocol/-query-request/deadline.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-rates-fix-protocol/-query-request/session-i-d.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-rates-fix-protocol/-sign-request/session-i-d.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-service-request-message/get-reply-to.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-service-request-message/index.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-service-request-message/session-i-d.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-acceptor/notary.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-acceptor/other-side.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-acceptor/session-i-d.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-f-i-x_-i-n-i-t-i-a-t-e_-t-o-p-i-c.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixer/initiation.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixer/other-side.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixer/session-i-d.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-role-decider/-init-.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-role-decider/-l-o-a-d-i-n-g/-init-.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-role-decider/-l-o-a-d-i-n-g/index.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-role-decider/call.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-role-decider/index.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-role-decider/progress-tracker.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-role-decider/ref.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-role-decider/timeout.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-role-decider/tracker.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-session-initiation/-init-.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-session-initiation/index.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-session-initiation/party.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-session-initiation/sender.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-session-initiation/session-i-d.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-session-initiation/timeout.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-floater/my-key-pair.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-floater/notary-node.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-floater/other-session-i-d.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-floater/other-side.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-floater/payload.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-instigator/my-key-pair.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-instigator/notary-node.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-instigator/notary.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-instigator/other-session-i-d.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-instigator/other-side.html create mode 100644 docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-instigator/payload.html create mode 100644 docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/-a-p-p-r-o-v-i-n-g.html create mode 100644 docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/-init-.html create mode 100644 docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/-r-e-j-e-c-t-i-n-g.html create mode 100644 docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/-t-o-p-i-c_-c-h-a-n-g-e.html create mode 100644 docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/-t-o-p-i-c_-i-n-i-t-i-a-t-e.html create mode 100644 docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/-v-e-r-i-f-y-i-n-g.html create mode 100644 docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/call.html create mode 100644 docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/index.html create mode 100644 docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/other-side.html create mode 100644 docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/progress-tracker.html create mode 100644 docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/session-id-for-receive.html create mode 100644 docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/session-id-for-send.html create mode 100644 docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/tracker.html create mode 100644 docs/build/html/api/protocols/-abstract-state-replacement-protocol/-handshake/-init-.html create mode 100644 docs/build/html/api/protocols/-abstract-state-replacement-protocol/-handshake/index.html create mode 100644 docs/build/html/api/protocols/-abstract-state-replacement-protocol/-handshake/session-i-d.html create mode 100644 docs/build/html/api/protocols/-abstract-state-replacement-protocol/-handshake/session-id-for-send.html create mode 100644 docs/build/html/api/protocols/-abstract-state-replacement-protocol/-init-.html create mode 100644 docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/-init-.html create mode 100644 docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/-n-o-t-a-r-y.html create mode 100644 docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/-s-i-g-n-i-n-g.html create mode 100644 docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/-t-o-p-i-c_-c-h-a-n-g-e.html create mode 100644 docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/-t-o-p-i-c_-i-n-i-t-i-a-t-e.html create mode 100644 docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/call.html create mode 100644 docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/index.html create mode 100644 docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/modification.html create mode 100644 docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/original-state.html create mode 100644 docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/progress-tracker.html create mode 100644 docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/tracker.html create mode 100644 docs/build/html/api/protocols/-abstract-state-replacement-protocol/-proposal/index.html create mode 100644 docs/build/html/api/protocols/-abstract-state-replacement-protocol/-proposal/modification.html create mode 100644 docs/build/html/api/protocols/-abstract-state-replacement-protocol/-proposal/state-ref.html create mode 100644 docs/build/html/api/protocols/-abstract-state-replacement-protocol/-proposal/stx.html create mode 100644 docs/build/html/api/protocols/-abstract-state-replacement-protocol/-result/error.html create mode 100644 docs/build/html/api/protocols/-abstract-state-replacement-protocol/-result/index.html create mode 100644 docs/build/html/api/protocols/-abstract-state-replacement-protocol/-result/no-error.html create mode 100644 docs/build/html/api/protocols/-abstract-state-replacement-protocol/-result/sig.html create mode 100644 docs/build/html/api/protocols/-abstract-state-replacement-protocol/-result/with-error.html create mode 100644 docs/build/html/api/protocols/-abstract-state-replacement-protocol/index.html create mode 100644 docs/build/html/api/protocols/-notary-change-protocol/-acceptor/-init-.html create mode 100644 docs/build/html/api/protocols/-notary-change-protocol/-acceptor/-t-o-p-i-c_-c-h-a-n-g-e.html create mode 100644 docs/build/html/api/protocols/-notary-change-protocol/-acceptor/-t-o-p-i-c_-i-n-i-t-i-a-t-e.html create mode 100644 docs/build/html/api/protocols/-notary-change-protocol/-acceptor/index.html create mode 100644 docs/build/html/api/protocols/-notary-change-protocol/-acceptor/progress-tracker.html create mode 100644 docs/build/html/api/protocols/-notary-change-protocol/-instigator/-init-.html create mode 100644 docs/build/html/api/protocols/-notary-change-protocol/-instigator/-t-o-p-i-c_-c-h-a-n-g-e.html create mode 100644 docs/build/html/api/protocols/-notary-change-protocol/-instigator/-t-o-p-i-c_-i-n-i-t-i-a-t-e.html create mode 100644 docs/build/html/api/protocols/-notary-change-protocol/-instigator/index.html create mode 100644 docs/build/html/api/protocols/-notary-change-protocol/-proposal/-init-.html create mode 100644 docs/build/html/api/protocols/-notary-change-protocol/-proposal/index.html create mode 100644 docs/build/html/api/protocols/-notary-change-protocol/-proposal/modification.html create mode 100644 docs/build/html/api/protocols/-notary-change-protocol/-proposal/state-ref.html create mode 100644 docs/build/html/api/protocols/-notary-change-protocol/-proposal/stx.html create mode 100644 docs/build/html/api/protocols/-notary-change-protocol/-t-o-p-i-c_-c-h-a-n-g-e.html create mode 100644 docs/build/html/api/protocols/-notary-change-protocol/-t-o-p-i-c_-i-n-i-t-i-a-t-e.html create mode 100644 docs/build/html/api/protocols/-notary-change-protocol/index.html create mode 100644 docs/build/html/api/protocols/-state-replacement-exception/-init-.html create mode 100644 docs/build/html/api/protocols/-state-replacement-exception/error.html create mode 100644 docs/build/html/api/protocols/-state-replacement-exception/index.html create mode 100644 docs/build/html/api/protocols/-state-replacement-refused/-init-.html create mode 100644 docs/build/html/api/protocols/-state-replacement-refused/detail.html create mode 100644 docs/build/html/api/protocols/-state-replacement-refused/identity.html create mode 100644 docs/build/html/api/protocols/-state-replacement-refused/index.html create mode 100644 docs/build/html/api/protocols/-state-replacement-refused/state.html create mode 100644 docs/build/html/api/protocols/-state-replacement-refused/to-string.html create mode 100644 docs/build/html/api/protocols/index.html create mode 100644 docs/build/html/event-scheduling.html create mode 100644 docs/build/html/robots.txt diff --git a/docs/build/html/_sources/codestyle.txt b/docs/build/html/_sources/codestyle.txt index 2e15c7fd28..aeebb4f04d 100644 --- a/docs/build/html/_sources/codestyle.txt +++ b/docs/build/html/_sources/codestyle.txt @@ -185,3 +185,38 @@ instead do this The latter is easier to catch and handle if later necessary, and the type name should explain what went wrong. Note that Kotlin does not require exception types to be declared in method prototypes like Java does. + +5. Properties +############# + +Where we want a public property to have one super-type in public and another sub-type in private (or internal), perhaps +to expose additional methods with a greater level of access to the code within the enclosing class, the style should be: + +.. sourcecode:: kotlin + + class PrivateFoo : PublicFoo + + private val _foo = PrivateFoo() + val foo: PublicFoo get() = _foo + +Notably: + +* The public property should have an explicit and more restrictive type, most likely a super class or interface. +* The private, backed property should begin with underscore but otherwise have the same name as the public property. + The underscore resolves a potential property name clash, and avoids naming such as "privateFoo". If the type or use + of the private property is different enough that there is no naming collision, prefer the distinct names without + an underscore. +* The underscore prefix is not a general pattern for private properties. +* The public property should not have an additional backing field but use "get()" to return an appropriate copy of the + private field. +* The public property should optionally wrap the returned value in an immutable wrapper, such as Guava's immutable + collection wrappers, if that is appropriate. +* If the code following "get()" is succinct, prefer a one-liner formatting of the public property as above, otherwise + put the "get()" on the line below, indented. + +6. Compiler warnings +#################### + +We do not allow compiler warnings, except in the experimental module where the usual standards do not apply and warnings +are suppressed. If a warning exists it should be either fixed or suppressed using @SuppressWarnings and if suppressed +there must be an accompanying explanation in the code for why the warning is a false positive. \ No newline at end of file diff --git a/docs/build/html/_sources/consensus.txt b/docs/build/html/_sources/consensus.txt index ee71767d50..85e789acf9 100644 --- a/docs/build/html/_sources/consensus.txt +++ b/docs/build/html/_sources/consensus.txt @@ -1,11 +1,11 @@ -Consensus Model +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 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) +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. @@ -15,104 +15,133 @@ 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: +The data model is extended so that every **state** has an appointed notary: .. sourcecode:: kotlin - interface ContractState { - /** Contract by which the state belongs */ - val contract: Contract - - /** Identity of the notary that ensures this state is not used as an input to a transaction more than once */ - val notary: Party + /** + * 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). +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 +.. 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, +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, +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**) + Validation ---------- -The Notary *does not validate* transaction integrity (i.e. does not run contracts or check signatures) to minimise the exposed data. -Validation would require the caller to reveal the whole transaction history chain, resulting in a privacy leak. +One of the design decisions for a notary is whether or not to **validate** a transaction before committing its input states. -However, this makes it open to "denial of state" attacks, where a party could submit any invalid transaction to the Notary and thus "block" someone else's states. -That is partially alleviated by requiring the calling party to authenticate and storing its identity for the request. +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). + 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 the Notary can see the entire 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). - -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**) +.. 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. +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, +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. -Implementation & Usage ----------------------- +Running a Notary Service +------------------------ -At present we have single basic implementation of a Notary that uses a :code:`UniquenessProvider` storing committed input states in memory: +At present we have two basic implementations that store committed input states in memory: -.. sourcecode:: kotlin +- ``SimpleNotaryService`` -- commits the provided transaction without any validation - class InMemoryUniquenessProvider() : UniquenessProvider { - /** For each input state store the consuming transaction information */ - private val committedStates = HashMap() +- ``ValidatingNotaryService`` -- retrieves and validates the whole transaction history (including the given transaction) before committing - override fun commit(tx: WireTransaction, callerIdentity: Party) { - ... - } - } - ... - /** - * Specifies the transaction id, the position of the consumed state in the inputs, and - * the caller identity requesting the commit - */ - data class ConsumingTx(val id: SecureHash, val inputIndex: Int, val requestingParty: Party) +To run one of these services the node has to simply specify either ``SimpleNotaryService.Type`` or ``ValidatingNotaryService.Type`` in its ``advertisedServices`` set, and the correct type will be initialised. -To obtain a signature from a Notary use :code:`NotaryProtocol`, passing in a :code:`WireTransaction`. -The protocol will work out which Notary needs to be called based on the input states and the timestamp command. +Obtaining a signature +--------------------- + +To obtain a signature from a notary use ``NotaryProtocol.Client``, passing in a ``WireTransaction``. +The protocol will work out which notary needs to be called based on the input states and the timestamp command. For example, the following snippet can be used when writing a custom protocol: .. sourcecode:: kotlin - private fun getNotarySignature(wtx: WireTransaction): DigitalSignature.LegallyIdentifiable { - return subProtocol(NotaryProtocol(wtx)) + fun getNotarySignature(wtx: WireTransaction): DigitalSignature.LegallyIdentifiable { + return subProtocol(NotaryProtocol.Client(wtx)) } -On conflict the :code:`NotaryProtocol` with throw a :code:`NotaryException` containing the conflict details: +On conflict the ``NotaryProtocol`` with throw a ``NotaryException`` containing the conflict details: .. sourcecode:: kotlin /** Specifies the consuming transaction for the conflicting input state */ data class Conflict(val stateHistory: Map) -Conflict handling and resolution is currently the responsibility of the protocol author. \ No newline at end of file + /** + * Specifies the transaction id, the position of the consumed state in the inputs, and + * the caller identity requesting the commit + */ + data class ConsumingTx(val id: SecureHash, val inputIndex: Int, val requestingParty: Party) + +Conflict handling and resolution is currently the responsibility of the protocol author. + +Changing notaries +----------------- + +To change the notary for an input state, use the ``NotaryChangeProtocol``. For example: + +.. sourcecode:: kotlin + + fun changeNotary(originalState: StateAndRef, + newNotary: Party): StateAndRef { + val protocol = NotaryChangeProtocol.Instigator(originalState, newNotary) + return subProtocol(protocol) + } + +The protocol 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 \ No newline at end of file diff --git a/docs/build/html/_sources/event-scheduling.txt b/docs/build/html/_sources/event-scheduling.txt new file mode 100644 index 0000000000..9c2cacfd92 --- /dev/null +++ b/docs/build/html/_sources/event-scheduling.txt @@ -0,0 +1,102 @@ +.. highlight:: kotlin +.. raw:: html + + + + +Event scheduling +================ + +This article explains our experimental approach to modelling time based events in code. It explains how a contract +state can expose an upcoming event and what action to take if the scheduled time for that event is reached. + +Introduction +------------ + +Many financial instruments have time sensitive components to them. For example, an Interest Rate Swap has a schedule +for when: + +* Interest rate fixings should take place for floating legs, so that the interest rate used as the basis for payments + can be agreed. +* Any payments between the parties are expected to take place. +* Any payments between the parties become overdue. + +Each of these is dependent on the current state of the financial instrument. What payments and interest rate fixings +have already happened should already be recorded in the state, for example. This means that the *next* time sensitive +event is thus a property of the current contract state. By next, we mean earliest in chronological terms, that is still +due. If a contract state is consumed in the UTXO model, then what *was* the next event becomes irrelevant and obsolete +and the next time sensitive event is determined by any successor contract state. + +Knowing when the next time sensitive event is due to occur is useful, but typically some *activity* is expected to take +place when this event occurs. We already have a model for business processes in the form of the protocol state machines, +so in the platform we have introduced the concept of *scheduled activities* that can invoke protocol state machines +at a scheduled time. A contract state can optionally described the next scheduled activity for itself. If it omits +to do so, then nothing will be scheduled. + +How to implement scheduled events +--------------------------------- + +There are two main steps to implementing scheduled events: + +* Have your ``ContractState`` implementation also implement ``SchedulableState``. This requires a method named + ``nextScheduledActivity`` to be implemented which returns an optional ``ScheduledActivity`` instance. + ``ScheduledActivity`` captures what ``ProtocolLogic`` instance each node will run, to perform the activity, and when it + will run is described by a ``java.time.Instant``. Once your state implements this interface and is tracked by the + wallet, it can expect to be queried for the next activity when recorded via the ``ServiceHub.recordTransactions`` + method during protocols execution. +* If nothing suitable exists, implement a ``ProtocolLogic`` to be executed by each node as the activity itself. + The important thing to remember is that each node that is party to the transaction, in the current implementation, + will execute the same ``ProtocolLogic`` so that needs to establish roles in the business process based on the contract + state and the node it is running on, and follow different but complementary paths through the business logic. + +.. note:: The scheduler's clock always operates in the UTC time zone for uniformity, so any time zone logic must be + performed by the contract, using ``ZonedDateTime``. + +In the short term, until we have automatic protocol session set up, you will also likely need to install a network +handler to help with obtaining a unqiue and secure random session. An example is described below. + +The production and consumption of ``ContractStates`` is observed by the scheduler and the activities associated with +any consumed states are unscheduled. Any newly produced states are then queried via the ``nextScheduledActivity`` +method and if they do not return ``null`` then that activity is scheduled based on the content of the +``ScheduledActivity`` object returned. + +An example +---------- + +Let's take an example of the Interest Rate Swap fixings for our scheduled events. The first task is to implement the +``nextScheduledActivity`` method on the ``State``. + + +.. container:: codeset + + .. sourcecode:: kotlin + + override fun nextScheduledActivity(thisStateRef: StateRef, + protocolLogicRefFactory: ProtocolLogicRefFactory): ScheduledActivity? { + val nextFixingOf = nextFixingOf() ?: return null + + // This is perhaps not how we should determine the time point in the business day, but instead expect the + // schedule to detail some of these aspects. + val (instant, duration) = suggestInterestRateAnnouncementTimeWindow(index = nextFixingOf.name, + source = floatingLeg.indexSource, + date = nextFixingOf.forDay) + return ScheduledActivity(protocolLogicRefFactory.create(TwoPartyDealProtocol.FixingRoleDecider::class.java, + thisStateRef, duration), instant) + } + +The first thing this does is establish if there are any remaining fixings. If there are none, then it returns ``null`` +to indicate that there is no activity to schedule. Otherwise it calculates the ``Instant`` at which the interest rate +should become available and schedules an activity at that time to work out what roles each node will take in the fixing +business process and to take on those roles. That ``ProtocolLogic`` will be handed the ``StateRef`` for the interest +rate swap ``State`` in question, as well as a tolerance ``Duration`` of how long to wait after the activity is triggered +for the interest rate before indicating an error. + +.. note:: The use of the factory to create a ``ProtocolLogicRef`` instance to embed in the ``ScheduledActivity``. This is a + way to create a reference to the ``ProtocolLogic`` class and it's constructor parameters to instantiate that can be + checked against a per node whitelist of approved and allowable types as part of our overall security sandboxing. + +As previously mentioned, we currently need a small network handler to assist with session setup until the work to +automate that is complete. See the interest rate swap specific implementation ``FixingSessionInitiationHandler`` which +is responsible for starting a ``ProtocolLogic`` to perform one role in the fixing protocol with the ``sessionID`` sent +by the ``FixingRoleDecider`` on the other node which then launches the other role in the fixing protocol. Currently +the handler needs to be manually installed in the node. diff --git a/docs/build/html/_sources/index.txt b/docs/build/html/_sources/index.txt index f18a72c5a4..df3e876da5 100644 --- a/docs/build/html/_sources/index.txt +++ b/docs/build/html/_sources/index.txt @@ -41,6 +41,7 @@ Read on to learn: tutorial-contract protocol-state-machines oracles + event-scheduling .. toctree:: :maxdepth: 2 diff --git a/docs/build/html/_sources/inthebox.txt b/docs/build/html/_sources/inthebox.txt index 690932881c..25ed8e2afa 100644 --- a/docs/build/html/_sources/inthebox.txt +++ b/docs/build/html/_sources/inthebox.txt @@ -1,46 +1,46 @@ What's included? ================ -The current prototype consists of a small amount of code that defines: +The Corda prototype currently includes: -* Key data structures. +* A peer to peer network with message persistence and delivery retries. +* Key data structures for defining contracts and states. +* Smart contracts: + * Cash + * Cash obligations + * Interest rate swaps + * Commercial paper (implemented in both Java and Kotlin for comparison) * Algorithms that work with them, such as serialising, hashing, signing, and verification of the signatures. -* Two smart contracts that implement a notion of a cash claim and basic commercial paper (implemented twice, in two - different programming languages). These are simplified versions of the real things. -* Unit tests that check the algorithms do what is expected, and which verify the behaviour of the smart contracts. -* API documentation and tutorials (what you're reading) -* A simple standalone node that uses an embedded message queue broker as its P2P messaging layer. -* A trading demo that runs the node in either a listening/buying mode, or a connecting/selling mode, and swaps some - fake commercial paper assets for some self-issued IOU cash, using a generic *protocol framework*. -* It also includes two oracles: one for precise timestamping and another for interest rate swaps. +* API documentation and tutorials (what you're reading). +* A business process orchestration framework. +* Notary infrastructure for precise timestamping, and elimination of double spending without a blockchain. +* A simple REST API. Some things it does not currently include but should gain later are: * Sandboxing, distribution or publication of smart contract code -* A peer to peer network * Database persistence -* An API for integrating external software * A user interface for administration * Many other things -You can browse `the JIRA bug tracker `_. - The prototype's goal is rapid exploration of ideas. Therefore in places it takes shortcuts that a production system would not in order to boost productivity: * It uses an object graph serialization framework instead of a well specified, vendor neutral protocol. -* It uses secp256r1, an obsolete elliptic curve. * It uses the default, out of the box Apache Artemis MQ protocol instead of AMQP/1.0 (although switching should be easy) +* There is no inter-node SSL or other encryption yet. Contracts --------- The primary goal of this prototype is to implement various kinds of contracts and verify that useful business logic can be expressed with the data model, developing and refining an API along the way. To that end there are currently -two contracts in the repository: +four contracts in the repository: 1. Cash 2. Commercial paper +3. Nettable obligations +4. Interest rate swaps ``Cash`` implements the idea of a claim on some quantity of deposits at some institutional party, denominated in some currency, identified by some *deposit reference*. A deposit reference is an opaque byte array which is usable by @@ -57,12 +57,14 @@ contract is implemented twice, once in Java and once in a language called Kotlin ``InterestRateSwap`` implements a vanilla OTC same currency bilateral fixed / floating leg swap. For further details, see :doc:`irs` +``Obligation`` implements a bilaterally or multi-laterally nettable, fungible obligation that can default. + Each contract comes with unit tests. Kotlin ------ -The prototype is written in a language called `Kotlin `_. Kotlin is a language that targets the JVM +Corda is written in a language called `Kotlin `_. Kotlin is a language that targets the JVM and can be thought of as a simpler Scala, with much better Java interop. It is developed by and has commercial support from JetBrains, the makers of the IntelliJ IDE and other popular developer tools. @@ -71,11 +73,4 @@ Java for industrial use and as such, the syntax was carefully designed to be rea the language, after only a few minutes of introduction. Due to the seamless Java interop the use of Kotlin to extend the platform is *not* required and the tutorial shows how -to write contracts in both Kotlin and Java. You can `read more about why Kotlin is a potentially strong successor to Java here `_. - -Kotlin programs use the regular Java standard library and ordinary Java frameworks. Frameworks used at this time are: - -* JUnit for unit testing -* Kryo for serialisation (this is not intended to be permanent) -* Gradle for the build -* Guava for a few utility functions +to write contracts in both Kotlin and Java. You can `read more about why Kotlin is a potentially strong successor to Java here `_. \ No newline at end of file diff --git a/docs/build/html/_sources/release-notes.txt b/docs/build/html/_sources/release-notes.txt index f8dcde9f73..b78680b575 100644 --- a/docs/build/html/_sources/release-notes.txt +++ b/docs/build/html/_sources/release-notes.txt @@ -6,13 +6,72 @@ Here are brief summaries of what's changed between each snapshot release. Unreleased ---------- -Here are changes in git master that haven't yet made it to a snapshot release: +There are currently no unreleased changes. -* The cash contract has moved from com.r3corda.contracts to com.r3corda.contracts.cash. -* Amount class is now generic, to support non-currency types (such as assets, or currency with additional information). +Milestone 1 +----------- + +Highlights of this release: + +* Event scheduling. States in the ledger can now request protocols to be invoked at particular times, for states + considered relevant by the wallet. +* Upgrades to the notary/consensus service support: + + * There is now a way to change the notary controlling a state. + * You can pick between validating and non-validating notaries, these let you select your privacy/robustness tradeoff. + +* A new obligation contract that supports bilateral and multilateral netting of obligations, default tracking and + more. +* Improvements to the financial type system, with core classes and contracts made more generic. +* Switch to a better digital signature algorithm: ed25519 instead of the previous JDK default of secp256r1. +* A new integration test suite. +* A new Java unit testing DSL for contracts, similar in spirit to the one already developed for Kotlin users (which + depended on Kotlin specific features). +* An experimental module, where developers who want to work with the latest Corda code can check in contracts/cordapp + code before it's been fully reviewed. Code in this module has compiler warnings suppressed but we will still make + sure it compiles across refactorings. +* Persistence improvements: transaction data is now stored to disk and automatic protocol resume is now implemented. +* Many smaller bug fixes, cleanups and improvements. + +We have new documentation on: + +* :doc:`event-scheduling` +* :doc:`transaction-data-types` +* :doc:`consensus` + +Summary of API changes (not exhaustive): + +* Notary/consensus service: + + * ``NotaryService`` is now extensible. + * Every ``ContractState`` now has to specify a *participants* field, which is a list of parties that are able to + consume this state in a valid transaction. This is used for e.g. making sure all relevant parties obtain the updated + state when changing a notary. + * Introduced ``TransactionState``, which wraps ``ContractState``, and is used when defining a transaction output. + The notary field is moved from ``ContractState`` into ``TransactionState``. + * Every transaction now has a *type* field, which specifies custom build & validation rules for that transaction type. + Currently two types are supported: General (runs the default build and validation logic) and NotaryChange ( + contract code is not run during validation, checks that the notary field is the only difference between the + inputs and outputs). + ``TransactionBuilder()`` is now abstract, you should use ``TransactionType.General.Builder()`` for building transactions. + +* The cash contract has moved from ``com.r3corda.contracts`` to ``com.r3corda.contracts.cash`` +* ``Amount`` class is now generic, to support non-currency types such as physical assets. Where you previously had just + ``Amount``, you should now use ``Amount``. * Refactored the Cash contract to have a new FungibleAsset superclass, to model all countable assets that can be merged and split (currency, barrels of oil, etc.) +* Messaging: + * ``addMessageHandler`` now has a different signature as part of error handling changes. + * If you want to return nothing to a protocol, use ``Ack`` instead of ``Unit`` from now on. + +* In the IRS contract, dateOffset is now an integer instead of an enum. +* In contracts, you now use ``tx.getInputs`` and ``tx.getOutputs`` instead of ``getInStates`` and ``getOutStates``. This is + just a renaming. +* A new ``NonEmptySet`` type has been added for cases where you wish to express that you have a collection of unique + objects which cannot be empty. +* Please use the global ``newSecureRandom()`` function rather than instantiating your own SecureRandom's from now on, as + the custom function forces the use of non-blocking random drivers on Linux. Milestone 0 ----------- @@ -24,4 +83,4 @@ This is the first release, which includes: * The first version of the protocol/orchestration framework * Some initial support for pluggable consensus mechanisms * Tutorials and documentation explaining how it works -* Much more ... \ No newline at end of file +* Much more ... diff --git a/docs/build/html/_sources/running-the-demos.txt b/docs/build/html/_sources/running-the-demos.txt index 93499522a5..a064258f66 100644 --- a/docs/build/html/_sources/running-the-demos.txt +++ b/docs/build/html/_sources/running-the-demos.txt @@ -73,9 +73,7 @@ And in the second run: ./build/install/r3prototyping/bin/irsdemo --role=NodeB -The node in the first terminal will complain that it didn't know about nodeB, so restart it. It'll then find the -location and identity keys of nodeA and be happy. NodeB also doubles up as the interest rates oracle and you should -see some rates data get loaded. +NodeB also doubles up as the interest rates oracle and you should see some rates data get loaded. Now in the third terminal run: diff --git a/docs/build/html/_sources/transaction-data-types.txt b/docs/build/html/_sources/transaction-data-types.txt index 20872a7c01..49ea4e2ac8 100644 --- a/docs/build/html/_sources/transaction-data-types.txt +++ b/docs/build/html/_sources/transaction-data-types.txt @@ -1,5 +1,5 @@ -Transaction Data Types -====================== +Data types +========== There is a large library of data types used in Corda transactions and contract state objects. @@ -27,15 +27,18 @@ delivered (themselves referring to a currency), an ``Amount`` such as the follow Amount> -Contract State --------------- +State +----- A Corda contract is composed of three parts; the executable code, the legal prose, and the state objects that represent the details of the contract (see :doc:`data-model` for further detail). States essentially convert the generic template -(code and legal prose) into a specific instance. In a ``WireTransaction``, outputs are provided as ``ContractState`` +(code and legal prose) into a specific instance. In a ``WireTransaction``, outputs are provided as ``TransactionState`` implementations, while the inputs are references to the outputs of a previous transaction. These references are then stored as ``StateRef`` objects, which are converted to ``StateAndRef`` on demand. +The ``TransactionState`` is a 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`). + A number of interfaces then extend ``ContractState``, representing standardised functionality for states: ``OwnableState`` @@ -64,8 +67,8 @@ interface for its subclasses' state objects to implement. The clear use-case 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 Types ------------------ +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 @@ -84,7 +87,7 @@ for signatures present on the transaction, as well as list of parties for those .. note:: These types are provisional and are likely to change in future, for example to add additional information to ``Party``. -Date Support +Date support ------------ There are a number of supporting interfaces and classes for use by contract which deal with dates (especially in the diff --git a/docs/build/html/api/alltypes/index.html b/docs/build/html/api/alltypes/index.html index aede8b799b..4087f54f7b 100644 --- a/docs/build/html/api/alltypes/index.html +++ b/docs/build/html/api/alltypes/index.html @@ -56,8 +56,15 @@ I/O), or a mock implementation suitable for unit test environments.

+ + + + @@ -83,6 +90,14 @@ We dont actually do anything with this yet though, so its ignored for now.

+ + + + + + + + + + + + - - - - @@ -181,6 +201,13 @@ API call from a single party without bi-directional access to the database of of + + + + +com.r3corda.contracts.asset.Cash + + + + + + + + @@ -319,7 +359,9 @@ timestamp attached to the transaction itself i.e. it is NOT necessarily the curr @@ -331,6 +373,12 @@ updated, instead, any changes must generate a new successor state.

+ + + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + +com.r3corda.contracts.asset.FungibleAsset +com.r3corda.contracts.asset.FungibleAssetState + + + + @@ -610,6 +699,12 @@ service would provide.

+ + + + +com.r3corda.core.testing.InMemoryWalletService + + + + @@ -718,6 +822,21 @@ from which the state object is initialised.

+ + + + + + + + @@ -730,7 +849,32 @@ from which the state object is initialised.

+kotlin.collections.Iterable (extensions in package com.r3corda.contracts.asset) + + + + + + + + + + + + + + + + @@ -758,12 +902,29 @@ call out to a hardware security module that enforces various auditing and freque + + + + + + + + + + + + + + + + @@ -1026,11 +1202,18 @@ rate fix (e.g. LIBOR, EURIBOR ...).

+ + + + @@ -1038,7 +1221,32 @@ states relevant to us into a database and once such a wallet is implemented, thi com.r3corda.core.utilities.NonEmptySet + + + + + + + + + + + + @@ -1074,6 +1282,16 @@ construction, and attempting to remove the last element will cause an IllegalSta + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1399,6 +1683,14 @@ functionality and you dont want to hard-code which types in the interface.

+ + + + + + + + + + + + + + + + - - - - - - - - @@ -1632,6 +1931,14 @@ multiple parties.

+ + + + @@ -1674,6 +1981,14 @@ this subgraph does not contain conflicts and is accepted by the involved contrac + + + + + + + + @@ -1711,6 +2033,13 @@ and seller) and the following steps:

+ + + + @@ -1782,22 +2110,6 @@ about new transactions from our peers and generate new transactions that consume - - - - - - - - +State(issuance: PartyAndReference, owner: PublicKey, faceValue: Amount<Issued<Currency>>, maturityDate: Instant)
sumCashBy -fun Iterable<ContractState>.sumCashBy(owner: PublicKey): <ERROR CLASS>

Sums the cash states in the list belonging to a single owner, throwing an exception +fun Iterable<ContractState>.sumCashBy(owner: PublicKey): <ERROR CLASS>

Sums the cash states in the list belonging to a single owner, throwing an exception if there are none, or if any of the cash states cannot be added together (i.e. are different currencies).

sumCashOrZero -fun Iterable<ContractState>.sumCashOrZero(currency: Currency): <ERROR CLASS>

Sums the cash states in the list, returning zero of the given currency if there are none.

+fun Iterable<ContractState>.sumCashOrZero(currency: Currency): <ERROR CLASS>

Sums the cash states in the list, returning zero of the given currency if there are none.

sumFungibleBy -fun <T> Iterable<ContractState>.sumFungibleBy(owner: PublicKey): <ERROR CLASS>

Sums the asset states in the list belonging to a single owner, throwing an exception +fun <T> Iterable<ContractState>.sumFungibleBy(owner: PublicKey): <ERROR CLASS>

Sums the asset states in the list belonging to a single owner, throwing an exception if there are none, or if any of the asset states cannot be added together (i.e. are different tokens).

sumFungibleOrZero -fun <T> Iterable<ContractState>.sumFungibleOrZero(token: T): <ERROR CLASS>

Sums the asset states in the list, returning zero of the given token if there are none.

+fun <T> Iterable<ContractState>.sumFungibleOrZero(token: T): <ERROR CLASS>

Sums the asset states in the list, returning zero of the given token if there are none.

issued by -infix fun State.issued by(party: Party): State
owned by -infix fun State.owned by(owner: PublicKey): State
+infix fun State.owned by(owner: PublicKey): State
infix fun State.owned by(owner: PublicKey): State
infix fun <ERROR CLASS>.owned by(new_owner: PublicKey): <ERROR CLASS>
generateRedeem -fun generateRedeem(tx: TransactionBuilder, paper: StateAndRef<State>, wallet: List<StateAndRef<State>>): Unit

Intended to be called by the issuer of some commercial paper, when an owner has notified us that they wish +fun generateRedeem(tx: TransactionBuilder, paper: StateAndRef<State>, wallet: List<StateAndRef<State>>): Unit

Intended to be called by the issuer of some commercial paper, when an owner has notified us that they wish to redeem the paper. We must therefore send enough money to the key that owns the paper to satisfy the face value, and then ensure the paper is removed from the ledger.

-com.r3corda.contracts.cash
com.r3corda.protocols.AbstractRequestMessage -

Abstract superclass for request messages sent to services, which includes common -fields such as replyTo and replyToTopic.

+
+protocols.AbstractStateReplacementProtocol +

Abstract protocol to be used for replacing one state with another, for example when changing the notary of a state. +Notably this requires a one to one replacement of states, states cannot be split, merged or issued as part of these +protocols.

+com.r3corda.core.messaging.Ack +

A general Ack message that conveys no content other than its presence for use when you want an acknowledgement +from a recipient. Using Unit can be ambiguous as it is similar to Void and so could mean no response.

+
com.r3corda.node.utilities.AddOrRemove

Enum for when adding/removing something, for example adding or removing an entry in a directory.

@@ -105,6 +120,12 @@ for ensuring code runs on the right thread, and also for unit testing.

+com.r3corda.core.testing.AlwaysSucceedContract +
com.r3corda.core.contracts.Amount

Amount represents a positive quantity of some token (currency, asset, etc.), measured in quantity of the smallest @@ -114,6 +135,14 @@ amount used in whatever underlying thing the amount represents.

+com.r3corda.core.protocols.AppContext +

This is just some way to track what attachments need to be in the class loader, but may later include some app +properties loaded from the attachments. And perhaps the authenticated user for an API call?

+
com.r3corda.node.services.messaging.ArtemisMessagingService

This class implements the MessagingService API using Apache Artemis, the successor to their ActiveMQ product. @@ -124,14 +153,6 @@ as well.

-com.r3corda.contracts.asset.AssetIssuanceDefinition -

Subset of cash-like contract state, containing the issuance definition. If these definitions match for two -contracts states, those states can be aggregated.

-
com.r3corda.core.contracts.Attachment

An attachment is a ZIP (or an optionally signed JAR) that contains one or more files. Attachments are meant to @@ -150,8 +171,7 @@ of how attachments are meant to be used include:

com.r3corda.core.node.services.AttachmentStorage -

An attachment store records potentially large binary objects, identified by their hash. Note that attachments are -immutable and can never be erased once inserted

+

An attachment store records potentially large binary objects, identified by their hash.

+com.r3corda.core.contracts.BilateralNettableState +

Interface for state objects that support being netted with other state objects.

+
com.r3corda.core.utilities.BriefLogFormatter

A Java logging formatter that writes more compact output than the default.

@@ -209,7 +236,7 @@ no staff are around to handle problems.

-com.r3corda.contracts.asset.Cash

A cash transaction may split and merge money represented by a set of (issuer, depositRef) pairs, across multiple input and output states. Imagine a Bitcoin transaction but in which all UTXOs had a colour @@ -246,6 +273,19 @@ the same transaction.

+com.r3corda.demos.CliParams +

Parsed command line parameters.

+
+com.r3corda.demos.CliParamsSpec +
java.time.Clock (extensions in package com.r3corda.node.utilities)

A contract state (or just "state") contains opaque data used by a contract program. It can be thought of as a disk file that the program can use to persist data across transactions. States are immutable: once created they are never -updated, instead, any changes must generate a new successor state.

+updated, instead, any changes must generate a new successor state. States can be updated (consumed) only once: the +notary is responsible for ensuring there is no "double spending" by only signing a transaction if the input states +are all free.

+java.util.Currency (extensions in package com.r3corda.core.contracts) +
com.r3corda.node.servlets.DataUploadServlet

Accepts binary streams, finds the right AcceptsFileUpload implementor and hands the stream off to it.

@@ -346,14 +394,6 @@ glue that sits between the network layer and the database layer.

-com.r3corda.core.contracts.DateOffset -

Date offset that the fixing is done prior to the accrual start date. -Currently not used in the calculation.

-
com.r3corda.core.contracts.DateRollConvention

This reflects what happens if a date on which a business event is supposed to happen actually falls upon a non-working day @@ -402,6 +442,13 @@ implementation of general protocols that manipulate many agreement types.

+com.r3corda.core.serialization.DeserializeAsKotlinObjectDef +

Marker interface for kotlin object definitions so that they are deserialized as the singleton instance.

+
com.r3corda.core.crypto.DigitalSignature

A wrapper around a digital signature. The covering field is a generic tag usable by whatever is interpreting the @@ -429,12 +476,25 @@ building partially signed transactions.

+com.r3corda.core.testing.DummyLinearState +
com.r3corda.core.crypto.DummyPublicKey
+com.r3corda.core.contracts.DummyState +

Dummy state for use in testing. Not part of any real contract.

+
com.r3corda.node.services.keys.E2ETestKeyManagementService

A simple in-memory KMS that doesnt bother saving keys to disk. A real implementation would:

@@ -442,6 +502,20 @@ building partially signed transactions.

+com.r3corda.core.serialization.Ed25519PrivateKeySerializer +

For serialising an ed25519 private key

+
+com.r3corda.core.serialization.Ed25519PublicKeySerializer +

For serialising an ed25519 public key

+
com.r3corda.core.utilities.Emoji

A simple wrapper class that contains icons and support for printing them only when were connected to a terminal.

@@ -546,6 +620,14 @@ Assumes that the rate is valid.

+com.r3corda.node.services.FixingSessionInitiationHandler +

This is a temporary handler required for establishing random sessionIDs for the Fixer and Floater as part of +running scheduled fixings for the InterestRateSwap contract.

+
com.r3corda.contracts.FloatingRate

The parent class of the Floating rate classes

@@ -569,7 +651,7 @@ that would divide into (eg annually = 1, semiannual = 2, monthly = 12 etc).

-com.r3corda.contracts.asset.FungibleAsset

Superclass for contracts 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 @@ -581,15 +663,22 @@ countable, and so on.

-com.r3corda.contracts.asset.FungibleAssetState

Common elements of cash contract states.

+com.r3corda.demos.IRSDemoNode +
com.r3corda.demos.IRSDemoRole +

Roles. There are 4 modes this demo can be run:

+com.r3corda.core.protocols.IllegalProtocolLogicException +
com.r3corda.core.serialization.ImmutableClassSerializer

Serializes properties and deserializes by using the constructor. This assumes that all backed properties are @@ -656,7 +751,16 @@ testing).

-com.r3corda.contracts.asset.InsufficientBalanceException +

This class implements a simple, in memory wallet that tracks states that are owned by us, and also has a convenience +method to auto-generate some self-issued cash states that can be used for test trading. A real wallet would persist +states relevant to us into a database and once such a wallet is implemented, this scaffolding can be removed.

+
+com.r3corda.contracts.asset.InsufficientBalanceException
+com.r3corda.core.contracts.IssueCommand +

A common issue command, to enforce that issue commands have a nonce value.

+
+com.r3corda.core.contracts.Issued +

Definition for an issued product, which can be cash, a cash-like thing, assets, or generally anything else thats +quantifiable with integer quantities.

+
kotlin.collections.Iterable (extensions in package com.r3corda.core.contracts)
-kotlin.collections.Iterable (extensions in package com.r3corda.contracts.cash) +
+kotlin.collections.Iterable (extensions in package com.r3corda.node.internal.testing) +
+com.r3corda.core.contracts.JavaTestHelpers +
+com.r3corda.core.testing.JavaTestHelpers +

JAVA INTEROP. Please keep the following points in mind when extending the Kotlin DSL

+
+com.r3corda.contracts.testing.JavaTestHelpers
+com.r3corda.core.serialization.KotlinObjectSerializer +

Serializer to deserialize kotlin object definitions marked with DeserializeAsKotlinObjectDef.

+
com.r3corda.core.testing.LabeledOutput
+com.r3corda.core.testing.LastLineShouldTestForAcceptOrFailure +

If you jumped here from a compiler error make sure the last line of your test tests for a transaction accept or fail +This is a dummy type that can only be instantiated by functions in this module. This way we can ensure that all tests +will have as the last line either an accept or a failure test. The name is deliberately long to help make sense of +the triggered diagnostic

+
com.r3corda.core.contracts.LedgerTransaction

A LedgerTransaction wraps the data needed to calculate one or more successor states from a set of input states. @@ -917,6 +1078,13 @@ This is not an interface because it is too lightweight to bother mocking out.

+com.r3corda.core.contracts.MoveCommand +

A common move command for contracts which can change owner.

+
com.r3corda.node.utilities.MutableClock

An abstract class with helper methods for a type of Clock that might have its concept of "now" @@ -932,6 +1100,14 @@ adjusted externally.

+com.r3corda.core.contracts.NetType +

Enum for the types of netting that can be applied to state objects. Exact behaviour +for each type of netting is left to the contract to determine.

+
com.r3corda.core.node.services.NetworkCacheError
+com.r3corda.node.services.events.NodeSchedulerService +

A first pass of a simple SchedulerService that works with MutableClocks for testing, demonstrations and simulations +that also encompasses the Wallet observer for processing transactions.

+
com.r3corda.node.services.wallet.NodeWalletService -

This class implements a simple, in memory wallet that tracks states that are owned by us, and also has a convenience -method to auto-generate some self-issued cash states that can be used for test trading. A real wallet would persist -states relevant to us into a database and once such a wallet is implemented, this scaffolding can be removed.

+

Currently, the node wallet service is just the in-memory wallet service until we have finished evaluating and +selecting a persistence layer (probably an ORM over a SQL DB).

A set which is constrained to ensure it can never be empty. An initial value must be provided at -construction, and attempting to remove the last element will cause an IllegalStateException.

+construction, and attempting to remove the last element will cause an IllegalStateException. +The underlying set is exposed for Kryo to access, but should not be accessed directly.

+
+com.r3corda.core.utilities.NonEmptySetSerializer +

Custom serializer which understands it has to read in an item before +trying to construct the set.

+
+protocols.NotaryChangeProtocol +

A protocol to be used for changing a states Notary. This is required since all input states to a transaction +must point to the same notary.

+
+com.r3corda.node.services.NotaryChangeService +

A service that monitors the network for requests for changing the notary of a state, +and immediately runs the NotaryChangeProtocol if the auto-accept criteria are met.

+com.r3corda.contracts.asset.Obligation +

An obligation contract commits the obligor to delivering a specified amount of a fungible asset (for example the +Cash contract) at a specified future point in time. Settlement transactions may split and merge contracts across +multiple input and output states. The goal of this design is to handle amounts owed, and these contracts are expected +to be netted/merged, with settlement only for any remainder amount.

+
com.r3corda.core.serialization.OpaqueBytes

A simple class that wraps a byte array and makes the equals/hashCode/toString methods work as you actually expect. @@ -1197,6 +1415,20 @@ a node crash, how many instances of your protocol there are running and so on.

+com.r3corda.core.protocols.ProtocolLogicRef +

A class representing a ProtocolLogic instance which would be possible to safely pass out of the contract sandbox

+
+com.r3corda.core.protocols.ProtocolLogicRefFactory +

A class for conversion to and from ProtocolLogic and ProtocolLogicRef instances

+
com.r3corda.node.api.ProtocolRef

Encapsulates the protocol to be instantiated. e.g. TwoPartyTradeProtocol.Buyer.

@@ -1267,6 +1499,13 @@ for each step.

+com.r3corda.core.node.services.ReadOnlyTransactionStorage +

Thread-safe storage of transactions.

+
com.r3corda.core.utilities.RecordingMap

A RecordingMap wraps a regular Map<K, V> and records the sequence of gets and puts to it. This is useful in @@ -1333,6 +1572,51 @@ again.

+com.r3corda.core.contracts.SchedulableState +
+com.r3corda.core.contracts.Scheduled +

Something which is scheduled to happen at a point in time

+
+com.r3corda.core.contracts.ScheduledActivity +

This class represents the lifecycle activity that a contract state of type LinearState would like to perform at a given point in time. +e.g. run a fixing protocol

+
+com.r3corda.node.services.events.ScheduledActivityObserver +

This observes the wallet and schedules and unschedules activities appropriately based on state production and +consumption.

+
+com.r3corda.core.contracts.ScheduledStateRef +

Represents a contract state (unconsumed output) of type LinearState and a point in time that a lifecycle event is expected to take place +for that contract state.

+
+com.r3corda.core.node.services.SchedulerService +

Provides access to schedule activity at some point in time. This interface might well be expanded to +increase the feature set in the future.

+
com.r3corda.core.crypto.SecureHash
+com.r3corda.protocols.ServiceRequestMessage +

Abstract superclass for request messages sent to services, which includes common +fields such as replyTo and replyToTopic.

+
com.r3corda.core.node.services.ServiceType

Identifier for service types a node can expose over the network to other peers. These types are placed into network @@ -1497,6 +1789,19 @@ transaction defined the state and where in that transaction it was.

+protocols.StateReplacementException +
+protocols.StateReplacementRefused +

Thrown when a participant refuses proposed the state replacement

+
com.r3corda.node.api.StatesQuery

Extremely rudimentary query language which should most likely be replaced with a product

@@ -1567,6 +1872,13 @@ way that ensures itll be released if theres an exception.

+com.r3corda.core.utilities.TimeWindow +

A class representing a window in time from a particular instant, lasting a specified duration.

+
com.r3corda.core.node.services.TimestampChecker

Checks if the given timestamp falls within the allowed tolerance interval

@@ -1597,18 +1909,6 @@ then B and C trade with each other, then C and A etc).

-com.r3corda.demos.TraderDemoProtocolBuyer -
-com.r3corda.demos.TraderDemoProtocolSeller -
com.r3corda.node.api.TransactionBuildStep

Encapsulate a generateXXX method call on a contract.

@@ -1619,9 +1919,8 @@ then B and C trade with each other, then C and A etc).

com.r3corda.core.contracts.TransactionBuilder

A TransactionBuilder is a transaction class thats mutable (unlike the others which are all immutable). It is -intended to be passed around contracts that may edit it by adding new states/commands or modifying the existing set. -Then once the states and commands are right, this class can be used as a holding bucket to gather signatures from -multiple parties.

+intended to be passed around contracts 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.

+com.r3corda.core.contracts.TransactionForContract +

A transaction to be passed as input to a contract verification function. Defines helper methods to +simplify verification logic in contracts.

+
com.r3corda.core.testing.TransactionForTest
+com.r3corda.core.contracts.TransactionState +

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.

+
com.r3corda.core.node.services.TransactionStorage

Thread-safe storage of transactions.

@@ -1681,6 +1996,13 @@ this subgraph does not contain conflicts and is accepted by the involved contrac
+com.r3corda.core.contracts.TransactionType +

Defines transaction build & validation logic for a specific transaction type

+
com.r3corda.core.contracts.TransactionVerificationException
+com.r3corda.core.node.services.TxWritableStorageService +

Storage service, with extensions to allow validated transactions to be added to. For use only within ServiceHub.

+
com.r3corda.core.contracts.TypeOnlyCommandData

Commands that inherit from this are intended to have no data items: its only their presence that matters.

@@ -1749,8 +2078,7 @@ first. The wrapper helps you to avoid forgetting this vital step. Things you mig
com.r3corda.demos.protocols.UpdateBusinessDayProtocol -

This is a very temporary, demo-oriented way of initiating processing of temporal events and is not -intended as the way things will necessarily be done longer term

+

This is a less temporary, demo-oriented way of initiating processing of temporal events

-com.r3corda.node.internal.testing.WalletFiller -
-com.r3corda.node.services.wallet.WalletImpl -

A wallet (name may be temporary) wraps a set of states that are useful for us to keep track of, for instance, -because we own them. This class represents an immutable, stable state of a wallet: it is guaranteed not to -change out from underneath you, even though the canonical currently-best-known wallet may change as we learn -about new transactions from our peers and generate new transactions that consume states ourselves.

-
com.r3corda.core.node.services.WalletService

A WalletService is responsible for securely and safely persisting the current state of a wallet to storage. The diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-c-a-s-h_-p-r-o-g-r-a-m_-i-d.html b/docs/build/html/api/com.r3corda.contracts.asset/-c-a-s-h_-p-r-o-g-r-a-m_-i-d.html new file mode 100644 index 0000000000..663d79fe8f --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-c-a-s-h_-p-r-o-g-r-a-m_-i-d.html @@ -0,0 +1,15 @@ + + +CASH_PROGRAM_ID - + + + +com.r3corda.contracts.asset / CASH_PROGRAM_ID
+
+

CASH_PROGRAM_ID

+ +val CASH_PROGRAM_ID: Cash
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/-exit/-init-.html b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/-exit/-init-.html new file mode 100644 index 0000000000..9d2bb595b7 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/-exit/-init-.html @@ -0,0 +1,16 @@ + + +Cash.Commands.Exit.<init> - + + + +com.r3corda.contracts.asset / Cash / Commands / Exit / <init>
+
+

<init>

+Exit(amount: Amount<Issued<Currency>>)
+

A command stating that money has been withdrawn from the shared ledger and is now accounted for +in some other way.

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/-exit/amount.html b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/-exit/amount.html new file mode 100644 index 0000000000..422f093494 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/-exit/amount.html @@ -0,0 +1,16 @@ + + +Cash.Commands.Exit.amount - + + + +com.r3corda.contracts.asset / Cash / Commands / Exit / amount
+
+

amount

+ +val amount: Amount<Issued<Currency>>
+Overrides Exit.amount
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/-exit/index.html b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/-exit/index.html new file mode 100644 index 0000000000..b94696ccd6 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/-exit/index.html @@ -0,0 +1,40 @@ + + +Cash.Commands.Exit - + + + +com.r3corda.contracts.asset / Cash / Commands / Exit
+
+

Exit

+data class Exit : Commands, Exit<Currency>
+

A command stating that money has been withdrawn from the shared ledger and is now accounted for +in some other way.

+
+
+

Constructors

+ + + + + + + +
+<init> +Exit(amount: Amount<Issued<Currency>>)

A command stating that money has been withdrawn from the shared ledger and is now accounted for +in some other way.

+
+

Properties

+ + + + + + + +
+amount +val amount: Amount<Issued<Currency>>
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/-issue/-init-.html b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/-issue/-init-.html new file mode 100644 index 0000000000..4f6712998b --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/-issue/-init-.html @@ -0,0 +1,16 @@ + + +Cash.Commands.Issue.<init> - + + + +com.r3corda.contracts.asset / Cash / Commands / Issue / <init>
+
+

<init>

+Issue(nonce: Long = newSecureRandom().nextLong())
+

Allows new cash states to be issued into existence: the nonce ("number used once") ensures the transaction +has a unique ID even when there are no inputs.

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/-issue/index.html b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/-issue/index.html new file mode 100644 index 0000000000..ae387254ae --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/-issue/index.html @@ -0,0 +1,40 @@ + + +Cash.Commands.Issue - + + + +com.r3corda.contracts.asset / Cash / Commands / Issue
+
+

Issue

+data class Issue : Issue, Commands
+

Allows new cash states to be issued into existence: the nonce ("number used once") ensures the transaction +has a unique ID even when there are no inputs.

+
+
+

Constructors

+ + + + + + + +
+<init> +Issue(nonce: Long = newSecureRandom().nextLong())

Allows new cash states to be issued into existence: the nonce ("number used once") ensures the transaction +has a unique ID even when there are no inputs.

+
+

Properties

+ + + + + + + +
+nonce +val nonce: Long
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/-issue/nonce.html b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/-issue/nonce.html new file mode 100644 index 0000000000..95a9822b02 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/-issue/nonce.html @@ -0,0 +1,16 @@ + + +Cash.Commands.Issue.nonce - + + + +com.r3corda.contracts.asset / Cash / Commands / Issue / nonce
+
+

nonce

+ +val nonce: Long
+Overrides IssueCommand.nonce
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/-move/-init-.html b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/-move/-init-.html new file mode 100644 index 0000000000..e2e384ed92 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/-move/-init-.html @@ -0,0 +1,20 @@ + + +Cash.Commands.Move.<init> - + + + +com.r3corda.contracts.asset / Cash / Commands / Move / <init>
+
+

<init>

+Move(contractHash: SecureHash? = null)
+

A command stating that money has been moved, optionally to fulfil another contract.

+

Parameters

+ +contractHash - the contract this move is for the attention of. Only that contracts verify function +should take the moved states into account when considering whether it is valid. Typically this will be +null.
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/-move/contract-hash.html b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/-move/contract-hash.html new file mode 100644 index 0000000000..59d46a8707 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/-move/contract-hash.html @@ -0,0 +1,18 @@ + + +Cash.Commands.Move.contractHash - + + + +com.r3corda.contracts.asset / Cash / Commands / Move / contractHash
+
+

contractHash

+ +val contractHash: SecureHash?
+Overrides MoveCommand.contractHash
+

Contract code the moved state(s) are for the attention of, for example to indicate that the states are moved in +order to settle an obligation contracts state object(s).

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/-move/index.html b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/-move/index.html new file mode 100644 index 0000000000..11985568ed --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/-move/index.html @@ -0,0 +1,45 @@ + + +Cash.Commands.Move - + + + +com.r3corda.contracts.asset / Cash / Commands / Move
+
+

Move

+data class Move : Move, Commands
+

A command stating that money has been moved, optionally to fulfil another contract.

+

Parameters

+ +contractHash - the contract this move is for the attention of. Only that contracts verify function +should take the moved states into account when considering whether it is valid. Typically this will be +null.
+
+
+

Constructors

+ + + + + + + +
+<init> +Move(contractHash: SecureHash? = null)

A command stating that money has been moved, optionally to fulfil another contract.

+
+

Properties

+ + + + + + + +
+contractHash +val contractHash: SecureHash?

Contract code the moved state(s) are for the attention of, for example to indicate that the states are moved in +order to settle an obligation contracts state object(s).

+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/index.html b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/index.html new file mode 100644 index 0000000000..46bf5ea78c --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-commands/index.html @@ -0,0 +1,70 @@ + + +Cash.Commands - + + + +com.r3corda.contracts.asset / Cash / Commands
+
+

Commands

+interface Commands : CommandData
+
+
+

Types

+ + + + + + + + + + + + + + + +
+Exit +data class Exit : Commands, Exit<Currency>

A command stating that money has been withdrawn from the shared ledger and is now accounted for +in some other way.

+
+Issue +data class Issue : Issue, Commands

Allows new cash states to be issued into existence: the nonce ("number used once") ensures the transaction +has a unique ID even when there are no inputs.

+
+Move +data class Move : Move, Commands

A command stating that money has been moved, optionally to fulfil another contract.

+
+

Inheritors

+ + + + + + + + + + + + + + + +
+Exit +data class Exit : Commands, Exit<Currency>

A command stating that money has been withdrawn from the shared ledger and is now accounted for +in some other way.

+
+Issue +data class Issue : Issue, Commands

Allows new cash states to be issued into existence: the nonce ("number used once") ensures the transaction +has a unique ID even when there are no inputs.

+
+Move +data class Move : Move, Commands

A command stating that money has been moved, optionally to fulfil another contract.

+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-cash/-init-.html b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-init-.html new file mode 100644 index 0000000000..c8ee015072 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-init-.html @@ -0,0 +1,25 @@ + + +Cash.<init> - + + + +com.r3corda.contracts.asset / Cash / <init>
+
+

<init>

+Cash()
+

A cash transaction may split and merge money represented by a set of (issuer, depositRef) pairs, across multiple +input and output states. Imagine a Bitcoin transaction but in which all UTXOs had a colour +(a blend of issuer+depositRef) and you couldnt merge outputs of two colours together, but you COULD put them in +the same transaction.

+

The goal of this design is to ensure that money can be withdrawn from the ledger easily: if you receive some money +via this contract, you always know where to go in order to extract it from the R3 ledger, no matter how many hands +it has passed through in the intervening time.

+

At the same time, other contracts that just want money and dont care much who is currently holding it in their +vaults can ignore the issuer/depositRefs and just examine the amount fields.

+
+
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/-init-.html b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/-init-.html new file mode 100644 index 0000000000..e51cfe241a --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/-init-.html @@ -0,0 +1,18 @@ + + +Cash.State.<init> - + + + +com.r3corda.contracts.asset / Cash / State / <init>
+
+

<init>

+State(deposit: PartyAndReference, amount: Amount<Currency>, owner: PublicKey)
+
+
+State(amount: Amount<Issued<Currency>>, owner: PublicKey)
+

A state representing a cash claim against some party

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/amount.html b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/amount.html new file mode 100644 index 0000000000..d95375d7f4 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/amount.html @@ -0,0 +1,16 @@ + + +Cash.State.amount - + + + +com.r3corda.contracts.asset / Cash / State / amount
+
+

amount

+ +val amount: Amount<Issued<Currency>>
+Overrides State.amount
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/contract.html b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/contract.html new file mode 100644 index 0000000000..6ec51867f3 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/contract.html @@ -0,0 +1,43 @@ + + +Cash.State.contract - + + + +com.r3corda.contracts.asset / Cash / State / contract
+
+

contract

+ +val contract: Cash
+Overrides ContractState.contract
+

An instance of the contract class that will verify this state.

+

Discussion

+

This field is not the final design, its just a piece of temporary scaffolding. Once the contract sandbox is +further along, this field will become a description of which attachments are acceptable for defining the +contract.

+

Recall that an attachment is a zip file that can be referenced from any transaction. The contents of the +attachments are merged together and cannot define any overlapping files, thus for any given transaction there +is a miniature file system in which each file can be precisely mapped to the defining attachment.

+

Attachments may contain many things (data files, legal documents, etc) but mostly they contain JVM bytecode. +The class files inside define not only Contract implementations but also the classes that define the states. +Within the rest of a transaction, user-providable components are referenced by name only.

+

This means that a smart contract in Corda does two things:

+
  1. Define the data structures that compose the ledger (the states)

    +
  2. Define the rules for updating those structures

    +

The first is merely a utility role ... in theory contract code could manually parse byte streams by hand. +The second is vital to the integrity of the ledger. So this field needs to be able to express constraints like:

+
  • Only attachment 733c350f396a727655be1363c06635ba355036bd54a5ed6e594fd0b5d05f42f6 may be used with this state.

    +
  • Any attachment signed by public key 2d1ce0e330c52b8055258d776c40 may be used with this state.

    +
  • Attachments (1, 2, 3) may all be used with this state.

    +

and so on. In this way it becomes possible for the business logic governing a state to be evolved, if the +constraints are flexible enough.

+

Because contract classes often also define utilities that generate relevant transactions, and because attachments +cannot know their own hashes, we will have to provide various utilities to assist with obtaining the right +code constraints from within the contract code itself.

+

TODO: Implement the above description. See COR-226

+
+
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/deposit.html b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/deposit.html new file mode 100644 index 0000000000..b05b967fc6 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/deposit.html @@ -0,0 +1,20 @@ + + +Cash.State.deposit - + + + +com.r3corda.contracts.asset / Cash / State / deposit
+
+

deposit

+ +val deposit: PartyAndReference
+Overrides State.deposit
+

Where the underlying currency backing this ledger entry can be found (propagated)

+

Getter
+

Where the underlying currency backing this ledger entry can be found (propagated)

+

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/index.html b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/index.html new file mode 100644 index 0000000000..84f1bcfab9 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/index.html @@ -0,0 +1,132 @@ + + +Cash.State - + + + +com.r3corda.contracts.asset / Cash / State
+
+

State

+data class State : State<Currency>
+

A state representing a cash claim against some party

+
+
+

Constructors

+ + + + + + + +
+<init> +State(deposit: PartyAndReference, amount: Amount<Currency>, owner: PublicKey)State(amount: Amount<Issued<Currency>>, owner: PublicKey)

A state representing a cash claim against some party

+
+

Properties

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+amount +val amount: Amount<Issued<Currency>>
+contract +val contract: Cash

An instance of the contract class that will verify this state.

+
+deposit +val deposit: PartyAndReference

Where the underlying currency backing this ledger entry can be found (propagated)

+
+issuanceDef +val issuanceDef: Issued<Currency>
+owner +val owner: PublicKey

There must be a MoveCommand signed by this key to claim the amount

+
+participants +val participants: List<PublicKey>

A participant is any party that is able to consume this state in a valid transaction.

+
+productAmount +val productAmount: Amount<Currency>
+

Functions

+ + + + + + + + + + + + + + + +
+move +fun move(newAmount: Amount<Currency>, newOwner: PublicKey): State<Currency>
+toString +fun toString(): String
+withNewOwner +fun withNewOwner(newOwner: PublicKey): <ERROR CLASS>

Copies the underlying data structure, replacing the owner field with this new value and leaving the rest alone

+
+

Extension Functions

+ + + + + + + + + + + + + + + + + + + +
+issued by +infix fun State.issued by(party: Party): State
+infix fun State.issued by(deposit: PartyAndReference): State
+owned by +infix fun State.owned by(owner: PublicKey): <ERROR CLASS>
+with deposit +infix fun State.with deposit(deposit: PartyAndReference): State
+with notary +infix fun State.with notary(notary: Party): TransactionState<State>
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/issuance-def.html b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/issuance-def.html new file mode 100644 index 0000000000..53ff2162c2 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/issuance-def.html @@ -0,0 +1,16 @@ + + +Cash.State.issuanceDef - + + + +com.r3corda.contracts.asset / Cash / State / issuanceDef
+
+

issuanceDef

+ +val issuanceDef: Issued<Currency>
+Overrides FungibleAssetState.issuanceDef
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/move.html b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/move.html new file mode 100644 index 0000000000..f37e259715 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/move.html @@ -0,0 +1,15 @@ + + +Cash.State.move - + + + +com.r3corda.contracts.asset / Cash / State / move
+
+

move

+ +fun move(newAmount: Amount<Currency>, newOwner: PublicKey): State<Currency>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/owner.html b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/owner.html new file mode 100644 index 0000000000..60b915aa35 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/owner.html @@ -0,0 +1,17 @@ + + +Cash.State.owner - + + + +com.r3corda.contracts.asset / Cash / State / owner
+
+

owner

+ +val owner: PublicKey
+Overrides State.owner
+

There must be a MoveCommand signed by this key to claim the amount

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/participants.html b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/participants.html new file mode 100644 index 0000000000..89388968a0 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/participants.html @@ -0,0 +1,34 @@ + + +Cash.State.participants - + + + +com.r3corda.contracts.asset / Cash / State / participants
+
+

participants

+ +val participants: List<PublicKey>
+Overrides ContractState.participants
+

A participant is any party that is able to consume this state in a valid transaction.

+

The list of participants is required for certain types of transactions. For example, when changing the notary +for this state (TransactionType.NotaryChange), every participants has to be involved and approve the transaction +so that they receive the updated state, and dont end up in a situation where they can no longer use a state +they possess, since someone consumed that state during the notary change process.

+

The participants list should normally be derived from the contents of the state. E.g. for Cash the participants +list should just contain the owner.

+
+
+

Getter
+

A participant is any party that is able to consume this state in a valid transaction.

+

The list of participants is required for certain types of transactions. For example, when changing the notary +for this state (TransactionType.NotaryChange), every participants has to be involved and approve the transaction +so that they receive the updated state, and dont end up in a situation where they can no longer use a state +they possess, since someone consumed that state during the notary change process.

+

The participants list should normally be derived from the contents of the state. E.g. for Cash the participants +list should just contain the owner.

+

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/product-amount.html b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/product-amount.html new file mode 100644 index 0000000000..d8c5d61ac8 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/product-amount.html @@ -0,0 +1,16 @@ + + +Cash.State.productAmount - + + + +com.r3corda.contracts.asset / Cash / State / productAmount
+
+

productAmount

+ +val productAmount: Amount<Currency>
+Overrides FungibleAssetState.productAmount
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/to-string.html b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/to-string.html new file mode 100644 index 0000000000..94c2abeecd --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/to-string.html @@ -0,0 +1,15 @@ + + +Cash.State.toString - + + + +com.r3corda.contracts.asset / Cash / State / toString
+
+

toString

+ +fun toString(): String
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/with-new-owner.html b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/with-new-owner.html new file mode 100644 index 0000000000..d0fdf7138e --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-cash/-state/with-new-owner.html @@ -0,0 +1,17 @@ + + +Cash.State.withNewOwner - + + + +com.r3corda.contracts.asset / Cash / State / withNewOwner
+
+

withNewOwner

+ +fun withNewOwner(newOwner: PublicKey): <ERROR CLASS>
+Overrides OwnableState.withNewOwner
+

Copies the underlying data structure, replacing the owner field with this new value and leaving the rest alone

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-cash/generate-issue.html b/docs/build/html/api/com.r3corda.contracts.asset/-cash/generate-issue.html new file mode 100644 index 0000000000..bacf9b9dfb --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-cash/generate-issue.html @@ -0,0 +1,21 @@ + + +Cash.generateIssue - + + + +com.r3corda.contracts.asset / Cash / generateIssue
+
+

generateIssue

+ +fun generateIssue(tx: TransactionBuilder, tokenDef: Issued<Currency>, pennies: Long, owner: PublicKey, notary: Party): Unit
+

Puts together an issuance transaction from the given template, that starts out being owned by the given pubkey.

+
+
+ +fun generateIssue(tx: TransactionBuilder, amount: Amount<Issued<Currency>>, owner: PublicKey, notary: Party): Unit
+

Puts together an issuance transaction for the specified amount that starts out being owned by the given pubkey.

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-cash/generate-spend.html b/docs/build/html/api/com.r3corda.contracts.asset/-cash/generate-spend.html new file mode 100644 index 0000000000..08553e2510 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-cash/generate-spend.html @@ -0,0 +1,28 @@ + + +Cash.generateSpend - + + + +com.r3corda.contracts.asset / Cash / generateSpend
+
+

generateSpend

+ +fun generateSpend(tx: TransactionBuilder, amount: Amount<Issued<Currency>>, to: PublicKey, cashStates: List<StateAndRef<State>>): List<PublicKey>
+

Generate a transaction that consumes one or more of the given input states to move money to the given pubkey. +Note that the wallet list is not updated: its up to you to do that.

+
+
+ +fun generateSpend(tx: TransactionBuilder, amount: Amount<Currency>, to: PublicKey, cashStates: List<StateAndRef<State>>, onlyFromParties: Set<Party>? = null): List<PublicKey>
+

Generate a transaction that consumes one or more of the given input states to move money to the given pubkey. +Note that the wallet list is not updated: its up to you to do that.

+

Parameters

+ +onlyFromParties - if non-null, the wallet will be filtered to only include cash states issued by the set +of given parties. This can be useful if the party youre trying to pay has expectations +about which type of cash claims they are willing to accept.
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-cash/index.html b/docs/build/html/api/com.r3corda.contracts.asset/-cash/index.html new file mode 100644 index 0000000000..21856c02b0 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-cash/index.html @@ -0,0 +1,104 @@ + + +Cash - + + + +com.r3corda.contracts.asset / Cash
+
+

Cash

+class Cash : FungibleAsset<Currency>
+

A cash transaction may split and merge money represented by a set of (issuer, depositRef) pairs, across multiple +input and output states. Imagine a Bitcoin transaction but in which all UTXOs had a colour +(a blend of issuer+depositRef) and you couldnt merge outputs of two colours together, but you COULD put them in +the same transaction.

+

The goal of this design is to ensure that money can be withdrawn from the ledger easily: if you receive some money +via this contract, you always know where to go in order to extract it from the R3 ledger, no matter how many hands +it has passed through in the intervening time.

+

At the same time, other contracts that just want money and dont care much who is currently holding it in their +vaults can ignore the issuer/depositRefs and just examine the amount fields.

+
+
+
+
+

Types

+ + + + + + + + + + + +
+Commands +interface Commands : CommandData
+State +data class State : State<Currency>

A state representing a cash claim against some party

+
+

Constructors

+ + + + + + + +
+<init> +Cash()

A cash transaction may split and merge money represented by a set of (issuer, depositRef) pairs, across multiple +input and output states. Imagine a Bitcoin transaction but in which all UTXOs had a colour +(a blend of issuer+depositRef) and you couldnt merge outputs of two colours together, but you COULD put them in +the same transaction.

+
+

Properties

+ + + + + + + +
+legalContractReference +val legalContractReference: SecureHash

TODO:

+
+

Functions

+ + + + + + + + + + + +
+generateIssue +fun generateIssue(tx: TransactionBuilder, tokenDef: Issued<Currency>, pennies: Long, owner: PublicKey, notary: Party): Unit

Puts together an issuance transaction from the given template, that starts out being owned by the given pubkey.

+fun generateIssue(tx: TransactionBuilder, amount: Amount<Issued<Currency>>, owner: PublicKey, notary: Party): Unit

Puts together an issuance transaction for the specified amount that starts out being owned by the given pubkey.

+
+generateSpend +fun generateSpend(tx: TransactionBuilder, amount: Amount<Issued<Currency>>, to: PublicKey, cashStates: List<StateAndRef<State>>): List<PublicKey>
+fun generateSpend(tx: TransactionBuilder, amount: Amount<Currency>, to: PublicKey, cashStates: List<StateAndRef<State>>, onlyFromParties: Set<Party>? = null): List<PublicKey>

Generate a transaction that consumes one or more of the given input states to move money to the given pubkey. +Note that the wallet list is not updated: its up to you to do that.

+
+

Inherited Functions

+ + + + + + + +
+verify +open fun verify(tx: TransactionForContract): Unit

This is the function EVERYONE runs

+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-cash/legal-contract-reference.html b/docs/build/html/api/com.r3corda.contracts.asset/-cash/legal-contract-reference.html new file mode 100644 index 0000000000..5978af553b --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-cash/legal-contract-reference.html @@ -0,0 +1,25 @@ + + +Cash.legalContractReference - + + + +com.r3corda.contracts.asset / Cash / legalContractReference
+
+

legalContractReference

+ +val legalContractReference: SecureHash
+Overrides Contract.legalContractReference
+

TODO:

+
  1. hash should be of the contents, not the URI

    +
  2. allow the content to be specified at time of instance creation?

    +

Motivation: its the difference between a state object referencing a programRef, which references a +legalContractReference and a state object which directly references both. The latter allows the legal wording +to evolve without requiring code changes. But creates a risk that users create objects governed by a program +that is inconsistent with the legal contract

+
+
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset-state/index.html b/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset-state/index.html new file mode 100644 index 0000000000..ecd1941e58 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset-state/index.html @@ -0,0 +1,106 @@ + + +FungibleAssetState - + + + +com.r3corda.contracts.asset / FungibleAssetState
+
+

FungibleAssetState

+interface FungibleAssetState<T, I> : OwnableState
+

Common elements of cash contract states.

+
+
+

Properties

+ + + + + + + + + + + +
+issuanceDef +abstract val issuanceDef: I
+productAmount +abstract val productAmount: Amount<T>
+

Inherited Properties

+ + + + + + + +
+owner +abstract val owner: PublicKey

There must be a MoveCommand signed by this key to claim the amount

+
+

Functions

+ + + + + + + +
+move +abstract fun move(newAmount: Amount<T>, newOwner: PublicKey): FungibleAssetState<T, I>
+

Inherited Functions

+ + + + + + + +
+withNewOwner +abstract fun withNewOwner(newOwner: PublicKey): <ERROR CLASS><CommandData, OwnableState>

Copies the underlying data structure, replacing the owner field with this new value and leaving the rest alone

+
+

Extension Functions

+ + + + + + + + + + + +
+hash +fun ContractState.hash(): SecureHash

Returns the SHA-256 hash of the serialised contents of this state (not cached)

+
+with notary +infix fun ContractState.with notary(notary: Party): TransactionState<ContractState>
+

Inheritors

+ + + + + + + + + + + +
+State +interface State<T> : FungibleAssetState<T, Issued<T>>

A state representing a cash claim against some party

+
+State +data class State<P> : FungibleAssetState<P, IssuanceDefinition<P>>, BilateralNettableState<State<P>>

A state representing the obligation of one party (obligor) to deliver a specified number of +units of an underlying asset (described as issuanceDef.acceptableIssuedProducts) to the beneficiary +no later than the specified time.

+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset-state/issuance-def.html b/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset-state/issuance-def.html new file mode 100644 index 0000000000..40ec6c2a50 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset-state/issuance-def.html @@ -0,0 +1,15 @@ + + +FungibleAssetState.issuanceDef - + + + +com.r3corda.contracts.asset / FungibleAssetState / issuanceDef
+
+

issuanceDef

+ +abstract val issuanceDef: I
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset-state/move.html b/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset-state/move.html new file mode 100644 index 0000000000..bd9d2983b6 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset-state/move.html @@ -0,0 +1,15 @@ + + +FungibleAssetState.move - + + + +com.r3corda.contracts.asset / FungibleAssetState / move
+
+

move

+ +abstract fun move(newAmount: Amount<T>, newOwner: PublicKey): FungibleAssetState<T, I>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset-state/product-amount.html b/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset-state/product-amount.html new file mode 100644 index 0000000000..c0a2c8926e --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset-state/product-amount.html @@ -0,0 +1,15 @@ + + +FungibleAssetState.productAmount - + + + +com.r3corda.contracts.asset / FungibleAssetState / productAmount
+
+

productAmount

+ +abstract val productAmount: Amount<T>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-commands/-exit/amount.html b/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-commands/-exit/amount.html new file mode 100644 index 0000000000..26fe2ecacc --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-commands/-exit/amount.html @@ -0,0 +1,15 @@ + + +FungibleAsset.Commands.Exit.amount - + + + +com.r3corda.contracts.asset / FungibleAsset / Commands / Exit / amount
+
+

amount

+ +abstract val amount: Amount<Issued<T>>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-commands/-exit/index.html b/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-commands/-exit/index.html new file mode 100644 index 0000000000..3e7b437c8e --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-commands/-exit/index.html @@ -0,0 +1,40 @@ + + +FungibleAsset.Commands.Exit - + + + +com.r3corda.contracts.asset / FungibleAsset / Commands / Exit
+
+

Exit

+interface Exit<T> : Commands
+

A command stating that money has been withdrawn from the shared ledger and is now accounted for +in some other way.

+
+
+

Properties

+ + + + + + + +
+amount +abstract val amount: Amount<Issued<T>>
+

Inheritors

+ + + + + + + +
+Exit +data class Exit : Commands, Exit<Currency>

A command stating that money has been withdrawn from the shared ledger and is now accounted for +in some other way.

+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-commands/-issue.html b/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-commands/-issue.html new file mode 100644 index 0000000000..8d374c58e4 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-commands/-issue.html @@ -0,0 +1,40 @@ + + +FungibleAsset.Commands.Issue - + + + +com.r3corda.contracts.asset / FungibleAsset / Commands / Issue
+
+

Issue

+interface Issue : IssueCommand, Commands
+

Allows new asset states to be issued into existence: the nonce ("number used once") ensures the transaction +has a unique ID even when there are no inputs.

+
+
+

Inherited Properties

+ + + + + + + +
+nonce +abstract val nonce: Long
+

Inheritors

+ + + + + + + +
+Issue +data class Issue : Issue, Commands

Allows new cash states to be issued into existence: the nonce ("number used once") ensures the transaction +has a unique ID even when there are no inputs.

+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-commands/-move.html b/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-commands/-move.html new file mode 100644 index 0000000000..dad666b735 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-commands/-move.html @@ -0,0 +1,39 @@ + + +FungibleAsset.Commands.Move - + + + +com.r3corda.contracts.asset / FungibleAsset / Commands / Move
+
+

Move

+interface Move : MoveCommand, Commands
+
+
+

Inherited Properties

+ + + + + + + +
+contractHash +abstract val contractHash: SecureHash?

Contract code the moved state(s) are for the attention of, for example to indicate that the states are moved in +order to settle an obligation contracts state object(s).

+
+

Inheritors

+ + + + + + + +
+Move +data class Move : Move, Commands

A command stating that money has been moved, optionally to fulfil another contract.

+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-commands/index.html b/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-commands/index.html new file mode 100644 index 0000000000..bf2dcae3d5 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-commands/index.html @@ -0,0 +1,68 @@ + + +FungibleAsset.Commands - + + + +com.r3corda.contracts.asset / FungibleAsset / Commands
+
+

Commands

+interface Commands : CommandData
+
+
+

Types

+ + + + + + + + + + + + + + + +
+Exit +interface Exit<T> : Commands

A command stating that money has been withdrawn from the shared ledger and is now accounted for +in some other way.

+
+Issue +interface Issue : IssueCommand, Commands

Allows new asset states to be issued into existence: the nonce ("number used once") ensures the transaction +has a unique ID even when there are no inputs.

+
+Move +interface Move : MoveCommand, Commands
+

Inheritors

+ + + + + + + + + + + + + + + +
+Exit +interface Exit<T> : Commands

A command stating that money has been withdrawn from the shared ledger and is now accounted for +in some other way.

+
+Issue +interface Issue : IssueCommand, Commands

Allows new asset states to be issued into existence: the nonce ("number used once") ensures the transaction +has a unique ID even when there are no inputs.

+
+Move +interface Move : MoveCommand, Commands
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-init-.html b/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-init-.html new file mode 100644 index 0000000000..0058e07544 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-init-.html @@ -0,0 +1,27 @@ + + +FungibleAsset.<init> - + + + +com.r3corda.contracts.asset / FungibleAsset / <init>
+
+

<init>

+FungibleAsset()
+

Superclass for contracts 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.

+

See Cash for an example subclass that implements currency.

+
+
+

Parameters

+ +T - a type that represents the asset in question. This should describe the basic type of the asset +(GBP, USD, oil, shares in company , etc.) and any additional metadata (issuer, grade, class, etc.)
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-state/amount.html b/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-state/amount.html new file mode 100644 index 0000000000..dab9d811f9 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-state/amount.html @@ -0,0 +1,15 @@ + + +FungibleAsset.State.amount - + + + +com.r3corda.contracts.asset / FungibleAsset / State / amount
+
+

amount

+ +abstract val amount: Amount<Issued<T>>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-state/deposit.html b/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-state/deposit.html new file mode 100644 index 0000000000..edc5d0b5c7 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-state/deposit.html @@ -0,0 +1,16 @@ + + +FungibleAsset.State.deposit - + + + +com.r3corda.contracts.asset / FungibleAsset / State / deposit
+
+

deposit

+ +abstract val deposit: PartyAndReference
+

Where the underlying currency backing this ledger entry can be found (propagated)

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-state/index.html b/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-state/index.html new file mode 100644 index 0000000000..53a1c27a3a --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-state/index.html @@ -0,0 +1,69 @@ + + +FungibleAsset.State - + + + +com.r3corda.contracts.asset / FungibleAsset / State
+
+

State

+interface State<T> : FungibleAssetState<T, Issued<T>>
+

A state representing a cash claim against some party

+
+
+

Properties

+ + + + + + + + + + + + + + + +
+amount +abstract val amount: Amount<Issued<T>>
+deposit +abstract val deposit: PartyAndReference

Where the underlying currency backing this ledger entry can be found (propagated)

+
+owner +abstract val owner: PublicKey

There must be a MoveCommand signed by this key to claim the amount

+
+

Inherited Properties

+ + + + + + + + + + + +
+issuanceDef +abstract val issuanceDef: I
+productAmount +abstract val productAmount: Amount<T>
+

Inheritors

+ + + + + + + +
+State +data class State : State<Currency>

A state representing a cash claim against some party

+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-state/owner.html b/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-state/owner.html new file mode 100644 index 0000000000..65b4b0cd45 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/-state/owner.html @@ -0,0 +1,17 @@ + + +FungibleAsset.State.owner - + + + +com.r3corda.contracts.asset / FungibleAsset / State / owner
+
+

owner

+ +abstract val owner: PublicKey
+Overrides OwnableState.owner
+

There must be a MoveCommand signed by this key to claim the amount

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/index.html b/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/index.html new file mode 100644 index 0000000000..38bb29c219 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/index.html @@ -0,0 +1,102 @@ + + +FungibleAsset - + + + +com.r3corda.contracts.asset / FungibleAsset
+
+

FungibleAsset

+abstract class FungibleAsset<T> : Contract
+

Superclass for contracts 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.

+

See Cash for an example subclass that implements currency.

+
+
+

Parameters

+ +T - a type that represents the asset in question. This should describe the basic type of the asset +(GBP, USD, oil, shares in company , etc.) and any additional metadata (issuer, grade, class, etc.)
+
+
+

Types

+ + + + + + + + + + + +
+Commands +interface Commands : CommandData
+State +interface State<T> : FungibleAssetState<T, Issued<T>>

A state representing a cash claim against some party

+
+

Constructors

+ + + + + + + +
+<init> +FungibleAsset()

Superclass for contracts 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.

+
+

Inherited Properties

+ + + + + + + +
+legalContractReference +abstract val legalContractReference: SecureHash

Unparsed reference to the natural language contract that this code is supposed to express (usually a hash of +the contracts contents).

+
+

Functions

+ + + + + + + +
+verify +open fun verify(tx: TransactionForContract): Unit

This is the function EVERYONE runs

+
+

Inheritors

+ + + + + + + +
+Cash +class Cash : FungibleAsset<Currency>

A cash transaction may split and merge money represented by a set of (issuer, depositRef) pairs, across multiple +input and output states. Imagine a Bitcoin transaction but in which all UTXOs had a colour +(a blend of issuer+depositRef) and you couldnt merge outputs of two colours together, but you COULD put them in +the same transaction.

+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/verify.html b/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/verify.html new file mode 100644 index 0000000000..fff6e7005b --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-fungible-asset/verify.html @@ -0,0 +1,17 @@ + + +FungibleAsset.verify - + + + +com.r3corda.contracts.asset / FungibleAsset / verify
+
+

verify

+ +open fun verify(tx: TransactionForContract): Unit
+Overrides Contract.verify
+

This is the function EVERYONE runs

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-insufficient-balance-exception/-init-.html b/docs/build/html/api/com.r3corda.contracts.asset/-insufficient-balance-exception/-init-.html new file mode 100644 index 0000000000..38477e2855 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-insufficient-balance-exception/-init-.html @@ -0,0 +1,14 @@ + + +InsufficientBalanceException.<init> - + + + +com.r3corda.contracts.asset / InsufficientBalanceException / <init>
+
+

<init>

+InsufficientBalanceException(amountMissing: Amount<Currency>)
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-insufficient-balance-exception/amount-missing.html b/docs/build/html/api/com.r3corda.contracts.asset/-insufficient-balance-exception/amount-missing.html new file mode 100644 index 0000000000..749da1ee5d --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-insufficient-balance-exception/amount-missing.html @@ -0,0 +1,15 @@ + + +InsufficientBalanceException.amountMissing - + + + +com.r3corda.contracts.asset / InsufficientBalanceException / amountMissing
+
+

amountMissing

+ +val amountMissing: Amount<Currency>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-insufficient-balance-exception/index.html b/docs/build/html/api/com.r3corda.contracts.asset/-insufficient-balance-exception/index.html new file mode 100644 index 0000000000..8031d756a4 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-insufficient-balance-exception/index.html @@ -0,0 +1,36 @@ + + +InsufficientBalanceException - + + + +com.r3corda.contracts.asset / InsufficientBalanceException
+
+

InsufficientBalanceException

+class InsufficientBalanceException : Exception
+
+
+

Constructors

+ + + + + + + +
+<init> +InsufficientBalanceException(amountMissing: Amount<Currency>)
+

Properties

+ + + + + + + +
+amountMissing +val amountMissing: Amount<Currency>
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-o-b-l-i-g-a-t-i-o-n_-p-r-o-g-r-a-m_-i-d.html b/docs/build/html/api/com.r3corda.contracts.asset/-o-b-l-i-g-a-t-i-o-n_-p-r-o-g-r-a-m_-i-d.html new file mode 100644 index 0000000000..67a47ab10a --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-o-b-l-i-g-a-t-i-o-n_-p-r-o-g-r-a-m_-i-d.html @@ -0,0 +1,15 @@ + + +OBLIGATION_PROGRAM_ID - + + + +com.r3corda.contracts.asset / OBLIGATION_PROGRAM_ID
+
+

OBLIGATION_PROGRAM_ID

+ +val OBLIGATION_PROGRAM_ID: Obligation<Currency>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-bilateral-net-state/-init-.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-bilateral-net-state/-init-.html new file mode 100644 index 0000000000..af18f3f409 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-bilateral-net-state/-init-.html @@ -0,0 +1,17 @@ + + +Obligation.BilateralNetState.<init> - + + + +com.r3corda.contracts.asset / Obligation / BilateralNetState / <init>
+
+

<init>

+BilateralNetState(partyKeys: Set<PublicKey>, template: StateTemplate<P>)
+

Subset of state, containing the elements which must match for two obligation transactions to be nettable. +If two obligation state objects produce equal bilateral net states, they are considered safe to net directly. +Bilateral states are used in close-out netting.

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-bilateral-net-state/index.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-bilateral-net-state/index.html new file mode 100644 index 0000000000..5fa4936ec5 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-bilateral-net-state/index.html @@ -0,0 +1,48 @@ + + +Obligation.BilateralNetState - + + + +com.r3corda.contracts.asset / Obligation / BilateralNetState
+
+

BilateralNetState

+data class BilateralNetState<P> : NetState<P>
+

Subset of state, containing the elements which must match for two obligation transactions to be nettable. +If two obligation state objects produce equal bilateral net states, they are considered safe to net directly. +Bilateral states are used in close-out netting.

+
+
+

Constructors

+ + + + + + + +
+<init> +BilateralNetState(partyKeys: Set<PublicKey>, template: StateTemplate<P>)

Subset of state, containing the elements which must match for two obligation transactions to be nettable. +If two obligation state objects produce equal bilateral net states, they are considered safe to net directly. +Bilateral states are used in close-out netting.

+
+

Properties

+ + + + + + + + + + + +
+partyKeys +val partyKeys: Set<PublicKey>
+template +val template: StateTemplate<P>
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-bilateral-net-state/party-keys.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-bilateral-net-state/party-keys.html new file mode 100644 index 0000000000..2ddd5e694a --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-bilateral-net-state/party-keys.html @@ -0,0 +1,15 @@ + + +Obligation.BilateralNetState.partyKeys - + + + +com.r3corda.contracts.asset / Obligation / BilateralNetState / partyKeys
+
+

partyKeys

+ +val partyKeys: Set<PublicKey>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-bilateral-net-state/template.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-bilateral-net-state/template.html new file mode 100644 index 0000000000..de87ee09e9 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-bilateral-net-state/template.html @@ -0,0 +1,16 @@ + + +Obligation.BilateralNetState.template - + + + +com.r3corda.contracts.asset / Obligation / BilateralNetState / template
+
+

template

+ +val template: StateTemplate<P>
+Overrides NetState.template
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-exit/-init-.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-exit/-init-.html new file mode 100644 index 0000000000..3dbefa121d --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-exit/-init-.html @@ -0,0 +1,16 @@ + + +Obligation.Commands.Exit.<init> - + + + +com.r3corda.contracts.asset / Obligation / Commands / Exit / <init>
+
+

<init>

+Exit(aggregateState: IssuanceDefinition<P>, amount: Amount<P>)
+

A command stating that the debt is being released by the beneficiary. Normally would indicate +either settlement outside of the ledger, or that the obligor is unable to pay.

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-exit/aggregate-state.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-exit/aggregate-state.html new file mode 100644 index 0000000000..ed4ddfe019 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-exit/aggregate-state.html @@ -0,0 +1,16 @@ + + +Obligation.Commands.Exit.aggregateState - + + + +com.r3corda.contracts.asset / Obligation / Commands / Exit / aggregateState
+
+

aggregateState

+ +val aggregateState: IssuanceDefinition<P>
+Overrides IssuanceCommands.aggregateState
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-exit/amount.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-exit/amount.html new file mode 100644 index 0000000000..da43c51824 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-exit/amount.html @@ -0,0 +1,15 @@ + + +Obligation.Commands.Exit.amount - + + + +com.r3corda.contracts.asset / Obligation / Commands / Exit / amount
+
+

amount

+ +val amount: Amount<P>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-exit/index.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-exit/index.html new file mode 100644 index 0000000000..2f9da3e0a9 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-exit/index.html @@ -0,0 +1,46 @@ + + +Obligation.Commands.Exit - + + + +com.r3corda.contracts.asset / Obligation / Commands / Exit
+
+

Exit

+data class Exit<P> : Commands, IssuanceCommands<P>
+

A command stating that the debt is being released by the beneficiary. Normally would indicate +either settlement outside of the ledger, or that the obligor is unable to pay.

+
+
+

Constructors

+ + + + + + + +
+<init> +Exit(aggregateState: IssuanceDefinition<P>, amount: Amount<P>)

A command stating that the debt is being released by the beneficiary. Normally would indicate +either settlement outside of the ledger, or that the obligor is unable to pay.

+
+

Properties

+ + + + + + + + + + + +
+aggregateState +val aggregateState: IssuanceDefinition<P>
+amount +val amount: Amount<P>
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-issue/-init-.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-issue/-init-.html new file mode 100644 index 0000000000..38b84a837d --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-issue/-init-.html @@ -0,0 +1,16 @@ + + +Obligation.Commands.Issue.<init> - + + + +com.r3corda.contracts.asset / Obligation / Commands / Issue / <init>
+
+

<init>

+Issue(aggregateState: IssuanceDefinition<P>, nonce: Long = random63BitValue())
+

Allows new obligation states to be issued into existence: the nonce ("number used once") ensures the +transaction has a unique ID even when there are no inputs.

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-issue/aggregate-state.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-issue/aggregate-state.html new file mode 100644 index 0000000000..7897792325 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-issue/aggregate-state.html @@ -0,0 +1,16 @@ + + +Obligation.Commands.Issue.aggregateState - + + + +com.r3corda.contracts.asset / Obligation / Commands / Issue / aggregateState
+
+

aggregateState

+ +val aggregateState: IssuanceDefinition<P>
+Overrides IssuanceCommands.aggregateState
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-issue/index.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-issue/index.html new file mode 100644 index 0000000000..3fe4166ddd --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-issue/index.html @@ -0,0 +1,46 @@ + + +Obligation.Commands.Issue - + + + +com.r3corda.contracts.asset / Obligation / Commands / Issue
+
+

Issue

+data class Issue<P> : Commands, IssuanceCommands<P>
+

Allows new obligation states to be issued into existence: the nonce ("number used once") ensures the +transaction has a unique ID even when there are no inputs.

+
+
+

Constructors

+ + + + + + + +
+<init> +Issue(aggregateState: IssuanceDefinition<P>, nonce: Long = random63BitValue())

Allows new obligation states to be issued into existence: the nonce ("number used once") ensures the +transaction has a unique ID even when there are no inputs.

+
+

Properties

+ + + + + + + + + + + +
+aggregateState +val aggregateState: IssuanceDefinition<P>
+nonce +val nonce: Long
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-issue/nonce.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-issue/nonce.html new file mode 100644 index 0000000000..a25bbd3e38 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-issue/nonce.html @@ -0,0 +1,15 @@ + + +Obligation.Commands.Issue.nonce - + + + +com.r3corda.contracts.asset / Obligation / Commands / Issue / nonce
+
+

nonce

+ +val nonce: Long
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-move/-init-.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-move/-init-.html new file mode 100644 index 0000000000..afb8d0650c --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-move/-init-.html @@ -0,0 +1,20 @@ + + +Obligation.Commands.Move.<init> - + + + +com.r3corda.contracts.asset / Obligation / Commands / Move / <init>
+
+

<init>

+Move(aggregateState: IssuanceDefinition<P>, contractHash: SecureHash? = null)
+

A command stating that a debt has been moved, optionally to fulfil another contract.

+

Parameters

+ +contractHash - the contract this move is for the attention of. Only that contracts verify function +should take the moved states into account when considering whether it is valid. Typically this will be +null.
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-move/aggregate-state.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-move/aggregate-state.html new file mode 100644 index 0000000000..596ef6fcdb --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-move/aggregate-state.html @@ -0,0 +1,16 @@ + + +Obligation.Commands.Move.aggregateState - + + + +com.r3corda.contracts.asset / Obligation / Commands / Move / aggregateState
+
+

aggregateState

+ +val aggregateState: IssuanceDefinition<P>
+Overrides IssuanceCommands.aggregateState
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-move/contract-hash.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-move/contract-hash.html new file mode 100644 index 0000000000..2d780f98e1 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-move/contract-hash.html @@ -0,0 +1,18 @@ + + +Obligation.Commands.Move.contractHash - + + + +com.r3corda.contracts.asset / Obligation / Commands / Move / contractHash
+
+

contractHash

+ +val contractHash: SecureHash?
+Overrides MoveCommand.contractHash
+

Contract code the moved state(s) are for the attention of, for example to indicate that the states are moved in +order to settle an obligation contracts state object(s).

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-move/index.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-move/index.html new file mode 100644 index 0000000000..be51f4f8f3 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-move/index.html @@ -0,0 +1,51 @@ + + +Obligation.Commands.Move - + + + +com.r3corda.contracts.asset / Obligation / Commands / Move
+
+

Move

+data class Move<P> : Commands, IssuanceCommands<P>, MoveCommand
+

A command stating that a debt has been moved, optionally to fulfil another contract.

+

Parameters

+ +contractHash - the contract this move is for the attention of. Only that contracts verify function +should take the moved states into account when considering whether it is valid. Typically this will be +null.
+
+
+

Constructors

+ + + + + + + +
+<init> +Move(aggregateState: IssuanceDefinition<P>, contractHash: SecureHash? = null)

A command stating that a debt has been moved, optionally to fulfil another contract.

+
+

Properties

+ + + + + + + + + + + +
+aggregateState +val aggregateState: IssuanceDefinition<P>
+contractHash +val contractHash: SecureHash?

Contract code the moved state(s) are for the attention of, for example to indicate that the states are moved in +order to settle an obligation contracts state object(s).

+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-net/-init-.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-net/-init-.html new file mode 100644 index 0000000000..a5b6e45a4e --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-net/-init-.html @@ -0,0 +1,16 @@ + + +Obligation.Commands.Net.<init> - + + + +com.r3corda.contracts.asset / Obligation / Commands / Net / <init>
+
+

<init>

+Net(type: NetType)
+

Net two or more obligation states together in a close-out netting style. Limited to bilateral netting +as only the beneficiary (not the obligor) needs to sign.

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-net/index.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-net/index.html new file mode 100644 index 0000000000..83b2cd921b --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-net/index.html @@ -0,0 +1,40 @@ + + +Obligation.Commands.Net - + + + +com.r3corda.contracts.asset / Obligation / Commands / Net
+
+

Net

+data class Net : Commands
+

Net two or more obligation states together in a close-out netting style. Limited to bilateral netting +as only the beneficiary (not the obligor) needs to sign.

+
+
+

Constructors

+ + + + + + + +
+<init> +Net(type: NetType)

Net two or more obligation states together in a close-out netting style. Limited to bilateral netting +as only the beneficiary (not the obligor) needs to sign.

+
+

Properties

+ + + + + + + +
+type +val type: NetType
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-net/type.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-net/type.html new file mode 100644 index 0000000000..3af08472bc --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-net/type.html @@ -0,0 +1,15 @@ + + +Obligation.Commands.Net.type - + + + +com.r3corda.contracts.asset / Obligation / Commands / Net / type
+
+

type

+ +val type: NetType
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-set-lifecycle/-init-.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-set-lifecycle/-init-.html new file mode 100644 index 0000000000..c64b831c47 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-set-lifecycle/-init-.html @@ -0,0 +1,16 @@ + + +Obligation.Commands.SetLifecycle.<init> - + + + +com.r3corda.contracts.asset / Obligation / Commands / SetLifecycle / <init>
+
+

<init>

+SetLifecycle(aggregateState: IssuanceDefinition<P>, lifecycle: Lifecycle)
+

A command stating that the beneficiary is moving the contract into the defaulted state as it has not been settled +by the due date, or resetting a defaulted contract back to the issued state.

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-set-lifecycle/aggregate-state.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-set-lifecycle/aggregate-state.html new file mode 100644 index 0000000000..bff8bd5430 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-set-lifecycle/aggregate-state.html @@ -0,0 +1,16 @@ + + +Obligation.Commands.SetLifecycle.aggregateState - + + + +com.r3corda.contracts.asset / Obligation / Commands / SetLifecycle / aggregateState
+
+

aggregateState

+ +val aggregateState: IssuanceDefinition<P>
+Overrides IssuanceCommands.aggregateState
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-set-lifecycle/index.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-set-lifecycle/index.html new file mode 100644 index 0000000000..606e87ee52 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-set-lifecycle/index.html @@ -0,0 +1,52 @@ + + +Obligation.Commands.SetLifecycle - + + + +com.r3corda.contracts.asset / Obligation / Commands / SetLifecycle
+
+

SetLifecycle

+data class SetLifecycle<P> : Commands, IssuanceCommands<P>
+

A command stating that the beneficiary is moving the contract into the defaulted state as it has not been settled +by the due date, or resetting a defaulted contract back to the issued state.

+
+
+

Constructors

+ + + + + + + +
+<init> +SetLifecycle(aggregateState: IssuanceDefinition<P>, lifecycle: Lifecycle)

A command stating that the beneficiary is moving the contract into the defaulted state as it has not been settled +by the due date, or resetting a defaulted contract back to the issued state.

+
+

Properties

+ + + + + + + + + + + + + + + +
+aggregateState +val aggregateState: IssuanceDefinition<P>
+inverse +val inverse: Lifecycle
+lifecycle +val lifecycle: Lifecycle
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-set-lifecycle/inverse.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-set-lifecycle/inverse.html new file mode 100644 index 0000000000..a80362154a --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-set-lifecycle/inverse.html @@ -0,0 +1,15 @@ + + +Obligation.Commands.SetLifecycle.inverse - + + + +com.r3corda.contracts.asset / Obligation / Commands / SetLifecycle / inverse
+
+

inverse

+ +val inverse: Lifecycle
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-set-lifecycle/lifecycle.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-set-lifecycle/lifecycle.html new file mode 100644 index 0000000000..15a756de27 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-set-lifecycle/lifecycle.html @@ -0,0 +1,15 @@ + + +Obligation.Commands.SetLifecycle.lifecycle - + + + +com.r3corda.contracts.asset / Obligation / Commands / SetLifecycle / lifecycle
+
+

lifecycle

+ +val lifecycle: Lifecycle
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-settle/-init-.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-settle/-init-.html new file mode 100644 index 0000000000..05c39517e7 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-settle/-init-.html @@ -0,0 +1,19 @@ + + +Obligation.Commands.Settle.<init> - + + + +com.r3corda.contracts.asset / Obligation / Commands / Settle / <init>
+
+

<init>

+Settle(aggregateState: IssuanceDefinition<P>, amount: Amount<P>)
+

A command stating that the obligor is settling some or all of the amount owed by transferring a suitable +state object to the beneficiary. If this reduces the balance to zero, the state object is destroyed.

+

See Also
+

MoveCommand

+

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-settle/aggregate-state.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-settle/aggregate-state.html new file mode 100644 index 0000000000..edf1a102af --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-settle/aggregate-state.html @@ -0,0 +1,16 @@ + + +Obligation.Commands.Settle.aggregateState - + + + +com.r3corda.contracts.asset / Obligation / Commands / Settle / aggregateState
+
+

aggregateState

+ +val aggregateState: IssuanceDefinition<P>
+Overrides IssuanceCommands.aggregateState
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-settle/amount.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-settle/amount.html new file mode 100644 index 0000000000..95c0870d69 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-settle/amount.html @@ -0,0 +1,15 @@ + + +Obligation.Commands.Settle.amount - + + + +com.r3corda.contracts.asset / Obligation / Commands / Settle / amount
+
+

amount

+ +val amount: Amount<P>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-settle/index.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-settle/index.html new file mode 100644 index 0000000000..b71abacd79 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/-settle/index.html @@ -0,0 +1,49 @@ + + +Obligation.Commands.Settle - + + + +com.r3corda.contracts.asset / Obligation / Commands / Settle
+
+

Settle

+data class Settle<P> : Commands, IssuanceCommands<P>
+

A command stating that the obligor is settling some or all of the amount owed by transferring a suitable +state object to the beneficiary. If this reduces the balance to zero, the state object is destroyed.

+

See Also
+

MoveCommand

+

+
+
+

Constructors

+ + + + + + + +
+<init> +Settle(aggregateState: IssuanceDefinition<P>, amount: Amount<P>)

A command stating that the obligor is settling some or all of the amount owed by transferring a suitable +state object to the beneficiary. If this reduces the balance to zero, the state object is destroyed.

+
+

Properties

+ + + + + + + + + + + +
+aggregateState +val aggregateState: IssuanceDefinition<P>
+amount +val amount: Amount<P>
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/index.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/index.html new file mode 100644 index 0000000000..84f7523b8d --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-commands/index.html @@ -0,0 +1,118 @@ + + +Obligation.Commands - + + + +com.r3corda.contracts.asset / Obligation / Commands
+
+

Commands

+interface Commands : CommandData
+
+
+

Types

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Exit +data class Exit<P> : Commands, IssuanceCommands<P>

A command stating that the debt is being released by the beneficiary. Normally would indicate +either settlement outside of the ledger, or that the obligor is unable to pay.

+
+Issue +data class Issue<P> : Commands, IssuanceCommands<P>

Allows new obligation states to be issued into existence: the nonce ("number used once") ensures the +transaction has a unique ID even when there are no inputs.

+
+Move +data class Move<P> : Commands, IssuanceCommands<P>, MoveCommand

A command stating that a debt has been moved, optionally to fulfil another contract.

+
+Net +data class Net : Commands

Net two or more obligation states together in a close-out netting style. Limited to bilateral netting +as only the beneficiary (not the obligor) needs to sign.

+
+SetLifecycle +data class SetLifecycle<P> : Commands, IssuanceCommands<P>

A command stating that the beneficiary is moving the contract into the defaulted state as it has not been settled +by the due date, or resetting a defaulted contract back to the issued state.

+
+Settle +data class Settle<P> : Commands, IssuanceCommands<P>

A command stating that the obligor is settling some or all of the amount owed by transferring a suitable +state object to the beneficiary. If this reduces the balance to zero, the state object is destroyed.

+
+

Inheritors

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Exit +data class Exit<P> : Commands, IssuanceCommands<P>

A command stating that the debt is being released by the beneficiary. Normally would indicate +either settlement outside of the ledger, or that the obligor is unable to pay.

+
+Issue +data class Issue<P> : Commands, IssuanceCommands<P>

Allows new obligation states to be issued into existence: the nonce ("number used once") ensures the +transaction has a unique ID even when there are no inputs.

+
+Move +data class Move<P> : Commands, IssuanceCommands<P>, MoveCommand

A command stating that a debt has been moved, optionally to fulfil another contract.

+
+Net +data class Net : Commands

Net two or more obligation states together in a close-out netting style. Limited to bilateral netting +as only the beneficiary (not the obligor) needs to sign.

+
+SetLifecycle +data class SetLifecycle<P> : Commands, IssuanceCommands<P>

A command stating that the beneficiary is moving the contract into the defaulted state as it has not been settled +by the due date, or resetting a defaulted contract back to the issued state.

+
+Settle +data class Settle<P> : Commands, IssuanceCommands<P>

A command stating that the obligor is settling some or all of the amount owed by transferring a suitable +state object to the beneficiary. If this reduces the balance to zero, the state object is destroyed.

+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-init-.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-init-.html new file mode 100644 index 0000000000..aa410b900f --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-init-.html @@ -0,0 +1,21 @@ + + +Obligation.<init> - + + + +com.r3corda.contracts.asset / Obligation / <init>
+
+

<init>

+Obligation()
+

An obligation contract commits the obligor to delivering a specified amount of a fungible asset (for example the +Cash contract) at a specified future point in time. Settlement transactions may split and merge contracts across +multiple input and output states. The goal of this design is to handle amounts owed, and these contracts are expected +to be netted/merged, with settlement only for any remainder amount.

+

Parameters

+ +P - the product the obligation is for payment of.
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-issuance-commands/aggregate-state.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-issuance-commands/aggregate-state.html new file mode 100644 index 0000000000..9958e98a9c --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-issuance-commands/aggregate-state.html @@ -0,0 +1,15 @@ + + +Obligation.IssuanceCommands.aggregateState - + + + +com.r3corda.contracts.asset / Obligation / IssuanceCommands / aggregateState
+
+

aggregateState

+ +abstract val aggregateState: IssuanceDefinition<P>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-issuance-commands/index.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-issuance-commands/index.html new file mode 100644 index 0000000000..150871e311 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-issuance-commands/index.html @@ -0,0 +1,70 @@ + + +Obligation.IssuanceCommands - + + + +com.r3corda.contracts.asset / Obligation / IssuanceCommands
+
+

IssuanceCommands

+interface IssuanceCommands<P> : CommandData
+

Interface for commands that apply to states grouped by issuance definition

+
+
+

Properties

+ + + + + + + +
+aggregateState +abstract val aggregateState: IssuanceDefinition<P>
+

Inheritors

+ + + + + + + + + + + + + + + + + + + + + + + +
+Exit +data class Exit<P> : Commands, IssuanceCommands<P>

A command stating that the debt is being released by the beneficiary. Normally would indicate +either settlement outside of the ledger, or that the obligor is unable to pay.

+
+Issue +data class Issue<P> : Commands, IssuanceCommands<P>

Allows new obligation states to be issued into existence: the nonce ("number used once") ensures the +transaction has a unique ID even when there are no inputs.

+
+Move +data class Move<P> : Commands, IssuanceCommands<P>, MoveCommand

A command stating that a debt has been moved, optionally to fulfil another contract.

+
+SetLifecycle +data class SetLifecycle<P> : Commands, IssuanceCommands<P>

A command stating that the beneficiary is moving the contract into the defaulted state as it has not been settled +by the due date, or resetting a defaulted contract back to the issued state.

+
+Settle +data class Settle<P> : Commands, IssuanceCommands<P>

A command stating that the obligor is settling some or all of the amount owed by transferring a suitable +state object to the beneficiary. If this reduces the balance to zero, the state object is destroyed.

+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-issuance-definition/-init-.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-issuance-definition/-init-.html new file mode 100644 index 0000000000..9889000d66 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-issuance-definition/-init-.html @@ -0,0 +1,20 @@ + + +Obligation.IssuanceDefinition.<init> - + + + +com.r3corda.contracts.asset / Obligation / IssuanceDefinition / <init>
+
+

<init>

+IssuanceDefinition(obligor: Party, template: StateTemplate<P>)
+

Subset of state, containing the elements specified when issuing a new settlement contract. +TODO: This needs to be something common to contracts that we can be obliged to pay, and moved +out into core accordingly.

+

Parameters

+ +P - the product the obligation is for payment of.
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-issuance-definition/index.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-issuance-definition/index.html new file mode 100644 index 0000000000..682ee1a59a --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-issuance-definition/index.html @@ -0,0 +1,62 @@ + + +Obligation.IssuanceDefinition - + + + +com.r3corda.contracts.asset / Obligation / IssuanceDefinition
+
+

IssuanceDefinition

+data class IssuanceDefinition<P>
+

Subset of state, containing the elements specified when issuing a new settlement contract. +TODO: This needs to be something common to contracts that we can be obliged to pay, and moved +out into core accordingly.

+

Parameters

+ +P - the product the obligation is for payment of.
+
+
+

Constructors

+ + + + + + + +
+<init> +IssuanceDefinition(obligor: Party, template: StateTemplate<P>)

Subset of state, containing the elements specified when issuing a new settlement contract. +TODO: This needs to be something common to contracts that we can be obliged to pay, and moved +out into core accordingly.

+
+

Properties

+ + + + + + + + + + + +
+obligor +val obligor: Party
+template +val template: StateTemplate<P>
+

Extension Functions

+ + + + + + + +
+at +infix fun <T> IssuanceDefinition<T>.at(dueBefore: Instant): IssuanceDefinition<T>
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-issuance-definition/obligor.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-issuance-definition/obligor.html new file mode 100644 index 0000000000..74c795c24d --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-issuance-definition/obligor.html @@ -0,0 +1,15 @@ + + +Obligation.IssuanceDefinition.obligor - + + + +com.r3corda.contracts.asset / Obligation / IssuanceDefinition / obligor
+
+

obligor

+ +val obligor: Party
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-issuance-definition/template.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-issuance-definition/template.html new file mode 100644 index 0000000000..57d9a58a4e --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-issuance-definition/template.html @@ -0,0 +1,15 @@ + + +Obligation.IssuanceDefinition.template - + + + +com.r3corda.contracts.asset / Obligation / IssuanceDefinition / template
+
+

template

+ +val template: StateTemplate<P>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-lifecycle/-d-e-f-a-u-l-t-e-d.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-lifecycle/-d-e-f-a-u-l-t-e-d.html new file mode 100644 index 0000000000..7642b4c541 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-lifecycle/-d-e-f-a-u-l-t-e-d.html @@ -0,0 +1,16 @@ + + +Obligation.Lifecycle.DEFAULTED - + + + +com.r3corda.contracts.asset / Obligation / Lifecycle / DEFAULTED
+
+

DEFAULTED

+DEFAULTED
+

Indicates the contract has not been settled by its due date. Once in the defaulted state, +it can only be reverted to NORMAL state by the beneficiary.

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-lifecycle/-n-o-r-m-a-l.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-lifecycle/-n-o-r-m-a-l.html new file mode 100644 index 0000000000..37524a64f7 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-lifecycle/-n-o-r-m-a-l.html @@ -0,0 +1,15 @@ + + +Obligation.Lifecycle.NORMAL - + + + +com.r3corda.contracts.asset / Obligation / Lifecycle / NORMAL
+
+

NORMAL

+NORMAL
+

Default lifecycle state for a contract, in which it can be settled normally

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-lifecycle/index.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-lifecycle/index.html new file mode 100644 index 0000000000..842c4d81c5 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-lifecycle/index.html @@ -0,0 +1,37 @@ + + +Obligation.Lifecycle - + + + +com.r3corda.contracts.asset / Obligation / Lifecycle
+
+

Lifecycle

+enum class Lifecycle
+

Represents where in its lifecycle a contract state is, which in turn controls the commands that can be applied +to the state. Most states will not leave the NORMAL lifecycle. Note that settled (as an end lifecycle) is +represented by absence of the state on transaction output.

+
+
+

Enum Values

+ + + + + + + + + + + +
+NORMAL +

Default lifecycle state for a contract, in which it can be settled normally

+
+DEFAULTED +

Indicates the contract has not been settled by its due date. Once in the defaulted state, +it can only be reverted to NORMAL state by the beneficiary.

+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-multilateral-net-state/-init-.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-multilateral-net-state/-init-.html new file mode 100644 index 0000000000..76c45cb32d --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-multilateral-net-state/-init-.html @@ -0,0 +1,20 @@ + + +Obligation.MultilateralNetState.<init> - + + + +com.r3corda.contracts.asset / Obligation / MultilateralNetState / <init>
+
+

<init>

+MultilateralNetState(template: StateTemplate<P>)
+

Subset of state, containing the elements which must match for two or more obligation transactions to be candidates +for netting (this does not include the checks to enforce that everyones amounts received are the same at the end, +which is handled under the verify() function). +In comparison to BilateralNetState, this doesnt include the parties keys, as ensuring balances match on +input and output is handled elsewhere. +Used in cases where all parties (or their proxies) are signing, such as central clearing.

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-multilateral-net-state/index.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-multilateral-net-state/index.html new file mode 100644 index 0000000000..1811d4ecaf --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-multilateral-net-state/index.html @@ -0,0 +1,48 @@ + + +Obligation.MultilateralNetState - + + + +com.r3corda.contracts.asset / Obligation / MultilateralNetState
+
+

MultilateralNetState

+data class MultilateralNetState<P> : NetState<P>
+

Subset of state, containing the elements which must match for two or more obligation transactions to be candidates +for netting (this does not include the checks to enforce that everyones amounts received are the same at the end, +which is handled under the verify() function). +In comparison to BilateralNetState, this doesnt include the parties keys, as ensuring balances match on +input and output is handled elsewhere. +Used in cases where all parties (or their proxies) are signing, such as central clearing.

+
+
+

Constructors

+ + + + + + + +
+<init> +MultilateralNetState(template: StateTemplate<P>)

Subset of state, containing the elements which must match for two or more obligation transactions to be candidates +for netting (this does not include the checks to enforce that everyones amounts received are the same at the end, +which is handled under the verify() function). +In comparison to BilateralNetState, this doesnt include the parties keys, as ensuring balances match on +input and output is handled elsewhere. +Used in cases where all parties (or their proxies) are signing, such as central clearing.

+
+

Properties

+ + + + + + + +
+template +val template: StateTemplate<P>
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-multilateral-net-state/template.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-multilateral-net-state/template.html new file mode 100644 index 0000000000..79d0eb9272 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-multilateral-net-state/template.html @@ -0,0 +1,16 @@ + + +Obligation.MultilateralNetState.template - + + + +com.r3corda.contracts.asset / Obligation / MultilateralNetState / template
+
+

template

+ +val template: StateTemplate<P>
+Overrides NetState.template
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-net-state/index.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-net-state/index.html new file mode 100644 index 0000000000..d182442adb --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-net-state/index.html @@ -0,0 +1,53 @@ + + +Obligation.NetState - + + + +com.r3corda.contracts.asset / Obligation / NetState
+
+

NetState

+interface NetState<P>
+

Common interface for the state subsets used when determining nettability of two or more states. Exposes the +underlying issued thing.

+
+
+

Properties

+ + + + + + + +
+template +abstract val template: StateTemplate<P>
+

Inheritors

+ + + + + + + + + + + +
+BilateralNetState +data class BilateralNetState<P> : NetState<P>

Subset of state, containing the elements which must match for two obligation transactions to be nettable. +If two obligation state objects produce equal bilateral net states, they are considered safe to net directly. +Bilateral states are used in close-out netting.

+
+MultilateralNetState +data class MultilateralNetState<P> : NetState<P>

Subset of state, containing the elements which must match for two or more obligation transactions to be candidates +for netting (this does not include the checks to enforce that everyones amounts received are the same at the end, +which is handled under the verify() function). +In comparison to BilateralNetState, this doesnt include the parties keys, as ensuring balances match on +input and output is handled elsewhere. +Used in cases where all parties (or their proxies) are signing, such as central clearing.

+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-net-state/template.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-net-state/template.html new file mode 100644 index 0000000000..fac3c14750 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-net-state/template.html @@ -0,0 +1,15 @@ + + +Obligation.NetState.template - + + + +com.r3corda.contracts.asset / Obligation / NetState / template
+
+

template

+ +abstract val template: StateTemplate<P>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state-template/-init-.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state-template/-init-.html new file mode 100644 index 0000000000..2e798540c3 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state-template/-init-.html @@ -0,0 +1,18 @@ + + +Obligation.StateTemplate.<init> - + + + +com.r3corda.contracts.asset / Obligation / StateTemplate / <init>
+
+

<init>

+StateTemplate(acceptableContracts: NonEmptySet<SecureHash>, acceptableIssuedProducts: NonEmptySet<Issued<P>>, dueBefore: Instant, timeTolerance: Duration = Duration.ofSeconds(30))
+

Subset of state, containing the elements specified when issuing a new settlement contract.

+

Parameters

+ +P - the product the obligation is for payment of.
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state-template/acceptable-contracts.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state-template/acceptable-contracts.html new file mode 100644 index 0000000000..3a668ea9cc --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state-template/acceptable-contracts.html @@ -0,0 +1,16 @@ + + +Obligation.StateTemplate.acceptableContracts - + + + +com.r3corda.contracts.asset / Obligation / StateTemplate / acceptableContracts
+
+

acceptableContracts

+ +val acceptableContracts: NonEmptySet<SecureHash>
+

The hash of the asset contract were willing to accept in payment for this debt.

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state-template/acceptable-issued-products.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state-template/acceptable-issued-products.html new file mode 100644 index 0000000000..473b35da6d --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state-template/acceptable-issued-products.html @@ -0,0 +1,16 @@ + + +Obligation.StateTemplate.acceptableIssuedProducts - + + + +com.r3corda.contracts.asset / Obligation / StateTemplate / acceptableIssuedProducts
+
+

acceptableIssuedProducts

+ +val acceptableIssuedProducts: NonEmptySet<Issued<P>>
+

The parties whose assets we are willing to accept in payment for this debt.

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state-template/due-before.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state-template/due-before.html new file mode 100644 index 0000000000..5da6aaab3e --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state-template/due-before.html @@ -0,0 +1,16 @@ + + +Obligation.StateTemplate.dueBefore - + + + +com.r3corda.contracts.asset / Obligation / StateTemplate / dueBefore
+
+

dueBefore

+ +val dueBefore: Instant
+

When the contract must be settled by.

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state-template/index.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state-template/index.html new file mode 100644 index 0000000000..8e22c54fe9 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state-template/index.html @@ -0,0 +1,68 @@ + + +Obligation.StateTemplate - + + + +com.r3corda.contracts.asset / Obligation / StateTemplate
+
+

StateTemplate

+data class StateTemplate<P>
+

Subset of state, containing the elements specified when issuing a new settlement contract.

+

Parameters

+ +P - the product the obligation is for payment of.
+
+
+

Constructors

+ + + + + + + +
+<init> +StateTemplate(acceptableContracts: NonEmptySet<SecureHash>, acceptableIssuedProducts: NonEmptySet<Issued<P>>, dueBefore: Instant, timeTolerance: Duration = Duration.ofSeconds(30))

Subset of state, containing the elements specified when issuing a new settlement contract.

+
+

Properties

+ + + + + + + + + + + + + + + + + + + + + + + +
+acceptableContracts +val acceptableContracts: NonEmptySet<SecureHash>

The hash of the asset contract were willing to accept in payment for this debt.

+
+acceptableIssuedProducts +val acceptableIssuedProducts: NonEmptySet<Issued<P>>

The parties whose assets we are willing to accept in payment for this debt.

+
+dueBefore +val dueBefore: Instant

When the contract must be settled by.

+
+product +val product: P
+timeTolerance +val timeTolerance: Duration
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state-template/product.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state-template/product.html new file mode 100644 index 0000000000..7681b329e0 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state-template/product.html @@ -0,0 +1,15 @@ + + +Obligation.StateTemplate.product - + + + +com.r3corda.contracts.asset / Obligation / StateTemplate / product
+
+

product

+ +val product: P
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state-template/time-tolerance.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state-template/time-tolerance.html new file mode 100644 index 0000000000..e2c5837d99 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state-template/time-tolerance.html @@ -0,0 +1,15 @@ + + +Obligation.StateTemplate.timeTolerance - + + + +com.r3corda.contracts.asset / Obligation / StateTemplate / timeTolerance
+
+

timeTolerance

+ +val timeTolerance: Duration
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/-init-.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/-init-.html new file mode 100644 index 0000000000..4e73b2558e --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/-init-.html @@ -0,0 +1,20 @@ + + +Obligation.State.<init> - + + + +com.r3corda.contracts.asset / Obligation / State / <init>
+
+

<init>

+State(lifecycle: Lifecycle = Lifecycle.NORMAL, obligor: Party, template: StateTemplate<P>, quantity: Long, beneficiary: PublicKey)
+

A state representing the obligation of one party (obligor) to deliver a specified number of +units of an underlying asset (described as issuanceDef.acceptableIssuedProducts) to the beneficiary +no later than the specified time.

+

Parameters

+ +P - the product the obligation is for payment of.
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/acceptable-contracts.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/acceptable-contracts.html new file mode 100644 index 0000000000..d1d9b7fbb4 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/acceptable-contracts.html @@ -0,0 +1,15 @@ + + +Obligation.State.acceptableContracts - + + + +com.r3corda.contracts.asset / Obligation / State / acceptableContracts
+
+

acceptableContracts

+ +val acceptableContracts: NonEmptySet<SecureHash>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/acceptable-issuance-definitions.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/acceptable-issuance-definitions.html new file mode 100644 index 0000000000..356bf3a180 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/acceptable-issuance-definitions.html @@ -0,0 +1,15 @@ + + +Obligation.State.acceptableIssuanceDefinitions - + + + +com.r3corda.contracts.asset / Obligation / State / acceptableIssuanceDefinitions
+
+

acceptableIssuanceDefinitions

+ +val acceptableIssuanceDefinitions: NonEmptySet<*>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/aggregate-state.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/aggregate-state.html new file mode 100644 index 0000000000..42b3213ed7 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/aggregate-state.html @@ -0,0 +1,15 @@ + + +Obligation.State.aggregateState - + + + +com.r3corda.contracts.asset / Obligation / State / aggregateState
+
+

aggregateState

+ +val aggregateState: IssuanceDefinition<P>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/amount.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/amount.html new file mode 100644 index 0000000000..8d771e00c5 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/amount.html @@ -0,0 +1,15 @@ + + +Obligation.State.amount - + + + +com.r3corda.contracts.asset / Obligation / State / amount
+
+

amount

+ +val amount: Amount<P>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/beneficiary.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/beneficiary.html new file mode 100644 index 0000000000..50a5913f2d --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/beneficiary.html @@ -0,0 +1,16 @@ + + +Obligation.State.beneficiary - + + + +com.r3corda.contracts.asset / Obligation / State / beneficiary
+
+

beneficiary

+ +val beneficiary: PublicKey
+

The public key of the entity the contract pays to

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/bilateral-net-state.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/bilateral-net-state.html new file mode 100644 index 0000000000..8534329c23 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/bilateral-net-state.html @@ -0,0 +1,22 @@ + + +Obligation.State.bilateralNetState - + + + +com.r3corda.contracts.asset / Obligation / State / bilateralNetState
+
+

bilateralNetState

+ +val bilateralNetState: BilateralNetState<P>
+Overrides BilateralNettableState.bilateralNetState
+

Returns an object used to determine if two states can be subject to close-out netting. If two states return +equal objects, they can be close out netted together.

+

Getter
+

Returns an object used to determine if two states can be subject to close-out netting. If two states return +equal objects, they can be close out netted together.

+

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/contract.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/contract.html new file mode 100644 index 0000000000..b52d711d52 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/contract.html @@ -0,0 +1,43 @@ + + +Obligation.State.contract - + + + +com.r3corda.contracts.asset / Obligation / State / contract
+
+

contract

+ +val contract: Obligation<Currency>
+Overrides ContractState.contract
+

An instance of the contract class that will verify this state.

+

Discussion

+

This field is not the final design, its just a piece of temporary scaffolding. Once the contract sandbox is +further along, this field will become a description of which attachments are acceptable for defining the +contract.

+

Recall that an attachment is a zip file that can be referenced from any transaction. The contents of the +attachments are merged together and cannot define any overlapping files, thus for any given transaction there +is a miniature file system in which each file can be precisely mapped to the defining attachment.

+

Attachments may contain many things (data files, legal documents, etc) but mostly they contain JVM bytecode. +The class files inside define not only Contract implementations but also the classes that define the states. +Within the rest of a transaction, user-providable components are referenced by name only.

+

This means that a smart contract in Corda does two things:

+
  1. Define the data structures that compose the ledger (the states)

    +
  2. Define the rules for updating those structures

    +

The first is merely a utility role ... in theory contract code could manually parse byte streams by hand. +The second is vital to the integrity of the ledger. So this field needs to be able to express constraints like:

+
  • Only attachment 733c350f396a727655be1363c06635ba355036bd54a5ed6e594fd0b5d05f42f6 may be used with this state.

    +
  • Any attachment signed by public key 2d1ce0e330c52b8055258d776c40 may be used with this state.

    +
  • Attachments (1, 2, 3) may all be used with this state.

    +

and so on. In this way it becomes possible for the business logic governing a state to be evolved, if the +constraints are flexible enough.

+

Because contract classes often also define utilities that generate relevant transactions, and because attachments +cannot know their own hashes, we will have to provide various utilities to assist with obtaining the right +code constraints from within the contract code itself.

+

TODO: Implement the above description. See COR-226

+
+
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/due-before.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/due-before.html new file mode 100644 index 0000000000..7cb421c771 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/due-before.html @@ -0,0 +1,15 @@ + + +Obligation.State.dueBefore - + + + +com.r3corda.contracts.asset / Obligation / State / dueBefore
+
+

dueBefore

+ +val dueBefore: Instant
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/index.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/index.html new file mode 100644 index 0000000000..d35f1d12eb --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/index.html @@ -0,0 +1,209 @@ + + +Obligation.State - + + + +com.r3corda.contracts.asset / Obligation / State
+
+

State

+data class State<P> : FungibleAssetState<P, IssuanceDefinition<P>>, BilateralNettableState<State<P>>
+

A state representing the obligation of one party (obligor) to deliver a specified number of +units of an underlying asset (described as issuanceDef.acceptableIssuedProducts) to the beneficiary +no later than the specified time.

+

Parameters

+ +P - the product the obligation is for payment of.
+
+
+

Constructors

+ + + + + + + +
+<init> +State(lifecycle: Lifecycle = Lifecycle.NORMAL, obligor: Party, template: StateTemplate<P>, quantity: Long, beneficiary: PublicKey)

A state representing the obligation of one party (obligor) to deliver a specified number of +units of an underlying asset (described as issuanceDef.acceptableIssuedProducts) to the beneficiary +no later than the specified time.

+
+

Properties

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+acceptableContracts +val acceptableContracts: NonEmptySet<SecureHash>
+acceptableIssuanceDefinitions +val acceptableIssuanceDefinitions: NonEmptySet<*>
+aggregateState +val aggregateState: IssuanceDefinition<P>
+amount +val amount: Amount<P>
+beneficiary +val beneficiary: PublicKey

The public key of the entity the contract pays to

+
+bilateralNetState +val bilateralNetState: BilateralNetState<P>

Returns an object used to determine if two states can be subject to close-out netting. If two states return +equal objects, they can be close out netted together.

+
+contract +val contract: Obligation<Currency>

An instance of the contract class that will verify this state.

+
+dueBefore +val dueBefore: Instant
+issuanceDef +val issuanceDef: IssuanceDefinition<P>
+lifecycle +var lifecycle: Lifecycle
+multilateralNetState +val multilateralNetState: MultilateralNetState<P>
+obligor +val obligor: Party

Where the debt originates from (obligor)

+
+owner +val owner: PublicKey

There must be a MoveCommand signed by this key to claim the amount

+
+participants +val participants: List<PublicKey>

A participant is any party that is able to consume this state in a valid transaction.

+
+productAmount +val productAmount: Amount<P>
+quantity +val quantity: Long
+template +val template: StateTemplate<P>
+

Functions

+ + + + + + + + + + + + + + + + + + + +
+move +fun move(newAmount: Amount<P>, newOwner: PublicKey): State<P>
+net +fun net(other: State<P>): State<P>

Perform bilateral netting of this state with another state. The two states must be compatible (as in +bilateralNetState objects are equal).

+
+toString +fun toString(): String
+withNewOwner +fun withNewOwner(newOwner: PublicKey): <ERROR CLASS>

Copies the underlying data structure, replacing the owner field with this new value and leaving the rest alone

+
+

Extension Functions

+ + + + + + + + + + + + + + + + + + + +
+at +infix fun <T> State<T>.at(dueBefore: Instant): State<T>
+between +infix fun <T> State<T>.between(parties: <ERROR CLASS><Party, PublicKey>): State<T>
+issued by +infix fun <T> State<T>.issued by(party: Party): State<T>
+owned by +infix fun <T> State<T>.owned by(owner: PublicKey): <ERROR CLASS>
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/issuance-def.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/issuance-def.html new file mode 100644 index 0000000000..c7e58c54ae --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/issuance-def.html @@ -0,0 +1,16 @@ + + +Obligation.State.issuanceDef - + + + +com.r3corda.contracts.asset / Obligation / State / issuanceDef
+
+

issuanceDef

+ +val issuanceDef: IssuanceDefinition<P>
+Overrides FungibleAssetState.issuanceDef
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/lifecycle.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/lifecycle.html new file mode 100644 index 0000000000..e53e32620d --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/lifecycle.html @@ -0,0 +1,15 @@ + + +Obligation.State.lifecycle - + + + +com.r3corda.contracts.asset / Obligation / State / lifecycle
+
+

lifecycle

+ +var lifecycle: Lifecycle
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/move.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/move.html new file mode 100644 index 0000000000..57c87b1e33 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/move.html @@ -0,0 +1,15 @@ + + +Obligation.State.move - + + + +com.r3corda.contracts.asset / Obligation / State / move
+
+

move

+ +fun move(newAmount: Amount<P>, newOwner: PublicKey): State<P>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/multilateral-net-state.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/multilateral-net-state.html new file mode 100644 index 0000000000..520edcd1ab --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/multilateral-net-state.html @@ -0,0 +1,15 @@ + + +Obligation.State.multilateralNetState - + + + +com.r3corda.contracts.asset / Obligation / State / multilateralNetState
+
+

multilateralNetState

+ +val multilateralNetState: MultilateralNetState<P>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/net.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/net.html new file mode 100644 index 0000000000..6bcc04c4fa --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/net.html @@ -0,0 +1,17 @@ + + +Obligation.State.net - + + + +com.r3corda.contracts.asset / Obligation / State / net
+
+

net

+ +fun net(other: State<P>): State<P>
+

Perform bilateral netting of this state with another state. The two states must be compatible (as in +bilateralNetState objects are equal).

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/obligor.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/obligor.html new file mode 100644 index 0000000000..5145036d29 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/obligor.html @@ -0,0 +1,16 @@ + + +Obligation.State.obligor - + + + +com.r3corda.contracts.asset / Obligation / State / obligor
+
+

obligor

+ +val obligor: Party
+

Where the debt originates from (obligor)

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/owner.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/owner.html new file mode 100644 index 0000000000..85b1a8b720 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/owner.html @@ -0,0 +1,20 @@ + + +Obligation.State.owner - + + + +com.r3corda.contracts.asset / Obligation / State / owner
+
+

owner

+ +val owner: PublicKey
+Overrides OwnableState.owner
+

There must be a MoveCommand signed by this key to claim the amount

+

Getter
+

There must be a MoveCommand signed by this key to claim the amount

+

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/participants.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/participants.html new file mode 100644 index 0000000000..94bbb94bd5 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/participants.html @@ -0,0 +1,34 @@ + + +Obligation.State.participants - + + + +com.r3corda.contracts.asset / Obligation / State / participants
+
+

participants

+ +val participants: List<PublicKey>
+Overrides ContractState.participants
+

A participant is any party that is able to consume this state in a valid transaction.

+

The list of participants is required for certain types of transactions. For example, when changing the notary +for this state (TransactionType.NotaryChange), every participants has to be involved and approve the transaction +so that they receive the updated state, and dont end up in a situation where they can no longer use a state +they possess, since someone consumed that state during the notary change process.

+

The participants list should normally be derived from the contents of the state. E.g. for Cash the participants +list should just contain the owner.

+
+
+

Getter
+

A participant is any party that is able to consume this state in a valid transaction.

+

The list of participants is required for certain types of transactions. For example, when changing the notary +for this state (TransactionType.NotaryChange), every participants has to be involved and approve the transaction +so that they receive the updated state, and dont end up in a situation where they can no longer use a state +they possess, since someone consumed that state during the notary change process.

+

The participants list should normally be derived from the contents of the state. E.g. for Cash the participants +list should just contain the owner.

+

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/product-amount.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/product-amount.html new file mode 100644 index 0000000000..59d6383ed5 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/product-amount.html @@ -0,0 +1,16 @@ + + +Obligation.State.productAmount - + + + +com.r3corda.contracts.asset / Obligation / State / productAmount
+
+

productAmount

+ +val productAmount: Amount<P>
+Overrides FungibleAssetState.productAmount
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/quantity.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/quantity.html new file mode 100644 index 0000000000..624ed322f8 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/quantity.html @@ -0,0 +1,15 @@ + + +Obligation.State.quantity - + + + +com.r3corda.contracts.asset / Obligation / State / quantity
+
+

quantity

+ +val quantity: Long
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/template.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/template.html new file mode 100644 index 0000000000..8283121696 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/template.html @@ -0,0 +1,15 @@ + + +Obligation.State.template - + + + +com.r3corda.contracts.asset / Obligation / State / template
+
+

template

+ +val template: StateTemplate<P>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/to-string.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/to-string.html new file mode 100644 index 0000000000..d3ae40b4bd --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/to-string.html @@ -0,0 +1,15 @@ + + +Obligation.State.toString - + + + +com.r3corda.contracts.asset / Obligation / State / toString
+
+

toString

+ +fun toString(): String
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/with-new-owner.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/with-new-owner.html new file mode 100644 index 0000000000..36ca43cbb3 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/-state/with-new-owner.html @@ -0,0 +1,17 @@ + + +Obligation.State.withNewOwner - + + + +com.r3corda.contracts.asset / Obligation / State / withNewOwner
+
+

withNewOwner

+ +fun withNewOwner(newOwner: PublicKey): <ERROR CLASS>
+Overrides OwnableState.withNewOwner
+

Copies the underlying data structure, replacing the owner field with this new value and leaving the rest alone

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/generate-close-out-netting.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/generate-close-out-netting.html new file mode 100644 index 0000000000..65c37cd33f --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/generate-close-out-netting.html @@ -0,0 +1,23 @@ + + +Obligation.generateCloseOutNetting - + + + +com.r3corda.contracts.asset / Obligation / generateCloseOutNetting
+
+

generateCloseOutNetting

+ +fun generateCloseOutNetting(tx: TransactionBuilder, signer: PublicKey, vararg states: State<P>): Unit
+

Generate a transaction performing close-out netting of two or more states.

+

Parameters

+ +signer - the party who will sign the transaction. Must be one of the obligor or beneficiary.
+
+ +states - two or more states, which must be compatible for bilateral netting (same issuance definitions, +and same parties involved).
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/generate-issue.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/generate-issue.html new file mode 100644 index 0000000000..38d8ecf3c7 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/generate-issue.html @@ -0,0 +1,16 @@ + + +Obligation.generateIssue - + + + +com.r3corda.contracts.asset / Obligation / generateIssue
+
+

generateIssue

+ +fun generateIssue(tx: TransactionBuilder, obligor: Party, issuanceDef: StateTemplate<P>, pennies: Long, beneficiary: PublicKey, notary: Party): Unit
+

Puts together an issuance transaction for the specified amount that starts out being owned by the given pubkey.

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/generate-payment-netting.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/generate-payment-netting.html new file mode 100644 index 0000000000..c2321893d5 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/generate-payment-netting.html @@ -0,0 +1,15 @@ + + +Obligation.generatePaymentNetting - + + + +com.r3corda.contracts.asset / Obligation / generatePaymentNetting
+
+

generatePaymentNetting

+ +fun generatePaymentNetting(tx: TransactionBuilder, issued: Issued<P>, notary: Party, vararg states: State<P>): Unit
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/generate-set-lifecycle.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/generate-set-lifecycle.html new file mode 100644 index 0000000000..0efd6a6520 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/generate-set-lifecycle.html @@ -0,0 +1,20 @@ + + +Obligation.generateSetLifecycle - + + + +com.r3corda.contracts.asset / Obligation / generateSetLifecycle
+
+

generateSetLifecycle

+ +fun generateSetLifecycle(tx: TransactionBuilder, statesAndRefs: List<StateAndRef<State<P>>>, lifecycle: Lifecycle, notary: Party): Unit
+

Generate a transaction changing the lifecycle of one or more state objects.

+

Parameters

+ +statesAndRefs - a list of state objects, which MUST all have the same issuance definition. This avoids +potential complications arising from different deadlines applying to different states.
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/generate-settle.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/generate-settle.html new file mode 100644 index 0000000000..a6a480a4b5 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/generate-settle.html @@ -0,0 +1,27 @@ + + +Obligation.generateSettle - + + + +com.r3corda.contracts.asset / Obligation / generateSettle
+
+

generateSettle

+ +fun generateSettle(tx: TransactionBuilder, statesAndRefs: Iterable<StateAndRef<State<P>>>, assetStatesAndRefs: Iterable<StateAndRef<FungibleAssetState<P, *>>>, moveCommand: MoveCommand, notary: Party): Unit
+

Parameters

+ +statesAndRefs - a list of state objects, which MUST all have the same aggregate state. This is done as +only a single settlement command can be present in a transaction, to avoid potential problems with allocating +assets to different obligation issuances.
+
+ +assetStatesAndRefs - a list of fungible asset state objects, which MUST all be of the same issued product. +It is strongly encouraged that these all have the same beneficiary.
+
+ +moveCommand - the command used to move the asset state objects to their new owner.
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/index.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/index.html new file mode 100644 index 0000000000..1b6555517e --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/index.html @@ -0,0 +1,194 @@ + + +Obligation - + + + +com.r3corda.contracts.asset / Obligation
+
+

Obligation

+class Obligation<P> : Contract
+

An obligation contract commits the obligor to delivering a specified amount of a fungible asset (for example the +Cash contract) at a specified future point in time. Settlement transactions may split and merge contracts across +multiple input and output states. The goal of this design is to handle amounts owed, and these contracts are expected +to be netted/merged, with settlement only for any remainder amount.

+

Parameters

+ +P - the product the obligation is for payment of.
+
+
+

Types

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+BilateralNetState +data class BilateralNetState<P> : NetState<P>

Subset of state, containing the elements which must match for two obligation transactions to be nettable. +If two obligation state objects produce equal bilateral net states, they are considered safe to net directly. +Bilateral states are used in close-out netting.

+
+Commands +interface Commands : CommandData
+IssuanceCommands +interface IssuanceCommands<P> : CommandData

Interface for commands that apply to states grouped by issuance definition

+
+IssuanceDefinition +data class IssuanceDefinition<P>

Subset of state, containing the elements specified when issuing a new settlement contract. +TODO: This needs to be something common to contracts that we can be obliged to pay, and moved +out into core accordingly.

+
+Lifecycle +enum class Lifecycle

Represents where in its lifecycle a contract state is, which in turn controls the commands that can be applied +to the state. Most states will not leave the NORMAL lifecycle. Note that settled (as an end lifecycle) is +represented by absence of the state on transaction output.

+
+MultilateralNetState +data class MultilateralNetState<P> : NetState<P>

Subset of state, containing the elements which must match for two or more obligation transactions to be candidates +for netting (this does not include the checks to enforce that everyones amounts received are the same at the end, +which is handled under the verify() function). +In comparison to BilateralNetState, this doesnt include the parties keys, as ensuring balances match on +input and output is handled elsewhere. +Used in cases where all parties (or their proxies) are signing, such as central clearing.

+
+NetState +interface NetState<P>

Common interface for the state subsets used when determining nettability of two or more states. Exposes the +underlying issued thing.

+
+State +data class State<P> : FungibleAssetState<P, IssuanceDefinition<P>>, BilateralNettableState<State<P>>

A state representing the obligation of one party (obligor) to deliver a specified number of +units of an underlying asset (described as issuanceDef.acceptableIssuedProducts) to the beneficiary +no later than the specified time.

+
+StateTemplate +data class StateTemplate<P>

Subset of state, containing the elements specified when issuing a new settlement contract.

+
+

Constructors

+ + + + + + + +
+<init> +Obligation()

An obligation contract commits the obligor to delivering a specified amount of a fungible asset (for example the +Cash contract) at a specified future point in time. Settlement transactions may split and merge contracts across +multiple input and output states. The goal of this design is to handle amounts owed, and these contracts are expected +to be netted/merged, with settlement only for any remainder amount.

+
+

Properties

+ + + + + + + +
+legalContractReference +val legalContractReference: SecureHash

TODO:

+
+

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+generateCloseOutNetting +fun generateCloseOutNetting(tx: TransactionBuilder, signer: PublicKey, vararg states: State<P>): Unit

Generate a transaction performing close-out netting of two or more states.

+
+generateIssue +fun generateIssue(tx: TransactionBuilder, obligor: Party, issuanceDef: StateTemplate<P>, pennies: Long, beneficiary: PublicKey, notary: Party): Unit

Puts together an issuance transaction for the specified amount that starts out being owned by the given pubkey.

+
+generatePaymentNetting +fun generatePaymentNetting(tx: TransactionBuilder, issued: Issued<P>, notary: Party, vararg states: State<P>): Unit
+generateSetLifecycle +fun generateSetLifecycle(tx: TransactionBuilder, statesAndRefs: List<StateAndRef<State<P>>>, lifecycle: Lifecycle, notary: Party): Unit

Generate a transaction changing the lifecycle of one or more state objects.

+
+generateSettle +fun generateSettle(tx: TransactionBuilder, statesAndRefs: Iterable<StateAndRef<State<P>>>, assetStatesAndRefs: Iterable<StateAndRef<FungibleAssetState<P, *>>>, moveCommand: MoveCommand, notary: Party): Unit
+verify +fun verify(tx: TransactionForContract): Unit

This is the function EVERYONE runs

+
+verifyIssueCommand +fun verifyIssueCommand(inputs: List<State<P>>, outputs: List<State<P>>, issueCommand: AuthenticatedObject<Issue<P>>, issued: Issued<P>, obligor: Party): Unit
+verifyNetCommand +fun verifyNetCommand(inputs: Iterable<State<P>>, outputs: Iterable<State<P>>, command: AuthenticatedObject<Net>, netState: NetState<P>): Unit

Verify a netting command. This handles both close-out and payment netting.

+
+verifySetLifecycleCommand +fun verifySetLifecycleCommand(inputs: List<State<P>>, outputs: List<State<P>>, tx: TransactionForContract, setLifecycleCommand: AuthenticatedObject<SetLifecycle<P>>): Unit

A default command mutates inputs and produces identical outputs, except that the lifecycle changes.

+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/legal-contract-reference.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/legal-contract-reference.html new file mode 100644 index 0000000000..d914315927 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/legal-contract-reference.html @@ -0,0 +1,25 @@ + + +Obligation.legalContractReference - + + + +com.r3corda.contracts.asset / Obligation / legalContractReference
+
+

legalContractReference

+ +val legalContractReference: SecureHash
+Overrides Contract.legalContractReference
+

TODO:

+
  1. hash should be of the contents, not the URI

    +
  2. allow the content to be specified at time of instance creation?

    +

Motivation: its the difference between a state object referencing a programRef, which references a +legalContractReference and a state object which directly references both. The latter allows the legal wording +to evolve without requiring code changes. But creates a risk that users create objects governed by a program +that is inconsistent with the legal contract

+
+
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/verify-issue-command.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/verify-issue-command.html new file mode 100644 index 0000000000..525e12f466 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/verify-issue-command.html @@ -0,0 +1,15 @@ + + +Obligation.verifyIssueCommand - + + + +com.r3corda.contracts.asset / Obligation / verifyIssueCommand
+
+

verifyIssueCommand

+ +protected fun verifyIssueCommand(inputs: List<State<P>>, outputs: List<State<P>>, issueCommand: AuthenticatedObject<Issue<P>>, issued: Issued<P>, obligor: Party): Unit
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/verify-net-command.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/verify-net-command.html new file mode 100644 index 0000000000..a897afe124 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/verify-net-command.html @@ -0,0 +1,16 @@ + + +Obligation.verifyNetCommand - + + + +com.r3corda.contracts.asset / Obligation / verifyNetCommand
+
+

verifyNetCommand

+ +protected fun verifyNetCommand(inputs: Iterable<State<P>>, outputs: Iterable<State<P>>, command: AuthenticatedObject<Net>, netState: NetState<P>): Unit
+

Verify a netting command. This handles both close-out and payment netting.

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/verify-set-lifecycle-command.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/verify-set-lifecycle-command.html new file mode 100644 index 0000000000..c741091d42 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/verify-set-lifecycle-command.html @@ -0,0 +1,16 @@ + + +Obligation.verifySetLifecycleCommand - + + + +com.r3corda.contracts.asset / Obligation / verifySetLifecycleCommand
+
+

verifySetLifecycleCommand

+ +protected fun verifySetLifecycleCommand(inputs: List<State<P>>, outputs: List<State<P>>, tx: TransactionForContract, setLifecycleCommand: AuthenticatedObject<SetLifecycle<P>>): Unit
+

A default command mutates inputs and produces identical outputs, except that the lifecycle changes.

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/-obligation/verify.html b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/verify.html new file mode 100644 index 0000000000..0216827f0a --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/-obligation/verify.html @@ -0,0 +1,17 @@ + + +Obligation.verify - + + + +com.r3corda.contracts.asset / Obligation / verify
+
+

verify

+ +fun verify(tx: TransactionForContract): Unit
+Overrides Contract.verify
+

This is the function EVERYONE runs

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/cash-balances.html b/docs/build/html/api/com.r3corda.contracts.asset/cash-balances.html new file mode 100644 index 0000000000..aaaba11c55 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/cash-balances.html @@ -0,0 +1,17 @@ + + +cashBalances - + + + +com.r3corda.contracts.asset / cashBalances
+
+

cashBalances

+ +val Wallet.cashBalances: Map<Currency, Amount<Currency>>
+

Returns a map of how much cash we have in each currency, ignoring details like issuer. Note: currencies for +which we have no cash evaluate to null (not present in map), not 0.

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/extract-amounts-due.html b/docs/build/html/api/com.r3corda.contracts.asset/extract-amounts-due.html new file mode 100644 index 0000000000..c64277dc3b --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/extract-amounts-due.html @@ -0,0 +1,18 @@ + + +extractAmountsDue - + + + +com.r3corda.contracts.asset / extractAmountsDue
+
+

extractAmountsDue

+ +fun <P> extractAmountsDue(product: P, states: Iterable<State<P>>): Map<<ERROR CLASS><PublicKey, PublicKey>, Amount<P>>
+

Convert a list of settlement states into total from each obligor to a beneficiary.

+

Return
+a map of obligor/beneficiary pairs to the balance due.

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/index.html b/docs/build/html/api/com.r3corda.contracts.asset/index.html new file mode 100644 index 0000000000..ef53ead635 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/index.html @@ -0,0 +1,129 @@ + + +com.r3corda.contracts.asset - + + + +com.r3corda.contracts.asset
+
+

Package com.r3corda.contracts.asset

+

Types

+ + + + + + + + + + + + + + + + + + + +
+Cash +class Cash : FungibleAsset<Currency>

A cash transaction may split and merge money represented by a set of (issuer, depositRef) pairs, across multiple +input and output states. Imagine a Bitcoin transaction but in which all UTXOs had a colour +(a blend of issuer+depositRef) and you couldnt merge outputs of two colours together, but you COULD put them in +the same transaction.

+
+FungibleAsset +abstract class FungibleAsset<T> : Contract

Superclass for contracts 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.

+
+FungibleAssetState +interface FungibleAssetState<T, I> : OwnableState

Common elements of cash contract states.

+
+Obligation +class Obligation<P> : Contract

An obligation contract commits the obligor to delivering a specified amount of a fungible asset (for example the +Cash contract) at a specified future point in time. Settlement transactions may split and merge contracts across +multiple input and output states. The goal of this design is to handle amounts owed, and these contracts are expected +to be netted/merged, with settlement only for any remainder amount.

+
+

Exceptions

+ + + + + + + +
+InsufficientBalanceException +class InsufficientBalanceException : Exception
+

Extensions for External Classes

+ + + + + + + +
+kotlin.collections.Iterable +
+

Properties

+ + + + + + + + + + + + + + + +
+CASH_PROGRAM_ID +val CASH_PROGRAM_ID: Cash
+OBLIGATION_PROGRAM_ID +val OBLIGATION_PROGRAM_ID: Obligation<Currency>
+cashBalances +val Wallet.cashBalances: Map<Currency, Amount<Currency>>

Returns a map of how much cash we have in each currency, ignoring details like issuer. Note: currencies for +which we have no cash evaluate to null (not present in map), not 0.

+
+

Functions

+ + + + + + + + + + + + + + + +
+extractAmountsDue +fun <P> extractAmountsDue(product: P, states: Iterable<State<P>>): Map<<ERROR CLASS><PublicKey, PublicKey>, Amount<P>>

Convert a list of settlement states into total from each obligor to a beneficiary.

+
+netAmountsDue +fun <P> netAmountsDue(balances: Map<<ERROR CLASS><PublicKey, PublicKey>, Amount<P>>): Map<<ERROR CLASS><PublicKey, PublicKey>, Amount<P>>

Net off the amounts due between parties.

+
+sumAmountsDue +fun <P> sumAmountsDue(balances: Map<<ERROR CLASS><PublicKey, PublicKey>, Amount<P>>): Map<PublicKey, Long>

Calculate the total balance movement for each party in the transaction, based off a summary of balances between +each obligor and beneficiary.

+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/index.html b/docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/index.html new file mode 100644 index 0000000000..ee4354b4dc --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/index.html @@ -0,0 +1,98 @@ + + +com.r3corda.contracts.asset.kotlin.collections.Iterable - + + + +com.r3corda.contracts.asset / kotlin.collections.Iterable
+
+

Extensions for kotlin.collections.Iterable

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+sumCash +fun Iterable<ContractState>.sumCash(): <ERROR CLASS>

Sums the cash states in the list, throwing an exception if there are none, or if any of the cash +states cannot be added together (i.e. are different currencies).

+
+sumCashBy +fun Iterable<ContractState>.sumCashBy(owner: PublicKey): <ERROR CLASS>

Sums the cash states in the list belonging to a single owner, throwing an exception +if there are none, or if any of the cash states cannot be added together (i.e. are +different currencies).

+
+sumCashOrNull +fun Iterable<ContractState>.sumCashOrNull(): <ERROR CLASS>

Sums the cash states in the list, returning null if there are none.

+
+sumCashOrZero +fun Iterable<ContractState>.sumCashOrZero(currency: Issued<Currency>): <ERROR CLASS>

Sums the cash states in the list, returning zero of the given currency if there are none.

+
+sumFungible +fun <T> Iterable<ContractState>.sumFungible(): <ERROR CLASS>

Sums the asset states in the list, throwing an exception if there are none, or if any of the asset +states cannot be added together (i.e. are different tokens).

+
+sumFungibleBy +fun <T> Iterable<ContractState>.sumFungibleBy(owner: PublicKey): <ERROR CLASS>

Sums the asset states in the list belonging to a single owner, throwing an exception +if there are none, or if any of the asset states cannot be added together (i.e. are +different tokens).

+
+sumFungibleOrNull +fun <T> Iterable<ContractState>.sumFungibleOrNull(): <ERROR CLASS>

Sums the asset states in the list, returning null if there are none.

+
+sumFungibleOrZero +fun <T> Iterable<ContractState>.sumFungibleOrZero(token: Issued<T>): <ERROR CLASS>

Sums the asset states in the list, returning zero of the given token if there are none.

+
+sumObligations +fun <P> Iterable<ContractState>.sumObligations(): Amount<P>

Sums the obligation states in the list, throwing an exception if there are none. All state objects in the list are presumed to be nettable.

+
+sumObligationsOrNull +fun <P> Iterable<ContractState>.sumObligationsOrNull(): Amount<P>?

Sums the obligation states in the list, returning null if there are none.

+
+sumObligationsOrZero +fun <P> Iterable<ContractState>.sumObligationsOrZero(product: P): Amount<P>

Sums the obligation states in the list, returning zero of the given product if there are none.

+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-cash-by.html b/docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-cash-by.html new file mode 100644 index 0000000000..94c663004e --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-cash-by.html @@ -0,0 +1,18 @@ + + +sumCashBy - + + + +com.r3corda.contracts.asset / kotlin.collections.Iterable / sumCashBy
+
+

sumCashBy

+ +fun Iterable<ContractState>.sumCashBy(owner: PublicKey): <ERROR CLASS>
+

Sums the cash states in the list belonging to a single owner, throwing an exception +if there are none, or if any of the cash states cannot be added together (i.e. are +different currencies).

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-cash-or-null.html b/docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-cash-or-null.html new file mode 100644 index 0000000000..3503e531b1 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-cash-or-null.html @@ -0,0 +1,16 @@ + + +sumCashOrNull - + + + +com.r3corda.contracts.asset / kotlin.collections.Iterable / sumCashOrNull
+
+

sumCashOrNull

+ +fun Iterable<ContractState>.sumCashOrNull(): <ERROR CLASS>
+

Sums the cash states in the list, returning null if there are none.

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-cash-or-zero.html b/docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-cash-or-zero.html new file mode 100644 index 0000000000..fa691bb37b --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-cash-or-zero.html @@ -0,0 +1,16 @@ + + +sumCashOrZero - + + + +com.r3corda.contracts.asset / kotlin.collections.Iterable / sumCashOrZero
+
+

sumCashOrZero

+ +fun Iterable<ContractState>.sumCashOrZero(currency: Issued<Currency>): <ERROR CLASS>
+

Sums the cash states in the list, returning zero of the given currency if there are none.

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-cash.html b/docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-cash.html new file mode 100644 index 0000000000..6283fb4e19 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-cash.html @@ -0,0 +1,17 @@ + + +sumCash - + + + +com.r3corda.contracts.asset / kotlin.collections.Iterable / sumCash
+
+

sumCash

+ +fun Iterable<ContractState>.sumCash(): <ERROR CLASS>
+

Sums the cash states in the list, throwing an exception if there are none, or if any of the cash +states cannot be added together (i.e. are different currencies).

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-fungible-by.html b/docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-fungible-by.html new file mode 100644 index 0000000000..cc0a42b341 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-fungible-by.html @@ -0,0 +1,18 @@ + + +sumFungibleBy - + + + +com.r3corda.contracts.asset / kotlin.collections.Iterable / sumFungibleBy
+
+

sumFungibleBy

+ +fun <T> Iterable<ContractState>.sumFungibleBy(owner: PublicKey): <ERROR CLASS>
+

Sums the asset states in the list belonging to a single owner, throwing an exception +if there are none, or if any of the asset states cannot be added together (i.e. are +different tokens).

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-fungible-or-null.html b/docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-fungible-or-null.html new file mode 100644 index 0000000000..e2b4162f63 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-fungible-or-null.html @@ -0,0 +1,16 @@ + + +sumFungibleOrNull - + + + +com.r3corda.contracts.asset / kotlin.collections.Iterable / sumFungibleOrNull
+
+

sumFungibleOrNull

+ +fun <T> Iterable<ContractState>.sumFungibleOrNull(): <ERROR CLASS>
+

Sums the asset states in the list, returning null if there are none.

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-fungible-or-zero.html b/docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-fungible-or-zero.html new file mode 100644 index 0000000000..f4f1dc7628 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-fungible-or-zero.html @@ -0,0 +1,16 @@ + + +sumFungibleOrZero - + + + +com.r3corda.contracts.asset / kotlin.collections.Iterable / sumFungibleOrZero
+
+

sumFungibleOrZero

+ +fun <T> Iterable<ContractState>.sumFungibleOrZero(token: Issued<T>): <ERROR CLASS>
+

Sums the asset states in the list, returning zero of the given token if there are none.

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-fungible.html b/docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-fungible.html new file mode 100644 index 0000000000..b594939bb4 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-fungible.html @@ -0,0 +1,17 @@ + + +sumFungible - + + + +com.r3corda.contracts.asset / kotlin.collections.Iterable / sumFungible
+
+

sumFungible

+ +fun <T> Iterable<ContractState>.sumFungible(): <ERROR CLASS>
+

Sums the asset states in the list, throwing an exception if there are none, or if any of the asset +states cannot be added together (i.e. are different tokens).

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-obligations-or-null.html b/docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-obligations-or-null.html new file mode 100644 index 0000000000..730805ad4a --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-obligations-or-null.html @@ -0,0 +1,16 @@ + + +sumObligationsOrNull - + + + +com.r3corda.contracts.asset / kotlin.collections.Iterable / sumObligationsOrNull
+
+

sumObligationsOrNull

+ +fun <P> Iterable<ContractState>.sumObligationsOrNull(): Amount<P>?
+

Sums the obligation states in the list, returning null if there are none.

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-obligations-or-zero.html b/docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-obligations-or-zero.html new file mode 100644 index 0000000000..79ff2da1f7 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-obligations-or-zero.html @@ -0,0 +1,16 @@ + + +sumObligationsOrZero - + + + +com.r3corda.contracts.asset / kotlin.collections.Iterable / sumObligationsOrZero
+
+

sumObligationsOrZero

+ +fun <P> Iterable<ContractState>.sumObligationsOrZero(product: P): Amount<P>
+

Sums the obligation states in the list, returning zero of the given product if there are none.

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-obligations.html b/docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-obligations.html new file mode 100644 index 0000000000..6d70942246 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/kotlin.collections.-iterable/sum-obligations.html @@ -0,0 +1,16 @@ + + +sumObligations - + + + +com.r3corda.contracts.asset / kotlin.collections.Iterable / sumObligations
+
+

sumObligations

+ +fun <P> Iterable<ContractState>.sumObligations(): Amount<P>
+

Sums the obligation states in the list, throwing an exception if there are none. All state objects in the list are presumed to be nettable.

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/net-amounts-due.html b/docs/build/html/api/com.r3corda.contracts.asset/net-amounts-due.html new file mode 100644 index 0000000000..f95281b45d --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/net-amounts-due.html @@ -0,0 +1,16 @@ + + +netAmountsDue - + + + +com.r3corda.contracts.asset / netAmountsDue
+
+

netAmountsDue

+ +fun <P> netAmountsDue(balances: Map<<ERROR CLASS><PublicKey, PublicKey>, Amount<P>>): Map<<ERROR CLASS><PublicKey, PublicKey>, Amount<P>>
+

Net off the amounts due between parties.

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.asset/sum-amounts-due.html b/docs/build/html/api/com.r3corda.contracts.asset/sum-amounts-due.html new file mode 100644 index 0000000000..9b65b87b47 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.asset/sum-amounts-due.html @@ -0,0 +1,21 @@ + + +sumAmountsDue - + + + +com.r3corda.contracts.asset / sumAmountsDue
+
+

sumAmountsDue

+ +fun <P> sumAmountsDue(balances: Map<<ERROR CLASS><PublicKey, PublicKey>, Amount<P>>): Map<PublicKey, Long>
+

Calculate the total balance movement for each party in the transaction, based off a summary of balances between +each obligor and beneficiary.

+

Parameters

+ +balances - payments due, indexed by obligor and beneficiary. Zero balances are stripped from the map before being +returned.
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.testing/-c-a-s-h.html b/docs/build/html/api/com.r3corda.contracts.testing/-c-a-s-h.html index 05953f3971..5c1d781fe3 100644 --- a/docs/build/html/api/com.r3corda.contracts.testing/-c-a-s-h.html +++ b/docs/build/html/api/com.r3corda.contracts.testing/-c-a-s-h.html @@ -8,7 +8,8 @@

CASH

-val Amount<Currency>.CASH: State
+val Amount<Currency>.CASH: State
+

Allows you to write 100.DOLLARS.CASH



diff --git a/docs/build/html/api/com.r3corda.contracts.testing/-d-u-m-m-y_-c-a-s-h_-i-s-s-u-e-r.html b/docs/build/html/api/com.r3corda.contracts.testing/-d-u-m-m-y_-c-a-s-h_-i-s-s-u-e-r.html new file mode 100644 index 0000000000..09f333ef0e --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.testing/-d-u-m-m-y_-c-a-s-h_-i-s-s-u-e-r.html @@ -0,0 +1,15 @@ + + +DUMMY_CASH_ISSUER - + + + +com.r3corda.contracts.testing / DUMMY_CASH_ISSUER
+
+

DUMMY_CASH_ISSUER

+ +val DUMMY_CASH_ISSUER: PartyAndReference
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.testing/-d-u-m-m-y_-c-a-s-h_-i-s-s-u-e-r_-k-e-y.html b/docs/build/html/api/com.r3corda.contracts.testing/-d-u-m-m-y_-c-a-s-h_-i-s-s-u-e-r_-k-e-y.html new file mode 100644 index 0000000000..f1c444e9b9 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.testing/-d-u-m-m-y_-c-a-s-h_-i-s-s-u-e-r_-k-e-y.html @@ -0,0 +1,15 @@ + + +DUMMY_CASH_ISSUER_KEY - + + + +com.r3corda.contracts.testing / DUMMY_CASH_ISSUER_KEY
+
+

DUMMY_CASH_ISSUER_KEY

+ +val DUMMY_CASH_ISSUER_KEY: <ERROR CLASS>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/-c-a-s-h.html b/docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/-c-a-s-h.html new file mode 100644 index 0000000000..fb4a97eee7 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/-c-a-s-h.html @@ -0,0 +1,15 @@ + + +JavaTestHelpers.CASH - + + + +com.r3corda.contracts.testing / JavaTestHelpers / CASH
+
+

CASH

+ +fun CASH(amount: Amount<Currency>): State
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/-o-b-l-i-g-a-t-i-o-n.html b/docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/-o-b-l-i-g-a-t-i-o-n.html new file mode 100644 index 0000000000..442875f366 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/-o-b-l-i-g-a-t-i-o-n.html @@ -0,0 +1,15 @@ + + +JavaTestHelpers.OBLIGATION - + + + +com.r3corda.contracts.testing / JavaTestHelpers / OBLIGATION
+
+

OBLIGATION

+ +fun OBLIGATION(amount: Amount<Issued<Currency>>): State<Currency>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/-o-b-l-i-g-a-t-i-o-n_-d-e-f.html b/docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/-o-b-l-i-g-a-t-i-o-n_-d-e-f.html new file mode 100644 index 0000000000..75259dbb11 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/-o-b-l-i-g-a-t-i-o-n_-d-e-f.html @@ -0,0 +1,15 @@ + + +JavaTestHelpers.OBLIGATION_DEF - + + + +com.r3corda.contracts.testing / JavaTestHelpers / OBLIGATION_DEF
+
+

OBLIGATION_DEF

+ +fun OBLIGATION_DEF(issued: Issued<Currency>): StateTemplate<Currency>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/-s-t-a-t-e.html b/docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/-s-t-a-t-e.html new file mode 100644 index 0000000000..01f3c66dd8 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/-s-t-a-t-e.html @@ -0,0 +1,15 @@ + + +JavaTestHelpers.STATE - + + + +com.r3corda.contracts.testing / JavaTestHelpers / STATE
+
+

STATE

+ +fun STATE(amount: Amount<Issued<Currency>>): State
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/at.html b/docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/at.html new file mode 100644 index 0000000000..7a51b70b8f --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/at.html @@ -0,0 +1,17 @@ + + +JavaTestHelpers.at - + + + +com.r3corda.contracts.testing / JavaTestHelpers / at
+
+

at

+ +fun <T> at(state: State<T>, dueBefore: Instant): State<T>
+ +fun <T> at(issuanceDef: IssuanceDefinition<T>, dueBefore: Instant): IssuanceDefinition<T>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/between.html b/docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/between.html new file mode 100644 index 0000000000..7e0dd0d712 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/between.html @@ -0,0 +1,15 @@ + + +JavaTestHelpers.between - + + + +com.r3corda.contracts.testing / JavaTestHelpers / between
+
+

between

+ +fun <T> between(state: State<T>, parties: <ERROR CLASS><Party, PublicKey>): State<T>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/index.html b/docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/index.html new file mode 100644 index 0000000000..8633b86f4e --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/index.html @@ -0,0 +1,87 @@ + + +JavaTestHelpers - + + + +com.r3corda.contracts.testing / JavaTestHelpers
+
+

JavaTestHelpers

+object JavaTestHelpers
+
+
+

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+CASH +fun CASH(amount: Amount<Currency>): State
+OBLIGATION +fun OBLIGATION(amount: Amount<Issued<Currency>>): State<Currency>
+OBLIGATION_DEF +fun OBLIGATION_DEF(issued: Issued<Currency>): StateTemplate<Currency>
+STATE +fun STATE(amount: Amount<Issued<Currency>>): State
+at +fun <T> at(state: State<T>, dueBefore: Instant): State<T>
+fun <T> at(issuanceDef: IssuanceDefinition<T>, dueBefore: Instant): IssuanceDefinition<T>
+between +fun <T> between(state: State<T>, parties: <ERROR CLASS><Party, PublicKey>): State<T>
+issuedBy +fun issuedBy(state: State, party: Party): State
+fun issuedBy(state: State, deposit: PartyAndReference): State
+fun <T> issuedBy(state: State<T>, party: Party): State<T>
+ownedBy +fun ownedBy(state: State, owner: PublicKey): State
+fun <T> ownedBy(state: State<T>, owner: PublicKey): State<T>
+fun ownedBy(state: State, owner: PublicKey): State
+fun ownedBy(state: <ERROR CLASS>, new_owner: PublicKey): <ERROR CLASS>
+withDeposit +fun withDeposit(state: State, deposit: PartyAndReference): State
+withNotary +fun withNotary(state: State, notary: Party): TransactionState<State>
+fun withNotary(state: State, notary: Party): TransactionState<State>
+fun withNotary(state: ContractState, notary: Party): TransactionState<ContractState>
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/issued-by.html b/docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/issued-by.html new file mode 100644 index 0000000000..41c30bf9cf --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/issued-by.html @@ -0,0 +1,19 @@ + + +JavaTestHelpers.issuedBy - + + + +com.r3corda.contracts.testing / JavaTestHelpers / issuedBy
+
+

issuedBy

+ +fun issuedBy(state: State, party: Party): State
+ +fun issuedBy(state: State, deposit: PartyAndReference): State
+ +fun <T> issuedBy(state: State<T>, party: Party): State<T>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/owned-by.html b/docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/owned-by.html new file mode 100644 index 0000000000..862160230b --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/owned-by.html @@ -0,0 +1,21 @@ + + +JavaTestHelpers.ownedBy - + + + +com.r3corda.contracts.testing / JavaTestHelpers / ownedBy
+
+

ownedBy

+ +fun ownedBy(state: State, owner: PublicKey): State
+ +fun <T> ownedBy(state: State<T>, owner: PublicKey): State<T>
+ +fun ownedBy(state: State, owner: PublicKey): State
+ +fun ownedBy(state: <ERROR CLASS>, new_owner: PublicKey): <ERROR CLASS>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/with-deposit.html b/docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/with-deposit.html new file mode 100644 index 0000000000..b7187449e9 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/with-deposit.html @@ -0,0 +1,15 @@ + + +JavaTestHelpers.withDeposit - + + + +com.r3corda.contracts.testing / JavaTestHelpers / withDeposit
+
+

withDeposit

+ +fun withDeposit(state: State, deposit: PartyAndReference): State
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/with-notary.html b/docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/with-notary.html new file mode 100644 index 0000000000..e9b5ed42de --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.testing/-java-test-helpers/with-notary.html @@ -0,0 +1,19 @@ + + +JavaTestHelpers.withNotary - + + + +com.r3corda.contracts.testing / JavaTestHelpers / withNotary
+
+

withNotary

+ +fun withNotary(state: State, notary: Party): TransactionState<State>
+ +fun withNotary(state: State, notary: Party): TransactionState<State>
+ +fun withNotary(state: ContractState, notary: Party): TransactionState<ContractState>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.testing/-o-b-l-i-g-a-t-i-o-n.html b/docs/build/html/api/com.r3corda.contracts.testing/-o-b-l-i-g-a-t-i-o-n.html new file mode 100644 index 0000000000..309a73b291 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.testing/-o-b-l-i-g-a-t-i-o-n.html @@ -0,0 +1,15 @@ + + +OBLIGATION - + + + +com.r3corda.contracts.testing / OBLIGATION
+
+

OBLIGATION

+ +val Amount<Issued<Currency>>.OBLIGATION: State<Currency>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.testing/-o-b-l-i-g-a-t-i-o-n_-d-e-f.html b/docs/build/html/api/com.r3corda.contracts.testing/-o-b-l-i-g-a-t-i-o-n_-d-e-f.html new file mode 100644 index 0000000000..5bd59f9d59 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.testing/-o-b-l-i-g-a-t-i-o-n_-d-e-f.html @@ -0,0 +1,16 @@ + + +OBLIGATION_DEF - + + + +com.r3corda.contracts.testing / OBLIGATION_DEF
+
+

OBLIGATION_DEF

+ +val Issued<Currency>.OBLIGATION_DEF: StateTemplate<Currency>
+

Allows you to write 100.DOLLARS.CASH

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.testing/-s-t-a-t-e.html b/docs/build/html/api/com.r3corda.contracts.testing/-s-t-a-t-e.html new file mode 100644 index 0000000000..a9b452c60f --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.testing/-s-t-a-t-e.html @@ -0,0 +1,15 @@ + + +STATE - + + + +com.r3corda.contracts.testing / STATE
+
+

STATE

+ +val Amount<Issued<Currency>>.STATE: State
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.testing/at.html b/docs/build/html/api/com.r3corda.contracts.testing/at.html new file mode 100644 index 0000000000..525f11dfc7 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.testing/at.html @@ -0,0 +1,17 @@ + + +at - + + + +com.r3corda.contracts.testing / at
+
+

at

+ +infix fun <T> State<T>.at(dueBefore: Instant): State<T>
+ +infix fun <T> IssuanceDefinition<T>.at(dueBefore: Instant): IssuanceDefinition<T>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.testing/between.html b/docs/build/html/api/com.r3corda.contracts.testing/between.html new file mode 100644 index 0000000000..0e7f6f7c27 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.testing/between.html @@ -0,0 +1,15 @@ + + +between - + + + +com.r3corda.contracts.testing / between
+
+

between

+ +infix fun <T> State<T>.between(parties: <ERROR CLASS><Party, PublicKey>): State<T>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.testing/fill-with-some-test-cash.html b/docs/build/html/api/com.r3corda.contracts.testing/fill-with-some-test-cash.html new file mode 100644 index 0000000000..37efa769e1 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.testing/fill-with-some-test-cash.html @@ -0,0 +1,25 @@ + + +fillWithSomeTestCash - + + + +com.r3corda.contracts.testing / fillWithSomeTestCash
+
+

fillWithSomeTestCash

+ +fun ServiceHub.fillWithSomeTestCash(howMuch: Amount<Currency>, notary: Party = DUMMY_NOTARY, atLeastThisManyStates: Int = 3, atMostThisManyStates: Int = 10, rng: Random = Random(), ref: OpaqueBytes = OpaqueBytes(ByteArray(1, { 0 }))): Wallet
+

Creates a random set of between (by default) 3 and 10 cash states that add up to the given amount and adds them +to the wallet. This is intended for unit tests.

+

The cash is self issued with the current nodes identity, as fetched from the storage service. Thus it +would not be trusted by any sensible market participant and is effectively an IOU. If it had been issued by +the central bank, well ... thatd be a different story altogether.

+

The service hub needs to provide at least a key management service and a storage service.

+
+
+

Return
+a wallet object that represents the generated states (it will NOT be the full wallet from the service hub)

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.testing/generate-state.html b/docs/build/html/api/com.r3corda.contracts.testing/generate-state.html index 4d78aeb3c8..13957b9ee1 100644 --- a/docs/build/html/api/com.r3corda.contracts.testing/generate-state.html +++ b/docs/build/html/api/com.r3corda.contracts.testing/generate-state.html @@ -7,8 +7,8 @@ com.r3corda.contracts.testing / generateState

generateState

- -fun generateState(notary: Party = DUMMY_NOTARY): State
+ +fun generateState(): DummyState


diff --git a/docs/build/html/api/com.r3corda.contracts.testing/index.html b/docs/build/html/api/com.r3corda.contracts.testing/index.html index 6904052376..7529ac4e35 100644 --- a/docs/build/html/api/com.r3corda.contracts.testing/index.html +++ b/docs/build/html/api/com.r3corda.contracts.testing/index.html @@ -7,6 +7,17 @@ com.r3corda.contracts.testing

Package com.r3corda.contracts.testing

+

Types

+ + + + + + + +
+JavaTestHelpers +object JavaTestHelpers

Properties

@@ -14,7 +25,39 @@ +val Amount<Currency>.CASH: State

Allows you to write 100.DOLLARS.CASH

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +fun generateState(): DummyState +infix fun State.issued by(party: Party): State
+infix fun State.issued by(deposit: PartyAndReference): State
+infix fun <T> State<T>.issued by(party: Party): State<T> + + + + + + + +
CASH -val Amount<Currency>.CASH: State
+DUMMY_CASH_ISSUER +val DUMMY_CASH_ISSUER: PartyAndReference
+DUMMY_CASH_ISSUER_KEY +val DUMMY_CASH_ISSUER_KEY: <ERROR CLASS>
+OBLIGATION +val Amount<Issued<Currency>>.OBLIGATION: State<Currency>
+OBLIGATION_DEF +val Issued<Currency>.OBLIGATION_DEF: StateTemplate<Currency>

Allows you to write 100.DOLLARS.CASH

+
+STATE +val Amount<Issued<Currency>>.STATE: State
@@ -29,24 +72,62 @@
+at +infix fun <T> State<T>.at(dueBefore: Instant): State<T>
+infix fun <T> IssuanceDefinition<T>.at(dueBefore: Instant): IssuanceDefinition<T>
+between +infix fun <T> State<T>.between(parties: <ERROR CLASS><Party, PublicKey>): State<T>
+fillWithSomeTestCash +fun ServiceHub.fillWithSomeTestCash(howMuch: Amount<Currency>, notary: Party = DUMMY_NOTARY, atLeastThisManyStates: Int = 3, atMostThisManyStates: Int = 10, rng: Random = Random(), ref: OpaqueBytes = OpaqueBytes(ByteArray(1, { 0 }))): Wallet

Creates a random set of between (by default) 3 and 10 cash states that add up to the given amount and adds them +to the wallet. This is intended for unit tests.

+
generateState -fun generateState(notary: Party = DUMMY_NOTARY): State
issued by -infix fun State.issued by(party: Party): State
owned by -infix fun State.owned by(owner: PublicKey): State
-infix fun State.owned by(owner: PublicKey): State
+infix fun State.owned by(owner: PublicKey): <ERROR CLASS>
+infix fun <T> State<T>.owned by(owner: PublicKey): <ERROR CLASS>
+infix fun State.owned by(owner: PublicKey): <ERROR CLASS>
infix fun <ERROR CLASS>.owned by(new_owner: PublicKey): <ERROR CLASS>
+with deposit +infix fun State.with deposit(deposit: PartyAndReference): State
+with notary +infix fun State.with notary(notary: Party): TransactionState<State>
+infix fun State.with notary(notary: Party): TransactionState<State>
+infix fun ContractState.with notary(notary: Party): TransactionState<ContractState>
diff --git a/docs/build/html/api/com.r3corda.contracts.testing/issued by.html b/docs/build/html/api/com.r3corda.contracts.testing/issued by.html index ef47702d38..4ddc7a89ae 100644 --- a/docs/build/html/api/com.r3corda.contracts.testing/issued by.html +++ b/docs/build/html/api/com.r3corda.contracts.testing/issued by.html @@ -8,7 +8,11 @@

issued by

-infix fun State.issued by(party: Party): State
+infix fun State.issued by(party: Party): State
+ +infix fun State.issued by(deposit: PartyAndReference): State
+ +infix fun <T> State<T>.issued by(party: Party): State<T>


diff --git a/docs/build/html/api/com.r3corda.contracts.testing/owned by.html b/docs/build/html/api/com.r3corda.contracts.testing/owned by.html index ed366ba82a..cbf4d09ddf 100644 --- a/docs/build/html/api/com.r3corda.contracts.testing/owned by.html +++ b/docs/build/html/api/com.r3corda.contracts.testing/owned by.html @@ -8,9 +8,11 @@

owned by

-infix fun State.owned by(owner: PublicKey): State
+infix fun State.owned by(owner: PublicKey): <ERROR CLASS>
+ +infix fun <T> State<T>.owned by(owner: PublicKey): <ERROR CLASS>
-infix fun State.owned by(owner: PublicKey): State
+infix fun State.owned by(owner: PublicKey): <ERROR CLASS>
infix fun <ERROR CLASS>.owned by(new_owner: PublicKey): <ERROR CLASS>

diff --git a/docs/build/html/api/com.r3corda.contracts.testing/with deposit.html b/docs/build/html/api/com.r3corda.contracts.testing/with deposit.html new file mode 100644 index 0000000000..ec178280e9 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.testing/with deposit.html @@ -0,0 +1,15 @@ + + +with deposit - + + + +com.r3corda.contracts.testing / with deposit
+
+

with deposit

+ +infix fun State.with deposit(deposit: PartyAndReference): State
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts.testing/with notary.html b/docs/build/html/api/com.r3corda.contracts.testing/with notary.html new file mode 100644 index 0000000000..e3ce4a77ac --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts.testing/with notary.html @@ -0,0 +1,19 @@ + + +with notary - + + + +com.r3corda.contracts.testing / with notary
+
+

with notary

+ +infix fun State.with notary(notary: Party): TransactionState<State>
+ +infix fun State.with notary(notary: Party): TransactionState<State>
+ +infix fun ContractState.with notary(notary: Party): TransactionState<ContractState>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts/-commercial-paper/-state/-init-.html b/docs/build/html/api/com.r3corda.contracts/-commercial-paper/-state/-init-.html index 5a7cb07409..c26f5d22d2 100644 --- a/docs/build/html/api/com.r3corda.contracts/-commercial-paper/-state/-init-.html +++ b/docs/build/html/api/com.r3corda.contracts/-commercial-paper/-state/-init-.html @@ -7,7 +7,7 @@ com.r3corda.contracts / CommercialPaper / State / <init>

<init>

-State(issuance: PartyAndReference, owner: PublicKey, faceValue: Amount<Currency>, maturityDate: Instant, notary: Party)
+State(issuance: PartyAndReference, owner: PublicKey, faceValue: Amount<Issued<Currency>>, maturityDate: Instant)


diff --git a/docs/build/html/api/com.r3corda.contracts/-commercial-paper/-state/contract.html b/docs/build/html/api/com.r3corda.contracts/-commercial-paper/-state/contract.html index e86a6a1146..2be4b05310 100644 --- a/docs/build/html/api/com.r3corda.contracts/-commercial-paper/-state/contract.html +++ b/docs/build/html/api/com.r3corda.contracts/-commercial-paper/-state/contract.html @@ -10,7 +10,33 @@ val contract: CommercialPaper
Overrides ContractState.contract
-

Contract by which the state belongs

+

An instance of the contract class that will verify this state.

+

Discussion

+

This field is not the final design, its just a piece of temporary scaffolding. Once the contract sandbox is +further along, this field will become a description of which attachments are acceptable for defining the +contract.

+

Recall that an attachment is a zip file that can be referenced from any transaction. The contents of the +attachments are merged together and cannot define any overlapping files, thus for any given transaction there +is a miniature file system in which each file can be precisely mapped to the defining attachment.

+

Attachments may contain many things (data files, legal documents, etc) but mostly they contain JVM bytecode. +The class files inside define not only Contract implementations but also the classes that define the states. +Within the rest of a transaction, user-providable components are referenced by name only.

+

This means that a smart contract in Corda does two things:

+
  1. Define the data structures that compose the ledger (the states)

    +
  2. Define the rules for updating those structures

    +

The first is merely a utility role ... in theory contract code could manually parse byte streams by hand. +The second is vital to the integrity of the ledger. So this field needs to be able to express constraints like:

+
  • Only attachment 733c350f396a727655be1363c06635ba355036bd54a5ed6e594fd0b5d05f42f6 may be used with this state.

    +
  • Any attachment signed by public key 2d1ce0e330c52b8055258d776c40 may be used with this state.

    +
  • Attachments (1, 2, 3) may all be used with this state.

    +

and so on. In this way it becomes possible for the business logic governing a state to be evolved, if the +constraints are flexible enough.

+

Because contract classes often also define utilities that generate relevant transactions, and because attachments +cannot know their own hashes, we will have to provide various utilities to assist with obtaining the right +code constraints from within the contract code itself.

+

TODO: Implement the above description. See COR-226

+
+


diff --git a/docs/build/html/api/com.r3corda.contracts/-commercial-paper/-state/face-value.html b/docs/build/html/api/com.r3corda.contracts/-commercial-paper/-state/face-value.html index b03d33e1d5..d39247b8d5 100644 --- a/docs/build/html/api/com.r3corda.contracts/-commercial-paper/-state/face-value.html +++ b/docs/build/html/api/com.r3corda.contracts/-commercial-paper/-state/face-value.html @@ -8,7 +8,7 @@

faceValue

-val faceValue: Amount<Currency>
+val faceValue: Amount<Issued<Currency>>


diff --git a/docs/build/html/api/com.r3corda.contracts/-commercial-paper/-state/index.html b/docs/build/html/api/com.r3corda.contracts/-commercial-paper/-state/index.html index 8fd8f29de4..2f43e427f5 100644 --- a/docs/build/html/api/com.r3corda.contracts/-commercial-paper/-state/index.html +++ b/docs/build/html/api/com.r3corda.contracts/-commercial-paper/-state/index.html @@ -17,7 +17,7 @@
<init> -State(issuance: PartyAndReference, owner: PublicKey, faceValue: Amount<Currency>, maturityDate: Instant, notary: Party)
@@ -28,14 +28,14 @@ contract -val contract: CommercialPaper

Contract by which the state belongs

+val contract: CommercialPaper

An instance of the contract class that will verify this state.

faceValue -val faceValue: Amount<Currency> +val faceValue: Amount<Issued<Currency>> @@ -51,16 +51,16 @@ -notary +owner -val notary: Party

Identity of the notary that ensures this state is not used as an input to a transaction more than once

+val owner: PublicKey

There must be a MoveCommand signed by this key to claim the amount

-owner +participants -val owner: PublicKey

There must be a MoveCommand signed by this key to claim the amount

+val participants: List<PublicKey>

A participant is any party that is able to consume this state in a valid transaction.

@@ -78,7 +78,7 @@ withFaceValue -fun withFaceValue(newFaceValue: Amount<Currency>): <ERROR CLASS> +fun withFaceValue(newFaceValue: Amount<Issued<Currency>>): <ERROR CLASS> @@ -120,7 +120,13 @@ owned by -infix fun State.owned by(owner: PublicKey): State +infix fun State.owned by(owner: PublicKey): <ERROR CLASS> + + + +with notary + +infix fun State.with notary(notary: Party): TransactionState<State> diff --git a/docs/build/html/api/com.r3corda.contracts/-commercial-paper/-state/participants.html b/docs/build/html/api/com.r3corda.contracts/-commercial-paper/-state/participants.html new file mode 100644 index 0000000000..272c1e6369 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts/-commercial-paper/-state/participants.html @@ -0,0 +1,34 @@ + + +CommercialPaper.State.participants - + + + +com.r3corda.contracts / CommercialPaper / State / participants
+
+

participants

+ +val participants: List<PublicKey>
+Overrides ContractState.participants
+

A participant is any party that is able to consume this state in a valid transaction.

+

The list of participants is required for certain types of transactions. For example, when changing the notary +for this state (TransactionType.NotaryChange), every participants has to be involved and approve the transaction +so that they receive the updated state, and dont end up in a situation where they can no longer use a state +they possess, since someone consumed that state during the notary change process.

+

The participants list should normally be derived from the contents of the state. E.g. for Cash the participants +list should just contain the owner.

+
+
+

Getter
+

A participant is any party that is able to consume this state in a valid transaction.

+

The list of participants is required for certain types of transactions. For example, when changing the notary +for this state (TransactionType.NotaryChange), every participants has to be involved and approve the transaction +so that they receive the updated state, and dont end up in a situation where they can no longer use a state +they possess, since someone consumed that state during the notary change process.

+

The participants list should normally be derived from the contents of the state. E.g. for Cash the participants +list should just contain the owner.

+

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts/-commercial-paper/-state/with-face-value.html b/docs/build/html/api/com.r3corda.contracts/-commercial-paper/-state/with-face-value.html index d56566210a..91c20287dc 100644 --- a/docs/build/html/api/com.r3corda.contracts/-commercial-paper/-state/with-face-value.html +++ b/docs/build/html/api/com.r3corda.contracts/-commercial-paper/-state/with-face-value.html @@ -7,8 +7,8 @@ com.r3corda.contracts / CommercialPaper / State / withFaceValue

withFaceValue

- -fun withFaceValue(newFaceValue: Amount<Currency>): <ERROR CLASS>
+ +fun withFaceValue(newFaceValue: Amount<Issued<Currency>>): <ERROR CLASS>


diff --git a/docs/build/html/api/com.r3corda.contracts/-commercial-paper/generate-issue.html b/docs/build/html/api/com.r3corda.contracts/-commercial-paper/generate-issue.html index 29b7f9c950..07cd5611bf 100644 --- a/docs/build/html/api/com.r3corda.contracts/-commercial-paper/generate-issue.html +++ b/docs/build/html/api/com.r3corda.contracts/-commercial-paper/generate-issue.html @@ -7,8 +7,8 @@ com.r3corda.contracts / CommercialPaper / generateIssue

generateIssue

- -fun generateIssue(issuance: PartyAndReference, faceValue: Amount<Currency>, maturityDate: Instant, notary: Party): TransactionBuilder
+ +fun generateIssue(faceValue: Amount<Issued<Currency>>, maturityDate: Instant, notary: Party): TransactionBuilder

Returns a transaction that issues commercial paper, owned by the issuing parties key. Does not update an existing transaction because you arent able to issue multiple pieces of CP in a single transaction at the moment: this restriction is not fundamental and may be lifted later.

diff --git a/docs/build/html/api/com.r3corda.contracts/-commercial-paper/generate-redeem.html b/docs/build/html/api/com.r3corda.contracts/-commercial-paper/generate-redeem.html index 26faf02ea0..b2e06b2a4a 100644 --- a/docs/build/html/api/com.r3corda.contracts/-commercial-paper/generate-redeem.html +++ b/docs/build/html/api/com.r3corda.contracts/-commercial-paper/generate-redeem.html @@ -8,7 +8,7 @@

generateRedeem

-fun generateRedeem(tx: TransactionBuilder, paper: StateAndRef<State>, wallet: List<StateAndRef<State>>): Unit
+fun generateRedeem(tx: TransactionBuilder, paper: StateAndRef<State>, wallet: List<StateAndRef<State>>): Unit

Intended to be called by the issuer of some commercial paper, when an owner has notified us that they wish to redeem the paper. We must therefore send enough money to the key that owns the paper to satisfy the face value, and then ensure the paper is removed from the ledger.

diff --git a/docs/build/html/api/com.r3corda.contracts/-commercial-paper/index.html b/docs/build/html/api/com.r3corda.contracts/-commercial-paper/index.html index 09e0690fa6..cf067f4164 100644 --- a/docs/build/html/api/com.r3corda.contracts/-commercial-paper/index.html +++ b/docs/build/html/api/com.r3corda.contracts/-commercial-paper/index.html @@ -58,7 +58,7 @@ the contracts contents).

generateIssue -fun generateIssue(issuance: PartyAndReference, faceValue: Amount<Currency>, maturityDate: Instant, notary: Party): TransactionBuilder

Returns a transaction that issues commercial paper, owned by the issuing parties key. Does not update +fun generateIssue(faceValue: Amount<Issued<Currency>>, maturityDate: Instant, notary: Party): TransactionBuilder

Returns a transaction that issues commercial paper, owned by the issuing parties key. Does not update an existing transaction because you arent able to issue multiple pieces of CP in a single transaction at the moment: this restriction is not fundamental and may be lifted later.

@@ -74,7 +74,7 @@ at the moment: this restriction is not fundamental and may be lifted later.

generateRedeem -fun generateRedeem(tx: TransactionBuilder, paper: StateAndRef<State>, wallet: List<StateAndRef<State>>): Unit

Intended to be called by the issuer of some commercial paper, when an owner has notified us that they wish +fun generateRedeem(tx: TransactionBuilder, paper: StateAndRef<State>, wallet: List<StateAndRef<State>>): Unit

Intended to be called by the issuer of some commercial paper, when an owner has notified us that they wish to redeem the paper. We must therefore send enough money to the key that owns the paper to satisfy the face value, and then ensure the paper is removed from the ledger.

@@ -83,7 +83,7 @@ value, and then ensure the paper is removed from the ledger.

verify -fun verify(tx: TransactionForVerification): Unit

Takes an object that represents a state transition, and ensures the inputs/outputs/commands make sense. +fun verify(tx: TransactionForContract): Unit

Takes an object that represents a state transition, and ensures the inputs/outputs/commands make sense. Must throw an exception if theres a problem that should prevent state transition. Takes a single object rather than an argument so that additional data can be added without breaking binary compatibility with existing contract code.

diff --git a/docs/build/html/api/com.r3corda.contracts/-commercial-paper/verify.html b/docs/build/html/api/com.r3corda.contracts/-commercial-paper/verify.html index a8099f0d09..56ce4ec630 100644 --- a/docs/build/html/api/com.r3corda.contracts/-commercial-paper/verify.html +++ b/docs/build/html/api/com.r3corda.contracts/-commercial-paper/verify.html @@ -7,8 +7,8 @@ com.r3corda.contracts / CommercialPaper / verify

verify

- -fun verify(tx: TransactionForVerification): Unit
+ +fun verify(tx: TransactionForContract): Unit
Overrides Contract.verify

Takes an object that represents a state transition, and ensures the inputs/outputs/commands make sense. Must throw an exception if theres a problem that should prevent state transition. Takes a single object diff --git a/docs/build/html/api/com.r3corda.contracts/-fixed-rate/hash-code.html b/docs/build/html/api/com.r3corda.contracts/-fixed-rate/hash-code.html index 951e1e4acf..84764d7c6c 100644 --- a/docs/build/html/api/com.r3corda.contracts/-fixed-rate/hash-code.html +++ b/docs/build/html/api/com.r3corda.contracts/-fixed-rate/hash-code.html @@ -10,10 +10,10 @@ fun hashCode(): Int
Overrides Rate.hashCode
-Returns
+

Returns
the hash code of the ratioUnit or zero if the ratioUnit is null, as is the case for floating rate fixings that have not yet happened. Yet-to-be fixed floating rates need to be equal such that schedules can be tested -for equality.
+for equality.



diff --git a/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-calculation/next-fixing-date.html b/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-calculation/next-fixing-date.html index 186db672bc..52cb69daf2 100644 --- a/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-calculation/next-fixing-date.html +++ b/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-calculation/next-fixing-date.html @@ -10,8 +10,8 @@ fun nextFixingDate(): LocalDate?

Gets the date of the next fixing.

-Return
-LocalDate or null if no more fixings.
+

Return
+LocalDate or null if no more fixings.



diff --git a/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-floating-leg/-init-.html b/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-floating-leg/-init-.html index 8c445d37fd..f2461c6d4c 100644 --- a/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-floating-leg/-init-.html +++ b/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-floating-leg/-init-.html @@ -7,7 +7,7 @@ com.r3corda.contracts / InterestRateSwap / FloatingLeg / <init>

<init>

-FloatingLeg(floatingRatePayer: Party, notional: Amount<Currency>, paymentFrequency: Frequency, effectiveDate: LocalDate, effectiveDateAdjustment: DateRollConvention?, terminationDate: LocalDate, terminationDateAdjustment: DateRollConvention?, dayCountBasisDay: DayCountBasisDay, dayCountBasisYear: DayCountBasisYear, dayInMonth: Int, paymentRule: PaymentRule, paymentDelay: Int, paymentCalendar: BusinessCalendar, interestPeriodAdjustment: AccrualAdjustment, rollConvention: DateRollConvention, fixingRollConvention: DateRollConvention, resetDayInMonth: Int, fixingPeriod: DateOffset, resetRule: PaymentRule, fixingsPerPayment: Frequency, fixingCalendar: BusinessCalendar, index: String, indexSource: String, indexTenor: Tenor)
+FloatingLeg(floatingRatePayer: Party, notional: Amount<Currency>, paymentFrequency: Frequency, effectiveDate: LocalDate, effectiveDateAdjustment: DateRollConvention?, terminationDate: LocalDate, terminationDateAdjustment: DateRollConvention?, dayCountBasisDay: DayCountBasisDay, dayCountBasisYear: DayCountBasisYear, dayInMonth: Int, paymentRule: PaymentRule, paymentDelay: Int, paymentCalendar: BusinessCalendar, interestPeriodAdjustment: AccrualAdjustment, rollConvention: DateRollConvention, fixingRollConvention: DateRollConvention, resetDayInMonth: Int, fixingPeriodOffset: Int, resetRule: PaymentRule, fixingsPerPayment: Frequency, fixingCalendar: BusinessCalendar, index: String, indexSource: String, indexTenor: Tenor)


diff --git a/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-floating-leg/copy.html b/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-floating-leg/copy.html index 067f666975..ddcd0d5059 100644 --- a/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-floating-leg/copy.html +++ b/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-floating-leg/copy.html @@ -7,8 +7,8 @@ com.r3corda.contracts / InterestRateSwap / FloatingLeg / copy

copy

- -fun copy(floatingRatePayer: Party = this.floatingRatePayer, notional: Amount<Currency> = this.notional, paymentFrequency: Frequency = this.paymentFrequency, effectiveDate: LocalDate = this.effectiveDate, effectiveDateAdjustment: DateRollConvention? = this.effectiveDateAdjustment, terminationDate: LocalDate = this.terminationDate, terminationDateAdjustment: DateRollConvention? = this.terminationDateAdjustment, dayCountBasisDay: DayCountBasisDay = this.dayCountBasisDay, dayCountBasisYear: DayCountBasisYear = this.dayCountBasisYear, dayInMonth: Int = this.dayInMonth, paymentRule: PaymentRule = this.paymentRule, paymentDelay: Int = this.paymentDelay, paymentCalendar: BusinessCalendar = this.paymentCalendar, interestPeriodAdjustment: AccrualAdjustment = this.interestPeriodAdjustment, rollConvention: DateRollConvention = this.rollConvention, fixingRollConvention: DateRollConvention = this.fixingRollConvention, resetDayInMonth: Int = this.resetDayInMonth, fixingPeriod: DateOffset = this.fixingPeriod, resetRule: PaymentRule = this.resetRule, fixingsPerPayment: Frequency = this.fixingsPerPayment, fixingCalendar: BusinessCalendar = this.fixingCalendar, index: String = this.index, indexSource: String = this.indexSource, indexTenor: Tenor = this.indexTenor): FloatingLeg
+ +fun copy(floatingRatePayer: Party = this.floatingRatePayer, notional: Amount<Currency> = this.notional, paymentFrequency: Frequency = this.paymentFrequency, effectiveDate: LocalDate = this.effectiveDate, effectiveDateAdjustment: DateRollConvention? = this.effectiveDateAdjustment, terminationDate: LocalDate = this.terminationDate, terminationDateAdjustment: DateRollConvention? = this.terminationDateAdjustment, dayCountBasisDay: DayCountBasisDay = this.dayCountBasisDay, dayCountBasisYear: DayCountBasisYear = this.dayCountBasisYear, dayInMonth: Int = this.dayInMonth, paymentRule: PaymentRule = this.paymentRule, paymentDelay: Int = this.paymentDelay, paymentCalendar: BusinessCalendar = this.paymentCalendar, interestPeriodAdjustment: AccrualAdjustment = this.interestPeriodAdjustment, rollConvention: DateRollConvention = this.rollConvention, fixingRollConvention: DateRollConvention = this.fixingRollConvention, resetDayInMonth: Int = this.resetDayInMonth, fixingPeriod: Int = this.fixingPeriodOffset, resetRule: PaymentRule = this.resetRule, fixingsPerPayment: Frequency = this.fixingsPerPayment, fixingCalendar: BusinessCalendar = this.fixingCalendar, index: String = this.index, indexSource: String = this.indexSource, indexTenor: Tenor = this.indexTenor): FloatingLeg


diff --git a/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-floating-leg/fixing-period-offset.html b/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-floating-leg/fixing-period-offset.html new file mode 100644 index 0000000000..f5e296f814 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-floating-leg/fixing-period-offset.html @@ -0,0 +1,15 @@ + + +InterestRateSwap.FloatingLeg.fixingPeriodOffset - + + + +com.r3corda.contracts / InterestRateSwap / FloatingLeg / fixingPeriodOffset
+
+

fixingPeriodOffset

+ +var fixingPeriodOffset: Int
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-floating-leg/index.html b/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-floating-leg/index.html index 15799fb581..8f1d4d245b 100644 --- a/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-floating-leg/index.html +++ b/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-floating-leg/index.html @@ -17,7 +17,7 @@ <init> -FloatingLeg(floatingRatePayer: Party, notional: Amount<Currency>, paymentFrequency: Frequency, effectiveDate: LocalDate, effectiveDateAdjustment: DateRollConvention?, terminationDate: LocalDate, terminationDateAdjustment: DateRollConvention?, dayCountBasisDay: DayCountBasisDay, dayCountBasisYear: DayCountBasisYear, dayInMonth: Int, paymentRule: PaymentRule, paymentDelay: Int, paymentCalendar: BusinessCalendar, interestPeriodAdjustment: AccrualAdjustment, rollConvention: DateRollConvention, fixingRollConvention: DateRollConvention, resetDayInMonth: Int, fixingPeriod: DateOffset, resetRule: PaymentRule, fixingsPerPayment: Frequency, fixingCalendar: BusinessCalendar, index: String, indexSource: String, indexTenor: Tenor) +FloatingLeg(floatingRatePayer: Party, notional: Amount<Currency>, paymentFrequency: Frequency, effectiveDate: LocalDate, effectiveDateAdjustment: DateRollConvention?, terminationDate: LocalDate, terminationDateAdjustment: DateRollConvention?, dayCountBasisDay: DayCountBasisDay, dayCountBasisYear: DayCountBasisYear, dayInMonth: Int, paymentRule: PaymentRule, paymentDelay: Int, paymentCalendar: BusinessCalendar, interestPeriodAdjustment: AccrualAdjustment, rollConvention: DateRollConvention, fixingRollConvention: DateRollConvention, resetDayInMonth: Int, fixingPeriodOffset: Int, resetRule: PaymentRule, fixingsPerPayment: Frequency, fixingCalendar: BusinessCalendar, index: String, indexSource: String, indexTenor: Tenor) @@ -32,9 +32,9 @@ -fixingPeriod +fixingPeriodOffset -var fixingPeriod: DateOffset +var fixingPeriodOffset: Int @@ -182,7 +182,7 @@ copy -fun copy(floatingRatePayer: Party = this.floatingRatePayer, notional: Amount<Currency> = this.notional, paymentFrequency: Frequency = this.paymentFrequency, effectiveDate: LocalDate = this.effectiveDate, effectiveDateAdjustment: DateRollConvention? = this.effectiveDateAdjustment, terminationDate: LocalDate = this.terminationDate, terminationDateAdjustment: DateRollConvention? = this.terminationDateAdjustment, dayCountBasisDay: DayCountBasisDay = this.dayCountBasisDay, dayCountBasisYear: DayCountBasisYear = this.dayCountBasisYear, dayInMonth: Int = this.dayInMonth, paymentRule: PaymentRule = this.paymentRule, paymentDelay: Int = this.paymentDelay, paymentCalendar: BusinessCalendar = this.paymentCalendar, interestPeriodAdjustment: AccrualAdjustment = this.interestPeriodAdjustment, rollConvention: DateRollConvention = this.rollConvention, fixingRollConvention: DateRollConvention = this.fixingRollConvention, resetDayInMonth: Int = this.resetDayInMonth, fixingPeriod: DateOffset = this.fixingPeriod, resetRule: PaymentRule = this.resetRule, fixingsPerPayment: Frequency = this.fixingsPerPayment, fixingCalendar: BusinessCalendar = this.fixingCalendar, index: String = this.index, indexSource: String = this.indexSource, indexTenor: Tenor = this.indexTenor): FloatingLeg +fun copy(floatingRatePayer: Party = this.floatingRatePayer, notional: Amount<Currency> = this.notional, paymentFrequency: Frequency = this.paymentFrequency, effectiveDate: LocalDate = this.effectiveDate, effectiveDateAdjustment: DateRollConvention? = this.effectiveDateAdjustment, terminationDate: LocalDate = this.terminationDate, terminationDateAdjustment: DateRollConvention? = this.terminationDateAdjustment, dayCountBasisDay: DayCountBasisDay = this.dayCountBasisDay, dayCountBasisYear: DayCountBasisYear = this.dayCountBasisYear, dayInMonth: Int = this.dayInMonth, paymentRule: PaymentRule = this.paymentRule, paymentDelay: Int = this.paymentDelay, paymentCalendar: BusinessCalendar = this.paymentCalendar, interestPeriodAdjustment: AccrualAdjustment = this.interestPeriodAdjustment, rollConvention: DateRollConvention = this.rollConvention, fixingRollConvention: DateRollConvention = this.fixingRollConvention, resetDayInMonth: Int = this.resetDayInMonth, fixingPeriod: Int = this.fixingPeriodOffset, resetRule: PaymentRule = this.resetRule, fixingsPerPayment: Frequency = this.fixingsPerPayment, fixingCalendar: BusinessCalendar = this.fixingCalendar, index: String = this.index, indexSource: String = this.indexSource, indexTenor: Tenor = this.indexTenor): FloatingLeg diff --git a/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-state/-init-.html b/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-state/-init-.html index 5d13246b7f..1da59b7898 100644 --- a/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-state/-init-.html +++ b/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-state/-init-.html @@ -7,7 +7,7 @@ com.r3corda.contracts / InterestRateSwap / State / <init>

<init>

-State(fixedLeg: FixedLeg, floatingLeg: FloatingLeg, calculation: Calculation, common: Common, notary: Party)
+State(fixedLeg: FixedLeg, floatingLeg: FloatingLeg, calculation: Calculation, common: Common)

The state class contains the 4 major data classes



diff --git a/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-state/contract.html b/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-state/contract.html index 3d5e0e1950..2e7a758a69 100644 --- a/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-state/contract.html +++ b/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-state/contract.html @@ -10,7 +10,33 @@ val contract: InterestRateSwap
Overrides ContractState.contract
-

Contract by which the state belongs

+

An instance of the contract class that will verify this state.

+

Discussion

+

This field is not the final design, its just a piece of temporary scaffolding. Once the contract sandbox is +further along, this field will become a description of which attachments are acceptable for defining the +contract.

+

Recall that an attachment is a zip file that can be referenced from any transaction. The contents of the +attachments are merged together and cannot define any overlapping files, thus for any given transaction there +is a miniature file system in which each file can be precisely mapped to the defining attachment.

+

Attachments may contain many things (data files, legal documents, etc) but mostly they contain JVM bytecode. +The class files inside define not only Contract implementations but also the classes that define the states. +Within the rest of a transaction, user-providable components are referenced by name only.

+

This means that a smart contract in Corda does two things:

+
  1. Define the data structures that compose the ledger (the states)

    +
  2. Define the rules for updating those structures

    +

The first is merely a utility role ... in theory contract code could manually parse byte streams by hand. +The second is vital to the integrity of the ledger. So this field needs to be able to express constraints like:

+
  • Only attachment 733c350f396a727655be1363c06635ba355036bd54a5ed6e594fd0b5d05f42f6 may be used with this state.

    +
  • Any attachment signed by public key 2d1ce0e330c52b8055258d776c40 may be used with this state.

    +
  • Attachments (1, 2, 3) may all be used with this state.

    +

and so on. In this way it becomes possible for the business logic governing a state to be evolved, if the +constraints are flexible enough.

+

Because contract classes often also define utilities that generate relevant transactions, and because attachments +cannot know their own hashes, we will have to provide various utilities to assist with obtaining the right +code constraints from within the contract code itself.

+

TODO: Implement the above description. See COR-226

+
+


diff --git a/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-state/generate-agreement.html b/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-state/generate-agreement.html index 21012e412e..a5cd1cce3b 100644 --- a/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-state/generate-agreement.html +++ b/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-state/generate-agreement.html @@ -7,8 +7,8 @@ com.r3corda.contracts / InterestRateSwap / State / generateAgreement

generateAgreement

- -fun generateAgreement(): TransactionBuilder
+ +fun generateAgreement(notary: Party): TransactionBuilder
Overrides DealState.generateAgreement

Generate a partial transaction representing an agreement (command) to this deal, allowing a general deal/agreement protocol to generate the necessary transaction for potential implementations

diff --git a/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-state/generate-fix.html b/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-state/generate-fix.html index a468f1a5ef..785167dc50 100644 --- a/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-state/generate-fix.html +++ b/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-state/generate-fix.html @@ -7,8 +7,8 @@ com.r3corda.contracts / InterestRateSwap / State / generateFix

generateFix

- -fun generateFix(ptx: TransactionBuilder, oldStateRef: StateRef, fix: Fix): Unit
+ +fun generateFix(ptx: TransactionBuilder, oldState: StateAndRef<*>, fix: Fix): Unit
Overrides FixableDealState.generateFix

Generate a fixing command for this deal and fix

TODO: This would also likely move to methods on the Contract once the changes to reference diff --git a/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-state/index.html b/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-state/index.html index 9321412cb0..654a8698a0 100644 --- a/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-state/index.html +++ b/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-state/index.html @@ -7,7 +7,7 @@ com.r3corda.contracts / InterestRateSwap / State

State

-data class State : FixableDealState
+data class State : FixableDealState, SchedulableState

The state class contains the 4 major data classes



@@ -18,7 +18,7 @@ <init> -State(fixedLeg: FixedLeg, floatingLeg: FloatingLeg, calculation: Calculation, common: Common, notary: Party)

The state class contains the 4 major data classes

+State(fixedLeg: FixedLeg, floatingLeg: FloatingLeg, calculation: Calculation, common: Common)

The state class contains the 4 major data classes

@@ -42,7 +42,7 @@ contract -val contract: InterestRateSwap

Contract by which the state belongs

+val contract: InterestRateSwap

An instance of the contract class that will verify this state.

@@ -59,9 +59,9 @@ -notary +participants -val notary: Party

Identity of the notary that ensures this state is not used as an input to a transaction more than once

+val participants: List<PublicKey>

A participant is any party that is able to consume this state in a valid transaction.

@@ -101,7 +101,7 @@ generateAgreement -fun generateAgreement(): TransactionBuilder

Generate a partial transaction representing an agreement (command) to this deal, allowing a general +fun generateAgreement(notary: Party): TransactionBuilder

Generate a partial transaction representing an agreement (command) to this deal, allowing a general deal/agreement protocol to generate the necessary transaction for potential implementations

@@ -109,7 +109,7 @@ deal/agreement protocol to generate the necessary transaction for potential impl generateFix -fun generateFix(ptx: TransactionBuilder, oldStateRef: StateRef, fix: Fix): Unit

Generate a fixing command for this deal and fix

+fun generateFix(ptx: TransactionBuilder, oldState: StateAndRef<*>, fix: Fix): Unit

Generate a fixing command for this deal and fix

@@ -128,6 +128,15 @@ deal/agreement protocol to generate the necessary transaction for potential impl +nextScheduledActivity + +fun nextScheduledActivity(thisStateRef: StateRef, protocolLogicRefFactory: ProtocolLogicRefFactory): ScheduledActivity?

Indicate whether there is some activity to be performed at some future point in time with respect to this +ContractState, what that activity is and at what point in time it should be initiated. +This can be used to implement deadlines for payment or processing of financial instruments according to a schedule.

+ + + + prettyPrint fun prettyPrint(): String

Just makes printing it out a bit better for those who dont have 80000 column wide monitors.

diff --git a/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-state/next-fixing-of.html b/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-state/next-fixing-of.html index 18b940ebf8..4df36de499 100644 --- a/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-state/next-fixing-of.html +++ b/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-state/next-fixing-of.html @@ -11,9 +11,6 @@ fun nextFixingOf(): FixOf?
Overrides FixableDealState.nextFixingOf

When is the next fixing and what is the fixing for?

-

TODO: In future we would use this to register for an event to trigger a/the fixing protocol

-
-


diff --git a/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-state/next-scheduled-activity.html b/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-state/next-scheduled-activity.html new file mode 100644 index 0000000000..f50a274e78 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-state/next-scheduled-activity.html @@ -0,0 +1,24 @@ + + +InterestRateSwap.State.nextScheduledActivity - + + + +com.r3corda.contracts / InterestRateSwap / State / nextScheduledActivity
+
+

nextScheduledActivity

+ +fun nextScheduledActivity(thisStateRef: StateRef, protocolLogicRefFactory: ProtocolLogicRefFactory): ScheduledActivity?
+Overrides SchedulableState.nextScheduledActivity
+

Indicate whether there is some activity to be performed at some future point in time with respect to this +ContractState, what that activity is and at what point in time it should be initiated. +This can be used to implement deadlines for payment or processing of financial instruments according to a schedule.

+

The state has no reference to its own StateRef, so supply that for use as input to any ProtocolLogic constructed.

+
+
+

Return
+null if there is no activity to schedule

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-state/participants.html b/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-state/participants.html new file mode 100644 index 0000000000..1de142b7c2 --- /dev/null +++ b/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-state/participants.html @@ -0,0 +1,34 @@ + + +InterestRateSwap.State.participants - + + + +com.r3corda.contracts / InterestRateSwap / State / participants
+
+

participants

+ +val participants: List<PublicKey>
+Overrides ContractState.participants
+

A participant is any party that is able to consume this state in a valid transaction.

+

The list of participants is required for certain types of transactions. For example, when changing the notary +for this state (TransactionType.NotaryChange), every participants has to be involved and approve the transaction +so that they receive the updated state, and dont end up in a situation where they can no longer use a state +they possess, since someone consumed that state during the notary change process.

+

The participants list should normally be derived from the contents of the state. E.g. for Cash the participants +list should just contain the owner.

+
+
+

Getter
+

A participant is any party that is able to consume this state in a valid transaction.

+

The list of participants is required for certain types of transactions. For example, when changing the notary +for this state (TransactionType.NotaryChange), every participants has to be involved and approve the transaction +so that they receive the updated state, and dont end up in a situation where they can no longer use a state +they possess, since someone consumed that state during the notary change process.

+

The participants list should normally be derived from the contents of the state. E.g. for Cash the participants +list should just contain the owner.

+

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-state/parties.html b/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-state/parties.html index c6ad978be4..9eb43a3855 100644 --- a/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-state/parties.html +++ b/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/-state/parties.html @@ -11,9 +11,9 @@ val parties: Array<Party>
Overrides DealState.parties

Exposes the Parties involved in a generic way

-Getter
+

Getter

Exposes the Parties involved in a generic way

-
+



diff --git a/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/index.html b/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/index.html index 454c3d0700..3dc096f1c6 100644 --- a/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/index.html +++ b/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/index.html @@ -62,7 +62,7 @@ copy / update for each transition)

State -data class State : FixableDealState

The state class contains the 4 major data classes

+data class State : FixableDealState, SchedulableState

The state class contains the 4 major data classes

@@ -148,7 +148,7 @@ Note: The day count, interest rate calculation etc are not finished yet, but the verify -fun verify(tx: TransactionForVerification): Unit

verify() with some examples of what needs to be checked.

+fun verify(tx: TransactionForContract): Unit

verify() with some examples of what needs to be checked.

diff --git a/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/verify.html b/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/verify.html index ea5638a19b..47b4b4b77d 100644 --- a/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/verify.html +++ b/docs/build/html/api/com.r3corda.contracts/-interest-rate-swap/verify.html @@ -7,8 +7,8 @@ com.r3corda.contracts / InterestRateSwap / verify

verify

- -fun verify(tx: TransactionForVerification): Unit
+ +fun verify(tx: TransactionForContract): Unit
Overrides Contract.verify

verify() with some examples of what needs to be checked.


diff --git a/docs/build/html/api/com.r3corda.contracts/-rate/hash-code.html b/docs/build/html/api/com.r3corda.contracts/-rate/hash-code.html index 3827fa867d..e48fba36d8 100644 --- a/docs/build/html/api/com.r3corda.contracts/-rate/hash-code.html +++ b/docs/build/html/api/com.r3corda.contracts/-rate/hash-code.html @@ -9,10 +9,10 @@

hashCode

open fun hashCode(): Int
-Returns
+

Returns
the hash code of the ratioUnit or zero if the ratioUnit is null, as is the case for floating rate fixings that have not yet happened. Yet-to-be fixed floating rates need to be equal such that schedules can be tested -for equality.
+for equality.



diff --git a/docs/build/html/api/com.r3corda.core.contracts/-amount/index.html b/docs/build/html/api/com.r3corda.core.contracts/-amount/index.html index 3e3ab1924a..e3aaaf3f4f 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-amount/index.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-amount/index.html @@ -108,7 +108,20 @@ amount used in whatever underlying thing the amount represents.

CASH -val Amount<Currency>.CASH: State +val Amount<Currency>.CASH: State

Allows you to write 100.DOLLARS.CASH

+ + + + +OBLIGATION + +val Amount<Issued<Currency>>.OBLIGATION: State<Currency> + + + +STATE + +val Amount<Issued<Currency>>.STATE: State @@ -117,6 +130,12 @@ amount used in whatever underlying thing the amount represents.

+issued by + +infix fun Amount<Currency>.issued by(deposit: PartyAndReference): Amount<Issued<Currency>> + + + times operator fun Amount<Currency>.times(other: RatioUnit): Amount<Currency> diff --git a/docs/build/html/api/com.r3corda.core.contracts/-bilateral-nettable-state/bilateral-net-state.html b/docs/build/html/api/com.r3corda.core.contracts/-bilateral-nettable-state/bilateral-net-state.html new file mode 100644 index 0000000000..35adc0bcb8 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-bilateral-nettable-state/bilateral-net-state.html @@ -0,0 +1,17 @@ + + +BilateralNettableState.bilateralNetState - + + + +com.r3corda.core.contracts / BilateralNettableState / bilateralNetState
+
+

bilateralNetState

+ +abstract val bilateralNetState: Any
+

Returns an object used to determine if two states can be subject to close-out netting. If two states return +equal objects, they can be close out netted together.

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-bilateral-nettable-state/index.html b/docs/build/html/api/com.r3corda.core.contracts/-bilateral-nettable-state/index.html new file mode 100644 index 0000000000..6d606cd40e --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-bilateral-nettable-state/index.html @@ -0,0 +1,55 @@ + + +BilateralNettableState - + + + +com.r3corda.core.contracts / BilateralNettableState
+
+

BilateralNettableState

+interface BilateralNettableState<T : BilateralNettableState<T>>
+

Interface for state objects that support being netted with other state objects.

+
+
+

Properties

+ + + + + + + +
+bilateralNetState +abstract val bilateralNetState: Any

Returns an object used to determine if two states can be subject to close-out netting. If two states return +equal objects, they can be close out netted together.

+
+

Functions

+ + + + + + + +
+net +abstract fun net(other: T): T

Perform bilateral netting of this state with another state. The two states must be compatible (as in +bilateralNetState objects are equal).

+
+

Inheritors

+ + + + + + + +
+State +data class State<P> : FungibleAssetState<P, IssuanceDefinition<P>>, BilateralNettableState<State<P>>

A state representing the obligation of one party (obligor) to deliver a specified number of +units of an underlying asset (described as issuanceDef.acceptableIssuedProducts) to the beneficiary +no later than the specified time.

+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-bilateral-nettable-state/net.html b/docs/build/html/api/com.r3corda.core.contracts/-bilateral-nettable-state/net.html new file mode 100644 index 0000000000..2aa96c4673 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-bilateral-nettable-state/net.html @@ -0,0 +1,17 @@ + + +BilateralNettableState.net - + + + +com.r3corda.core.contracts / BilateralNettableState / net
+
+

net

+ +abstract fun net(other: T): T
+

Perform bilateral netting of this state with another state. The two states must be compatible (as in +bilateralNetState objects are equal).

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-command-data.html b/docs/build/html/api/com.r3corda.core.contracts/-command-data.html index 043de5756c..f56b527e26 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-command-data.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-command-data.html @@ -22,13 +22,19 @@ -Commands +Commands interface Commands : CommandData -Commands +Commands + +interface Commands : CommandData + + + +Commands interface Commands : CommandData @@ -53,6 +59,27 @@ +IssuanceCommands + +interface IssuanceCommands<P> : CommandData

Interface for commands that apply to states grouped by issuance definition

+ + + + +IssueCommand + +interface IssueCommand : CommandData

A common issue command, to enforce that issue commands have a nonce value.

+ + + + +MoveCommand + +interface MoveCommand : CommandData

A common move command for contracts which can change owner.

+ + + + TimestampCommand data class TimestampCommand : CommandData

If present in a transaction, contains a time that was verified by the timestamping authority/authorities whose diff --git a/docs/build/html/api/com.r3corda.core.contracts/-contract-state/contract.html b/docs/build/html/api/com.r3corda.core.contracts/-contract-state/contract.html index 1cbd33ae28..582b5c58ad 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-contract-state/contract.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-contract-state/contract.html @@ -9,7 +9,33 @@

contract

abstract val contract: Contract
-

Contract by which the state belongs

+

An instance of the contract class that will verify this state.

+

Discussion

+

This field is not the final design, its just a piece of temporary scaffolding. Once the contract sandbox is +further along, this field will become a description of which attachments are acceptable for defining the +contract.

+

Recall that an attachment is a zip file that can be referenced from any transaction. The contents of the +attachments are merged together and cannot define any overlapping files, thus for any given transaction there +is a miniature file system in which each file can be precisely mapped to the defining attachment.

+

Attachments may contain many things (data files, legal documents, etc) but mostly they contain JVM bytecode. +The class files inside define not only Contract implementations but also the classes that define the states. +Within the rest of a transaction, user-providable components are referenced by name only.

+

This means that a smart contract in Corda does two things:

+
  1. Define the data structures that compose the ledger (the states)

    +
  2. Define the rules for updating those structures

    +

The first is merely a utility role ... in theory contract code could manually parse byte streams by hand. +The second is vital to the integrity of the ledger. So this field needs to be able to express constraints like:

+
  • Only attachment 733c350f396a727655be1363c06635ba355036bd54a5ed6e594fd0b5d05f42f6 may be used with this state.

    +
  • Any attachment signed by public key 2d1ce0e330c52b8055258d776c40 may be used with this state.

    +
  • Attachments (1, 2, 3) may all be used with this state.

    +

and so on. In this way it becomes possible for the business logic governing a state to be evolved, if the +constraints are flexible enough.

+

Because contract classes often also define utilities that generate relevant transactions, and because attachments +cannot know their own hashes, we will have to provide various utilities to assist with obtaining the right +code constraints from within the contract code itself.

+

TODO: Implement the above description. See COR-226

+
+


diff --git a/docs/build/html/api/com.r3corda.core.contracts/-contract-state/index.html b/docs/build/html/api/com.r3corda.core.contracts/-contract-state/index.html index b9f59297fd..13803bb336 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-contract-state/index.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-contract-state/index.html @@ -10,7 +10,9 @@ interface ContractState

A contract state (or just "state") contains opaque data used by a contract program. It can be thought of as a disk file that the program can use to persist data across transactions. States are immutable: once created they are never -updated, instead, any changes must generate a new successor state.

+updated, instead, any changes must generate a new successor state. States can be updated (consumed) only once: the +notary is responsible for ensuring there is no "double spending" by only signing a transaction if the input states +are all free.



Properties

@@ -20,14 +22,14 @@ updated, instead, any changes must generate a new successor state.

contract -abstract val contract: Contract

Contract by which the state belongs

+abstract val contract: Contract

An instance of the contract class that will verify this state.

-notary +participants -abstract val notary: Party

Identity of the notary that ensures this state is not used as an input to a transaction more than once

+abstract val participants: List<PublicKey>

A participant is any party that is able to consume this state in a valid transaction.

@@ -44,9 +46,9 @@ updated, instead, any changes must generate a new successor state.

-label +with notary -infix fun ContractState.label(label: String): LabeledOutput +infix fun ContractState.with notary(notary: Party): TransactionState<ContractState> @@ -55,6 +57,13 @@ updated, instead, any changes must generate a new successor state.

+DummyState + +data class DummyState : ContractState

Dummy state for use in testing. Not part of any real contract.

+ + + + LinearState interface LinearState : ContractState

A state that evolves by superseding itself, all of which share the common "thread"

@@ -62,6 +71,15 @@ updated, instead, any changes must generate a new successor state.

+MultiOwnerState + +data class MultiOwnerState : ContractState, State

Alternative state with multiple owners. This exists primarily to provide a dummy state with multiple +participants, and could in theory be merged with SingleOwnerState by putting the additional participants +in a different field, however this is a good example of a contract with multiple states.

+ + + + OwnableState interface OwnableState : ContractState

A contract state that can have a single owner.

@@ -69,9 +87,15 @@ updated, instead, any changes must generate a new successor state.

+SchedulableState + +interface SchedulableState : ContractState + + + State -class State : ContractState +interface State : ContractState diff --git a/docs/build/html/api/com.r3corda.core.contracts/-contract-state/participants.html b/docs/build/html/api/com.r3corda.core.contracts/-contract-state/participants.html new file mode 100644 index 0000000000..f9fb2b13ec --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-contract-state/participants.html @@ -0,0 +1,24 @@ + + +ContractState.participants - + + + +com.r3corda.core.contracts / ContractState / participants
+
+

participants

+ +abstract val participants: List<PublicKey>
+

A participant is any party that is able to consume this state in a valid transaction.

+

The list of participants is required for certain types of transactions. For example, when changing the notary +for this state (TransactionType.NotaryChange), every participants has to be involved and approve the transaction +so that they receive the updated state, and dont end up in a situation where they can no longer use a state +they possess, since someone consumed that state during the notary change process.

+

The participants list should normally be derived from the contents of the state. E.g. for Cash the participants +list should just contain the owner.

+
+
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-contract/index.html b/docs/build/html/api/com.r3corda.core.contracts/-contract/index.html index 739580dce6..07a0ccaa50 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-contract/index.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-contract/index.html @@ -34,7 +34,7 @@ the contracts contents).

verify -abstract fun verify(tx: TransactionForVerification): Unit

Takes an object that represents a state transition, and ensures the inputs/outputs/commands make sense. +abstract fun verify(tx: TransactionForContract): Unit

Takes an object that represents a state transition, and ensures the inputs/outputs/commands make sense. Must throw an exception if theres a problem that should prevent state transition. Takes a single object rather than an argument so that additional data can be added without breaking binary compatibility with existing contract code.

@@ -47,6 +47,12 @@ existing contract code.

+AlwaysSucceedContract + +class AlwaysSucceedContract : Contract + + + CommercialPaper class CommercialPaper : Contract @@ -59,7 +65,7 @@ existing contract code.

-FungibleAsset +FungibleAsset abstract class FungibleAsset<T> : Contract

Superclass for contracts 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 @@ -80,6 +86,16 @@ Currently, we are not interested (excuse pun) in valuing the swap, calculating t This is just a representation of a vanilla Fixed vs Floating (same currency) IRS in the R3 prototype model.

+ + +Obligation + +class Obligation<P> : Contract

An obligation contract commits the obligor to delivering a specified amount of a fungible asset (for example the +Cash contract) at a specified future point in time. Settlement transactions may split and merge contracts across +multiple input and output states. The goal of this design is to handle amounts owed, and these contracts are expected +to be netted/merged, with settlement only for any remainder amount.

+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-contract/verify.html b/docs/build/html/api/com.r3corda.core.contracts/-contract/verify.html index b45eb13e63..cf45cf2a45 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-contract/verify.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-contract/verify.html @@ -7,8 +7,8 @@ com.r3corda.core.contracts / Contract / verify

verify

- -abstract fun verify(tx: TransactionForVerification): Unit
+ +abstract fun verify(tx: TransactionForContract): Unit

Takes an object that represents a state transition, and ensures the inputs/outputs/commands make sense. Must throw an exception if theres a problem that should prevent state transition. Takes a single object rather than an argument so that additional data can be added without breaking binary compatibility with diff --git a/docs/build/html/api/com.r3corda.core.contracts/-deal-state/generate-agreement.html b/docs/build/html/api/com.r3corda.core.contracts/-deal-state/generate-agreement.html index 058b03e792..84717d321b 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-deal-state/generate-agreement.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-deal-state/generate-agreement.html @@ -7,8 +7,8 @@ com.r3corda.core.contracts / DealState / generateAgreement

generateAgreement

- -abstract fun generateAgreement(): TransactionBuilder
+ +abstract fun generateAgreement(notary: Party): TransactionBuilder

Generate a partial transaction representing an agreement (command) to this deal, allowing a general deal/agreement protocol to generate the necessary transaction for potential implementations

TODO: Currently this is the "inception" transaction but in future an offer of some description might be an input state ref

diff --git a/docs/build/html/api/com.r3corda.core.contracts/-deal-state/index.html b/docs/build/html/api/com.r3corda.core.contracts/-deal-state/index.html index 82c521ac03..19e34116b6 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-deal-state/index.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-deal-state/index.html @@ -50,7 +50,7 @@ implementation of general protocols that manipulate many agreement types.

generateAgreement -abstract fun generateAgreement(): TransactionBuilder

Generate a partial transaction representing an agreement (command) to this deal, allowing a general +abstract fun generateAgreement(notary: Party): TransactionBuilder

Generate a partial transaction representing an agreement (command) to this deal, allowing a general deal/agreement protocol to generate the necessary transaction for potential implementations

@@ -86,9 +86,9 @@ deal/agreement protocol to generate the necessary transaction for potential impl -label +with notary -infix fun ContractState.label(label: String): LabeledOutput +infix fun ContractState.with notary(notary: Party): TransactionState<ContractState> diff --git a/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-commands/-move/-init-.html b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-commands/-move/-init-.html new file mode 100644 index 0000000000..942f3076f1 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-commands/-move/-init-.html @@ -0,0 +1,14 @@ + + +DummyContract.Commands.Move.<init> - + + + +com.r3corda.core.contracts / DummyContract / Commands / Move / <init>
+
+

<init>

+Move()
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-commands/-move/index.html b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-commands/-move/index.html new file mode 100644 index 0000000000..7bba4256d4 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-commands/-move/index.html @@ -0,0 +1,42 @@ + + +DummyContract.Commands.Move - + + + +com.r3corda.core.contracts / DummyContract / Commands / Move
+
+

Move

+class Move : TypeOnlyCommandData, Commands
+
+
+

Constructors

+ + + + + + + +
+<init> +Move()
+

Inherited Functions

+ + + + + + + + + + + +
+equals +open fun equals(other: Any?): Boolean
+hashCode +open fun hashCode(): <ERROR CLASS>
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-commands/index.html b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-commands/index.html index 9cf330e87f..603df19645 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-commands/index.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-commands/index.html @@ -19,6 +19,12 @@ class Create : TypeOnlyCommandData, Commands + + +Move + +class Move : TypeOnlyCommandData, Commands +

Inheritors

@@ -30,6 +36,12 @@ class Create : TypeOnlyCommandData, Commands + + +Move + +class Move : TypeOnlyCommandData, Commands + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-multi-owner-state/-init-.html b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-multi-owner-state/-init-.html new file mode 100644 index 0000000000..89eb0ee891 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-multi-owner-state/-init-.html @@ -0,0 +1,17 @@ + + +DummyContract.MultiOwnerState.<init> - + + + +com.r3corda.core.contracts / DummyContract / MultiOwnerState / <init>
+
+

<init>

+MultiOwnerState(magicNumber: Int = 0, owners: List<PublicKey>)
+

Alternative state with multiple owners. This exists primarily to provide a dummy state with multiple +participants, and could in theory be merged with SingleOwnerState by putting the additional participants +in a different field, however this is a good example of a contract with multiple states.

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-multi-owner-state/contract.html b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-multi-owner-state/contract.html new file mode 100644 index 0000000000..ae60f276aa --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-multi-owner-state/contract.html @@ -0,0 +1,43 @@ + + +DummyContract.MultiOwnerState.contract - + + + +com.r3corda.core.contracts / DummyContract / MultiOwnerState / contract
+
+

contract

+ +val contract: DummyContract
+Overrides ContractState.contract
+

An instance of the contract class that will verify this state.

+

Discussion

+

This field is not the final design, its just a piece of temporary scaffolding. Once the contract sandbox is +further along, this field will become a description of which attachments are acceptable for defining the +contract.

+

Recall that an attachment is a zip file that can be referenced from any transaction. The contents of the +attachments are merged together and cannot define any overlapping files, thus for any given transaction there +is a miniature file system in which each file can be precisely mapped to the defining attachment.

+

Attachments may contain many things (data files, legal documents, etc) but mostly they contain JVM bytecode. +The class files inside define not only Contract implementations but also the classes that define the states. +Within the rest of a transaction, user-providable components are referenced by name only.

+

This means that a smart contract in Corda does two things:

+
  1. Define the data structures that compose the ledger (the states)

    +
  2. Define the rules for updating those structures

    +

The first is merely a utility role ... in theory contract code could manually parse byte streams by hand. +The second is vital to the integrity of the ledger. So this field needs to be able to express constraints like:

+
  • Only attachment 733c350f396a727655be1363c06635ba355036bd54a5ed6e594fd0b5d05f42f6 may be used with this state.

    +
  • Any attachment signed by public key 2d1ce0e330c52b8055258d776c40 may be used with this state.

    +
  • Attachments (1, 2, 3) may all be used with this state.

    +

and so on. In this way it becomes possible for the business logic governing a state to be evolved, if the +constraints are flexible enough.

+

Because contract classes often also define utilities that generate relevant transactions, and because attachments +cannot know their own hashes, we will have to provide various utilities to assist with obtaining the right +code constraints from within the contract code itself.

+

TODO: Implement the above description. See COR-226

+
+
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-multi-owner-state/index.html b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-multi-owner-state/index.html new file mode 100644 index 0000000000..992cfaf685 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-multi-owner-state/index.html @@ -0,0 +1,62 @@ + + +DummyContract.MultiOwnerState - + + + +com.r3corda.core.contracts / DummyContract / MultiOwnerState
+
+

MultiOwnerState

+data class MultiOwnerState : ContractState, State
+

Alternative state with multiple owners. This exists primarily to provide a dummy state with multiple +participants, and could in theory be merged with SingleOwnerState by putting the additional participants +in a different field, however this is a good example of a contract with multiple states.

+
+
+

Constructors

+ + + + + + + +
+<init> +MultiOwnerState(magicNumber: Int = 0, owners: List<PublicKey>)

Alternative state with multiple owners. This exists primarily to provide a dummy state with multiple +participants, and could in theory be merged with SingleOwnerState by putting the additional participants +in a different field, however this is a good example of a contract with multiple states.

+
+

Properties

+ + + + + + + + + + + + + + + + + + + +
+contract +val contract: DummyContract

An instance of the contract class that will verify this state.

+
+magicNumber +val magicNumber: Int
+owners +val owners: List<PublicKey>
+participants +val participants: List<PublicKey>

A participant is any party that is able to consume this state in a valid transaction.

+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-multi-owner-state/magic-number.html b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-multi-owner-state/magic-number.html new file mode 100644 index 0000000000..cfea75b093 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-multi-owner-state/magic-number.html @@ -0,0 +1,16 @@ + + +DummyContract.MultiOwnerState.magicNumber - + + + +com.r3corda.core.contracts / DummyContract / MultiOwnerState / magicNumber
+
+

magicNumber

+ +val magicNumber: Int
+Overrides State.magicNumber
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-multi-owner-state/owners.html b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-multi-owner-state/owners.html new file mode 100644 index 0000000000..f18d145d44 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-multi-owner-state/owners.html @@ -0,0 +1,15 @@ + + +DummyContract.MultiOwnerState.owners - + + + +com.r3corda.core.contracts / DummyContract / MultiOwnerState / owners
+
+

owners

+ +val owners: List<PublicKey>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-multi-owner-state/participants.html b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-multi-owner-state/participants.html new file mode 100644 index 0000000000..202d1c290a --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-multi-owner-state/participants.html @@ -0,0 +1,34 @@ + + +DummyContract.MultiOwnerState.participants - + + + +com.r3corda.core.contracts / DummyContract / MultiOwnerState / participants
+
+

participants

+ +val participants: List<PublicKey>
+Overrides ContractState.participants
+

A participant is any party that is able to consume this state in a valid transaction.

+

The list of participants is required for certain types of transactions. For example, when changing the notary +for this state (TransactionType.NotaryChange), every participants has to be involved and approve the transaction +so that they receive the updated state, and dont end up in a situation where they can no longer use a state +they possess, since someone consumed that state during the notary change process.

+

The participants list should normally be derived from the contents of the state. E.g. for Cash the participants +list should just contain the owner.

+
+
+

Getter
+

A participant is any party that is able to consume this state in a valid transaction.

+

The list of participants is required for certain types of transactions. For example, when changing the notary +for this state (TransactionType.NotaryChange), every participants has to be involved and approve the transaction +so that they receive the updated state, and dont end up in a situation where they can no longer use a state +they possess, since someone consumed that state during the notary change process.

+

The participants list should normally be derived from the contents of the state. E.g. for Cash the participants +list should just contain the owner.

+

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-single-owner-state/-init-.html b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-single-owner-state/-init-.html new file mode 100644 index 0000000000..0567f7f489 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-single-owner-state/-init-.html @@ -0,0 +1,14 @@ + + +DummyContract.SingleOwnerState.<init> - + + + +com.r3corda.core.contracts / DummyContract / SingleOwnerState / <init>
+
+

<init>

+SingleOwnerState(magicNumber: Int = 0, owner: PublicKey)
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-single-owner-state/contract.html b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-single-owner-state/contract.html new file mode 100644 index 0000000000..93e4007a60 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-single-owner-state/contract.html @@ -0,0 +1,43 @@ + + +DummyContract.SingleOwnerState.contract - + + + +com.r3corda.core.contracts / DummyContract / SingleOwnerState / contract
+
+

contract

+ +val contract: DummyContract
+Overrides ContractState.contract
+

An instance of the contract class that will verify this state.

+

Discussion

+

This field is not the final design, its just a piece of temporary scaffolding. Once the contract sandbox is +further along, this field will become a description of which attachments are acceptable for defining the +contract.

+

Recall that an attachment is a zip file that can be referenced from any transaction. The contents of the +attachments are merged together and cannot define any overlapping files, thus for any given transaction there +is a miniature file system in which each file can be precisely mapped to the defining attachment.

+

Attachments may contain many things (data files, legal documents, etc) but mostly they contain JVM bytecode. +The class files inside define not only Contract implementations but also the classes that define the states. +Within the rest of a transaction, user-providable components are referenced by name only.

+

This means that a smart contract in Corda does two things:

+
  1. Define the data structures that compose the ledger (the states)

    +
  2. Define the rules for updating those structures

    +

The first is merely a utility role ... in theory contract code could manually parse byte streams by hand. +The second is vital to the integrity of the ledger. So this field needs to be able to express constraints like:

+
  • Only attachment 733c350f396a727655be1363c06635ba355036bd54a5ed6e594fd0b5d05f42f6 may be used with this state.

    +
  • Any attachment signed by public key 2d1ce0e330c52b8055258d776c40 may be used with this state.

    +
  • Attachments (1, 2, 3) may all be used with this state.

    +

and so on. In this way it becomes possible for the business logic governing a state to be evolved, if the +constraints are flexible enough.

+

Because contract classes often also define utilities that generate relevant transactions, and because attachments +cannot know their own hashes, we will have to provide various utilities to assist with obtaining the right +code constraints from within the contract code itself.

+

TODO: Implement the above description. See COR-226

+
+
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-single-owner-state/index.html b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-single-owner-state/index.html new file mode 100644 index 0000000000..786b6ad714 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-single-owner-state/index.html @@ -0,0 +1,69 @@ + + +DummyContract.SingleOwnerState - + + + +com.r3corda.core.contracts / DummyContract / SingleOwnerState
+
+

SingleOwnerState

+data class SingleOwnerState : OwnableState, State
+
+
+

Constructors

+ + + + + + + +
+<init> +SingleOwnerState(magicNumber: Int = 0, owner: PublicKey)
+

Properties

+ + + + + + + + + + + + + + + + + + + +
+contract +val contract: DummyContract

An instance of the contract class that will verify this state.

+
+magicNumber +val magicNumber: Int
+owner +val owner: PublicKey

There must be a MoveCommand signed by this key to claim the amount

+
+participants +val participants: List<PublicKey>

A participant is any party that is able to consume this state in a valid transaction.

+
+

Functions

+ + + + + + + +
+withNewOwner +fun withNewOwner(newOwner: PublicKey): <ERROR CLASS>

Copies the underlying data structure, replacing the owner field with this new value and leaving the rest alone

+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-single-owner-state/magic-number.html b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-single-owner-state/magic-number.html new file mode 100644 index 0000000000..eec96bb510 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-single-owner-state/magic-number.html @@ -0,0 +1,16 @@ + + +DummyContract.SingleOwnerState.magicNumber - + + + +com.r3corda.core.contracts / DummyContract / SingleOwnerState / magicNumber
+
+

magicNumber

+ +val magicNumber: Int
+Overrides State.magicNumber
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-single-owner-state/owner.html b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-single-owner-state/owner.html new file mode 100644 index 0000000000..18fcc198a4 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-single-owner-state/owner.html @@ -0,0 +1,17 @@ + + +DummyContract.SingleOwnerState.owner - + + + +com.r3corda.core.contracts / DummyContract / SingleOwnerState / owner
+
+

owner

+ +val owner: PublicKey
+Overrides OwnableState.owner
+

There must be a MoveCommand signed by this key to claim the amount

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-single-owner-state/participants.html b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-single-owner-state/participants.html new file mode 100644 index 0000000000..6aa4a749ff --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-single-owner-state/participants.html @@ -0,0 +1,34 @@ + + +DummyContract.SingleOwnerState.participants - + + + +com.r3corda.core.contracts / DummyContract / SingleOwnerState / participants
+
+

participants

+ +val participants: List<PublicKey>
+Overrides ContractState.participants
+

A participant is any party that is able to consume this state in a valid transaction.

+

The list of participants is required for certain types of transactions. For example, when changing the notary +for this state (TransactionType.NotaryChange), every participants has to be involved and approve the transaction +so that they receive the updated state, and dont end up in a situation where they can no longer use a state +they possess, since someone consumed that state during the notary change process.

+

The participants list should normally be derived from the contents of the state. E.g. for Cash the participants +list should just contain the owner.

+
+
+

Getter
+

A participant is any party that is able to consume this state in a valid transaction.

+

The list of participants is required for certain types of transactions. For example, when changing the notary +for this state (TransactionType.NotaryChange), every participants has to be involved and approve the transaction +so that they receive the updated state, and dont end up in a situation where they can no longer use a state +they possess, since someone consumed that state during the notary change process.

+

The participants list should normally be derived from the contents of the state. E.g. for Cash the participants +list should just contain the owner.

+

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-single-owner-state/with-new-owner.html b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-single-owner-state/with-new-owner.html new file mode 100644 index 0000000000..02aa59fb8b --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-single-owner-state/with-new-owner.html @@ -0,0 +1,17 @@ + + +DummyContract.SingleOwnerState.withNewOwner - + + + +com.r3corda.core.contracts / DummyContract / SingleOwnerState / withNewOwner
+
+

withNewOwner

+ +fun withNewOwner(newOwner: PublicKey): <ERROR CLASS>
+Overrides OwnableState.withNewOwner
+

Copies the underlying data structure, replacing the owner field with this new value and leaving the rest alone

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-state/index.html b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-state/index.html index 7bc8c4b5b8..77c1761623 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-state/index.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-state/index.html @@ -7,44 +7,58 @@ com.r3corda.core.contracts / DummyContract / State

State

-class State : ContractState
+interface State : ContractState


-

Constructors

- - - - - - - -
-<init> -State(magicNumber: Int = 0, notary: Party)

Properties

- - - - +abstract val magicNumber: Int + + +
-contract -val contract: DummyContract

Contract by which the state belongs

-
magicNumber -val magicNumber: Int
+

Inherited Properties

+ + + + + +participants
+contract +abstract val contract: Contract

An instance of the contract class that will verify this state.

+
-notary -val notary: Party

Identity of the notary that ensures this state is not used as an input to a transaction more than once

+abstract val participants: List<PublicKey>

A participant is any party that is able to consume this state in a valid transaction.

+

Inheritors

+ + + + + + + + + + + +
+MultiOwnerState +data class MultiOwnerState : ContractState, State

Alternative state with multiple owners. This exists primarily to provide a dummy state with multiple +participants, and could in theory be merged with SingleOwnerState by putting the additional participants +in a different field, however this is a good example of a contract with multiple states.

+
+SingleOwnerState +data class SingleOwnerState : OwnableState, State
diff --git a/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-state/magic-number.html b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-state/magic-number.html index b7d5b7bde7..d7a05c8850 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-state/magic-number.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/-state/magic-number.html @@ -8,7 +8,7 @@

magicNumber

-val magicNumber: Int
+abstract val magicNumber: Int


diff --git a/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/index.html b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/index.html index e16c974ef7..707d589a3d 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/index.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/index.html @@ -21,9 +21,24 @@ +MultiOwnerState + +data class MultiOwnerState : ContractState, State

Alternative state with multiple owners. This exists primarily to provide a dummy state with multiple +participants, and could in theory be merged with SingleOwnerState by putting the additional participants +in a different field, however this is a good example of a contract with multiple states.

+ + + + +SingleOwnerState + +data class SingleOwnerState : OwnableState, State + + + State -class State : ContractState +interface State : ContractState @@ -64,7 +79,7 @@ the contracts contents).

verify -fun verify(tx: TransactionForVerification): Unit

Takes an object that represents a state transition, and ensures the inputs/outputs/commands make sense. +fun verify(tx: TransactionForContract): Unit

Takes an object that represents a state transition, and ensures the inputs/outputs/commands make sense. Must throw an exception if theres a problem that should prevent state transition. Takes a single object rather than an argument so that additional data can be added without breaking binary compatibility with existing contract code.

diff --git a/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/verify.html b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/verify.html index fe9cd0713b..744b53e2db 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/verify.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-dummy-contract/verify.html @@ -7,8 +7,8 @@ com.r3corda.core.contracts / DummyContract / verify

verify

- -fun verify(tx: TransactionForVerification): Unit
+ +fun verify(tx: TransactionForContract): Unit
Overrides Contract.verify

Takes an object that represents a state transition, and ensures the inputs/outputs/commands make sense. Must throw an exception if theres a problem that should prevent state transition. Takes a single object diff --git a/docs/build/html/api/com.r3corda.core.contracts/-dummy-state/-init-.html b/docs/build/html/api/com.r3corda.core.contracts/-dummy-state/-init-.html new file mode 100644 index 0000000000..9d914540ad --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-dummy-state/-init-.html @@ -0,0 +1,15 @@ + + +DummyState.<init> - + + + +com.r3corda.core.contracts / DummyState / <init>
+
+

<init>

+DummyState(magicNumber: Int = 0)
+

Dummy state for use in testing. Not part of any real contract.

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-dummy-state/contract.html b/docs/build/html/api/com.r3corda.core.contracts/-dummy-state/contract.html new file mode 100644 index 0000000000..c1b97983da --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-dummy-state/contract.html @@ -0,0 +1,43 @@ + + +DummyState.contract - + + + +com.r3corda.core.contracts / DummyState / contract
+
+

contract

+ +val contract: DummyContract
+Overrides ContractState.contract
+

An instance of the contract class that will verify this state.

+

Discussion

+

This field is not the final design, its just a piece of temporary scaffolding. Once the contract sandbox is +further along, this field will become a description of which attachments are acceptable for defining the +contract.

+

Recall that an attachment is a zip file that can be referenced from any transaction. The contents of the +attachments are merged together and cannot define any overlapping files, thus for any given transaction there +is a miniature file system in which each file can be precisely mapped to the defining attachment.

+

Attachments may contain many things (data files, legal documents, etc) but mostly they contain JVM bytecode. +The class files inside define not only Contract implementations but also the classes that define the states. +Within the rest of a transaction, user-providable components are referenced by name only.

+

This means that a smart contract in Corda does two things:

+
  1. Define the data structures that compose the ledger (the states)

    +
  2. Define the rules for updating those structures

    +

The first is merely a utility role ... in theory contract code could manually parse byte streams by hand. +The second is vital to the integrity of the ledger. So this field needs to be able to express constraints like:

+
  • Only attachment 733c350f396a727655be1363c06635ba355036bd54a5ed6e594fd0b5d05f42f6 may be used with this state.

    +
  • Any attachment signed by public key 2d1ce0e330c52b8055258d776c40 may be used with this state.

    +
  • Attachments (1, 2, 3) may all be used with this state.

    +

and so on. In this way it becomes possible for the business logic governing a state to be evolved, if the +constraints are flexible enough.

+

Because contract classes often also define utilities that generate relevant transactions, and because attachments +cannot know their own hashes, we will have to provide various utilities to assist with obtaining the right +code constraints from within the contract code itself.

+

TODO: Implement the above description. See COR-226

+
+
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-dummy-state/index.html b/docs/build/html/api/com.r3corda.core.contracts/-dummy-state/index.html new file mode 100644 index 0000000000..77dc38aeb6 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-dummy-state/index.html @@ -0,0 +1,70 @@ + + +DummyState - + + + +com.r3corda.core.contracts / DummyState
+
+

DummyState

+data class DummyState : ContractState
+

Dummy state for use in testing. Not part of any real contract.

+
+
+

Constructors

+ + + + + + + +
+<init> +DummyState(magicNumber: Int = 0)

Dummy state for use in testing. Not part of any real contract.

+
+

Properties

+ + + + + + + + + + + + + + + +
+contract +val contract: DummyContract

An instance of the contract class that will verify this state.

+
+magicNumber +val magicNumber: Int
+participants +val participants: List<PublicKey>

A participant is any party that is able to consume this state in a valid transaction.

+
+

Extension Functions

+ + + + + + + + + + + +
+hash +fun ContractState.hash(): SecureHash

Returns the SHA-256 hash of the serialised contents of this state (not cached)

+
+with notary +infix fun ContractState.with notary(notary: Party): TransactionState<ContractState>
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-dummy-state/magic-number.html b/docs/build/html/api/com.r3corda.core.contracts/-dummy-state/magic-number.html new file mode 100644 index 0000000000..024318b7e0 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-dummy-state/magic-number.html @@ -0,0 +1,15 @@ + + +DummyState.magicNumber - + + + +com.r3corda.core.contracts / DummyState / magicNumber
+
+

magicNumber

+ +val magicNumber: Int
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-dummy-state/participants.html b/docs/build/html/api/com.r3corda.core.contracts/-dummy-state/participants.html new file mode 100644 index 0000000000..4241d3c946 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-dummy-state/participants.html @@ -0,0 +1,34 @@ + + +DummyState.participants - + + + +com.r3corda.core.contracts / DummyState / participants
+
+

participants

+ +val participants: List<PublicKey>
+Overrides ContractState.participants
+

A participant is any party that is able to consume this state in a valid transaction.

+

The list of participants is required for certain types of transactions. For example, when changing the notary +for this state (TransactionType.NotaryChange), every participants has to be involved and approve the transaction +so that they receive the updated state, and dont end up in a situation where they can no longer use a state +they possess, since someone consumed that state during the notary change process.

+

The participants list should normally be derived from the contents of the state. E.g. for Cash the participants +list should just contain the owner.

+
+
+

Getter
+

A participant is any party that is able to consume this state in a valid transaction.

+

The list of participants is required for certain types of transactions. For example, when changing the notary +for this state (TransactionType.NotaryChange), every participants has to be involved and approve the transaction +so that they receive the updated state, and dont end up in a situation where they can no longer use a state +they possess, since someone consumed that state during the notary change process.

+

The participants list should normally be derived from the contents of the state. E.g. for Cash the participants +list should just contain the owner.

+

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-fixable-deal-state/generate-fix.html b/docs/build/html/api/com.r3corda.core.contracts/-fixable-deal-state/generate-fix.html index 8ab06e0b17..d2a9c9ceab 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-fixable-deal-state/generate-fix.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-fixable-deal-state/generate-fix.html @@ -7,8 +7,8 @@ com.r3corda.core.contracts / FixableDealState / generateFix

generateFix

- -abstract fun generateFix(ptx: TransactionBuilder, oldStateRef: StateRef, fix: Fix): Unit
+ +abstract fun generateFix(ptx: TransactionBuilder, oldState: StateAndRef<*>, fix: Fix): Unit

Generate a fixing command for this deal and fix

TODO: This would also likely move to methods on the Contract once the changes to reference the Contract from the ContractState are in

diff --git a/docs/build/html/api/com.r3corda.core.contracts/-fixable-deal-state/index.html b/docs/build/html/api/com.r3corda.core.contracts/-fixable-deal-state/index.html index 27dc826099..2ad6ee1f9d 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-fixable-deal-state/index.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-fixable-deal-state/index.html @@ -37,7 +37,7 @@ generateFix -abstract fun generateFix(ptx: TransactionBuilder, oldStateRef: StateRef, fix: Fix): Unit

Generate a fixing command for this deal and fix

+abstract fun generateFix(ptx: TransactionBuilder, oldState: StateAndRef<*>, fix: Fix): Unit

Generate a fixing command for this deal and fix

@@ -56,7 +56,7 @@ generateAgreement -abstract fun generateAgreement(): TransactionBuilder

Generate a partial transaction representing an agreement (command) to this deal, allowing a general +abstract fun generateAgreement(notary: Party): TransactionBuilder

Generate a partial transaction representing an agreement (command) to this deal, allowing a general deal/agreement protocol to generate the necessary transaction for potential implementations

@@ -80,9 +80,9 @@ deal/agreement protocol to generate the necessary transaction for potential impl -label +with notary -infix fun ContractState.label(label: String): LabeledOutput +infix fun ContractState.with notary(notary: Party): TransactionState<ContractState> @@ -93,7 +93,7 @@ deal/agreement protocol to generate the necessary transaction for potential impl State -data class State : FixableDealState

The state class contains the 4 major data classes

+data class State : FixableDealState, SchedulableState

The state class contains the 4 major data classes

diff --git a/docs/build/html/api/com.r3corda.core.contracts/-fixable-deal-state/next-fixing-of.html b/docs/build/html/api/com.r3corda.core.contracts/-fixable-deal-state/next-fixing-of.html index d0591aaaf3..0b27ea8c66 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-fixable-deal-state/next-fixing-of.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-fixable-deal-state/next-fixing-of.html @@ -10,9 +10,6 @@ abstract fun nextFixingOf(): FixOf?

When is the next fixing and what is the fixing for?

-

TODO: In future we would use this to register for an event to trigger a/the fixing protocol

-
-


diff --git a/docs/build/html/api/com.r3corda.core.contracts/-issuance-definition.html b/docs/build/html/api/com.r3corda.core.contracts/-issuance-definition.html index a595ee54d2..0d857c9478 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-issuance-definition.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-issuance-definition.html @@ -12,18 +12,5 @@ from which the state object is initialised.



-

Inheritors

- - - - - - - -
-AssetIssuanceDefinition -interface AssetIssuanceDefinition<T> : IssuanceDefinition

Subset of cash-like contract state, containing the issuance definition. If these definitions match for two -contracts states, those states can be aggregated.

-
diff --git a/docs/build/html/api/com.r3corda.core.contracts/-issue-command/index.html b/docs/build/html/api/com.r3corda.core.contracts/-issue-command/index.html new file mode 100644 index 0000000000..2d8504eb6e --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-issue-command/index.html @@ -0,0 +1,39 @@ + + +IssueCommand - + + + +com.r3corda.core.contracts / IssueCommand
+
+

IssueCommand

+interface IssueCommand : CommandData
+

A common issue command, to enforce that issue commands have a nonce value.

+
+
+

Properties

+ + + + + + + +
+nonce +abstract val nonce: Long
+

Inheritors

+ + + + + + + +
+Issue +interface Issue : IssueCommand, Commands

Allows new asset states to be issued into existence: the nonce ("number used once") ensures the transaction +has a unique ID even when there are no inputs.

+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-issue-command/nonce.html b/docs/build/html/api/com.r3corda.core.contracts/-issue-command/nonce.html new file mode 100644 index 0000000000..cce229d7fe --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-issue-command/nonce.html @@ -0,0 +1,15 @@ + + +IssueCommand.nonce - + + + +com.r3corda.core.contracts / IssueCommand / nonce
+
+

nonce

+ +abstract val nonce: Long
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-issued/-init-.html b/docs/build/html/api/com.r3corda.core.contracts/-issued/-init-.html new file mode 100644 index 0000000000..1d10e49dff --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-issued/-init-.html @@ -0,0 +1,19 @@ + + +Issued.<init> - + + + +com.r3corda.core.contracts / Issued / <init>
+
+

<init>

+Issued(issuer: PartyAndReference, product: P)
+

Definition for an issued product, which can be cash, a cash-like thing, assets, or generally anything else thats +quantifiable with integer quantities.

+

Parameters

+ +P - the type of product underlying the definition, for example Currency.
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-issued/index.html b/docs/build/html/api/com.r3corda.core.contracts/-issued/index.html new file mode 100644 index 0000000000..63db904130 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-issued/index.html @@ -0,0 +1,61 @@ + + +Issued - + + + +com.r3corda.core.contracts / Issued
+
+

Issued

+data class Issued<P>
+

Definition for an issued product, which can be cash, a cash-like thing, assets, or generally anything else thats +quantifiable with integer quantities.

+

Parameters

+ +P - the type of product underlying the definition, for example Currency.
+
+
+

Constructors

+ + + + + + + +
+<init> +Issued(issuer: PartyAndReference, product: P)

Definition for an issued product, which can be cash, a cash-like thing, assets, or generally anything else thats +quantifiable with integer quantities.

+
+

Properties

+ + + + + + + + + + + +
+issuer +val issuer: PartyAndReference
+product +val product: P
+

Extension Properties

+ + + + + + + +
+OBLIGATION_DEF +val Issued<Currency>.OBLIGATION_DEF: StateTemplate<Currency>

Allows you to write 100.DOLLARS.CASH

+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-issued/issuer.html b/docs/build/html/api/com.r3corda.core.contracts/-issued/issuer.html new file mode 100644 index 0000000000..c09a42e04d --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-issued/issuer.html @@ -0,0 +1,15 @@ + + +Issued.issuer - + + + +com.r3corda.core.contracts / Issued / issuer
+
+

issuer

+ +val issuer: PartyAndReference
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-issued/product.html b/docs/build/html/api/com.r3corda.core.contracts/-issued/product.html new file mode 100644 index 0000000000..3af736aebe --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-issued/product.html @@ -0,0 +1,15 @@ + + +Issued.product - + + + +com.r3corda.core.contracts / Issued / product
+
+

product

+ +val product: P
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-java-test-helpers/-c-h-f.html b/docs/build/html/api/com.r3corda.core.contracts/-java-test-helpers/-c-h-f.html new file mode 100644 index 0000000000..3b0247952d --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-java-test-helpers/-c-h-f.html @@ -0,0 +1,15 @@ + + +JavaTestHelpers.CHF - + + + +com.r3corda.core.contracts / JavaTestHelpers / CHF
+
+

CHF

+ +val CHF: Currency
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-java-test-helpers/-d-o-l-l-a-r-s.html b/docs/build/html/api/com.r3corda.core.contracts/-java-test-helpers/-d-o-l-l-a-r-s.html new file mode 100644 index 0000000000..3a554556b6 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-java-test-helpers/-d-o-l-l-a-r-s.html @@ -0,0 +1,17 @@ + + +JavaTestHelpers.DOLLARS - + + + +com.r3corda.core.contracts / JavaTestHelpers / DOLLARS
+
+

DOLLARS

+ +fun DOLLARS(amount: Int): Amount<Currency>
+ +fun DOLLARS(amount: Double): Amount<Currency>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-java-test-helpers/-g-b-p.html b/docs/build/html/api/com.r3corda.core.contracts/-java-test-helpers/-g-b-p.html new file mode 100644 index 0000000000..c58f8386f0 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-java-test-helpers/-g-b-p.html @@ -0,0 +1,15 @@ + + +JavaTestHelpers.GBP - + + + +com.r3corda.core.contracts / JavaTestHelpers / GBP
+
+

GBP

+ +val GBP: Currency
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-java-test-helpers/-p-o-u-n-d-s.html b/docs/build/html/api/com.r3corda.core.contracts/-java-test-helpers/-p-o-u-n-d-s.html new file mode 100644 index 0000000000..de743f0344 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-java-test-helpers/-p-o-u-n-d-s.html @@ -0,0 +1,15 @@ + + +JavaTestHelpers.POUNDS - + + + +com.r3corda.core.contracts / JavaTestHelpers / POUNDS
+
+

POUNDS

+ +fun POUNDS(amount: Int): Amount<Currency>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-java-test-helpers/-s-w-i-s-s_-f-r-a-n-c-s.html b/docs/build/html/api/com.r3corda.core.contracts/-java-test-helpers/-s-w-i-s-s_-f-r-a-n-c-s.html new file mode 100644 index 0000000000..f7386b8085 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-java-test-helpers/-s-w-i-s-s_-f-r-a-n-c-s.html @@ -0,0 +1,15 @@ + + +JavaTestHelpers.SWISS_FRANCS - + + + +com.r3corda.core.contracts / JavaTestHelpers / SWISS_FRANCS
+
+

SWISS_FRANCS

+ +fun SWISS_FRANCS(amount: Int): Amount<Currency>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-java-test-helpers/-u-s-d.html b/docs/build/html/api/com.r3corda.core.contracts/-java-test-helpers/-u-s-d.html new file mode 100644 index 0000000000..de201ece77 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-java-test-helpers/-u-s-d.html @@ -0,0 +1,15 @@ + + +JavaTestHelpers.USD - + + + +com.r3corda.core.contracts / JavaTestHelpers / USD
+
+

USD

+ +val USD: Currency
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-java-test-helpers/index.html b/docs/build/html/api/com.r3corda.core.contracts/-java-test-helpers/index.html new file mode 100644 index 0000000000..c17d7473a0 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-java-test-helpers/index.html @@ -0,0 +1,68 @@ + + +JavaTestHelpers - + + + +com.r3corda.core.contracts / JavaTestHelpers
+
+

JavaTestHelpers

+object JavaTestHelpers
+
+
+

Properties

+ + + + + + + + + + + + + + + +
+CHF +val CHF: Currency
+GBP +val GBP: Currency
+USD +val USD: Currency
+

Functions

+ + + + + + + + + + + + + + + + + + + +
+DOLLARS +fun DOLLARS(amount: Int): Amount<Currency>
+fun DOLLARS(amount: Double): Amount<Currency>
+POUNDS +fun POUNDS(amount: Int): Amount<Currency>
+SWISS_FRANCS +fun SWISS_FRANCS(amount: Int): Amount<Currency>
+issuedBy +fun issuedBy(currency: Currency, deposit: PartyAndReference): Issued<Currency>
+fun issuedBy(amount: Amount<Currency>, deposit: PartyAndReference): Amount<Issued<Currency>>
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-java-test-helpers/issued-by.html b/docs/build/html/api/com.r3corda.core.contracts/-java-test-helpers/issued-by.html new file mode 100644 index 0000000000..1293a9d956 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-java-test-helpers/issued-by.html @@ -0,0 +1,17 @@ + + +JavaTestHelpers.issuedBy - + + + +com.r3corda.core.contracts / JavaTestHelpers / issuedBy
+
+

issuedBy

+ +fun issuedBy(currency: Currency, deposit: PartyAndReference): Issued<Currency>
+ +fun issuedBy(amount: Amount<Currency>, deposit: PartyAndReference): Amount<Issued<Currency>>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-ledger-transaction/-init-.html b/docs/build/html/api/com.r3corda.core.contracts/-ledger-transaction/-init-.html index e04a3a7d77..b43c213d2a 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-ledger-transaction/-init-.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-ledger-transaction/-init-.html @@ -7,7 +7,7 @@ com.r3corda.core.contracts / LedgerTransaction / <init>

<init>

-LedgerTransaction(inputs: List<StateRef>, attachments: List<Attachment>, outputs: List<ContractState>, commands: List<AuthenticatedObject<CommandData>>, id: SecureHash)
+LedgerTransaction(inputs: List<StateRef>, outputs: List<TransactionState<*>>, commands: List<AuthenticatedObject<CommandData>>, attachments: List<Attachment>, id: SecureHash, signers: List<PublicKey>, type: TransactionType)

A LedgerTransaction wraps the data needed to calculate one or more successor states from a set of input states. It is the first step after extraction from a WireTransaction. The signatures at this point have been lined up with the commands from the wire, and verified/looked up.

diff --git a/docs/build/html/api/com.r3corda.core.contracts/-ledger-transaction/index.html b/docs/build/html/api/com.r3corda.core.contracts/-ledger-transaction/index.html index 871775a400..66319c54e7 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-ledger-transaction/index.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-ledger-transaction/index.html @@ -23,7 +23,7 @@ with the commands from the wire, and verified/looked up.

<init> -LedgerTransaction(inputs: List<StateRef>, attachments: List<Attachment>, outputs: List<ContractState>, commands: List<AuthenticatedObject<CommandData>>, id: SecureHash)

A LedgerTransaction wraps the data needed to calculate one or more successor states from a set of input states. +LedgerTransaction(inputs: List<StateRef>, outputs: List<TransactionState<*>>, commands: List<AuthenticatedObject<CommandData>>, attachments: List<Attachment>, id: SecureHash, signers: List<PublicKey>, type: TransactionType)

A LedgerTransaction wraps the data needed to calculate one or more successor states from a set of input states. It is the first step after extraction from a WireTransaction. The signatures at this point have been lined up with the commands from the wire, and verified/looked up.

@@ -65,9 +65,21 @@ with the commands from the wire, and verified/looked up.

outputs -val outputs: List<ContractState>

The states that will be generated by the execution of this transaction.

+val outputs: List<TransactionState<*>>

The states that will be generated by the execution of this transaction.

+ + +signers + +val signers: List<PublicKey> + + + +type + +val type: TransactionType +

Functions

diff --git a/docs/build/html/api/com.r3corda.core.contracts/-ledger-transaction/outputs.html b/docs/build/html/api/com.r3corda.core.contracts/-ledger-transaction/outputs.html index 01a46ad49e..8b5138d562 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-ledger-transaction/outputs.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-ledger-transaction/outputs.html @@ -8,7 +8,7 @@

outputs

-val outputs: List<ContractState>
+val outputs: List<TransactionState<*>>

The states that will be generated by the execution of this transaction.



diff --git a/docs/build/html/api/com.r3corda.core.contracts/-ledger-transaction/signers.html b/docs/build/html/api/com.r3corda.core.contracts/-ledger-transaction/signers.html new file mode 100644 index 0000000000..a642a4a5b2 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-ledger-transaction/signers.html @@ -0,0 +1,15 @@ + + +LedgerTransaction.signers - + + + +com.r3corda.core.contracts / LedgerTransaction / signers
+
+

signers

+ +val signers: List<PublicKey>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-ledger-transaction/type.html b/docs/build/html/api/com.r3corda.core.contracts/-ledger-transaction/type.html new file mode 100644 index 0000000000..c2bc0b4cea --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-ledger-transaction/type.html @@ -0,0 +1,15 @@ + + +LedgerTransaction.type - + + + +com.r3corda.core.contracts / LedgerTransaction / type
+
+

type

+ +val type: TransactionType
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-linear-state/index.html b/docs/build/html/api/com.r3corda.core.contracts/-linear-state/index.html index f09912513b..abc8dfb712 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-linear-state/index.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-linear-state/index.html @@ -33,14 +33,14 @@ contract -abstract val contract: Contract

Contract by which the state belongs

+abstract val contract: Contract

An instance of the contract class that will verify this state.

-notary +participants -abstract val notary: Party

Identity of the notary that ensures this state is not used as an input to a transaction more than once

+abstract val participants: List<PublicKey>

A participant is any party that is able to consume this state in a valid transaction.

@@ -69,9 +69,9 @@ -label +with notary -infix fun ContractState.label(label: String): LabeledOutput +infix fun ContractState.with notary(notary: Party): TransactionState<ContractState> @@ -86,6 +86,12 @@ implementation of general protocols that manipulate many agreement types.

+ + +DummyLinearState + +class DummyLinearState : LinearState + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-move-command/contract-hash.html b/docs/build/html/api/com.r3corda.core.contracts/-move-command/contract-hash.html new file mode 100644 index 0000000000..ea6950577f --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-move-command/contract-hash.html @@ -0,0 +1,17 @@ + + +MoveCommand.contractHash - + + + +com.r3corda.core.contracts / MoveCommand / contractHash
+
+

contractHash

+ +abstract val contractHash: SecureHash?
+

Contract code the moved state(s) are for the attention of, for example to indicate that the states are moved in +order to settle an obligation contracts state object(s).

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-move-command/index.html b/docs/build/html/api/com.r3corda.core.contracts/-move-command/index.html new file mode 100644 index 0000000000..ece58372ea --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-move-command/index.html @@ -0,0 +1,46 @@ + + +MoveCommand - + + + +com.r3corda.core.contracts / MoveCommand
+
+

MoveCommand

+interface MoveCommand : CommandData
+

A common move command for contracts which can change owner.

+
+
+

Properties

+ + + + + + + +
+contractHash +abstract val contractHash: SecureHash?

Contract code the moved state(s) are for the attention of, for example to indicate that the states are moved in +order to settle an obligation contracts state object(s).

+
+

Inheritors

+ + + + + + + + + + + +
+Move +interface Move : MoveCommand, Commands
+Move +data class Move<P> : Commands, IssuanceCommands<P>, MoveCommand

A command stating that a debt has been moved, optionally to fulfil another contract.

+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-net-type/-c-l-o-s-e_-o-u-t.html b/docs/build/html/api/com.r3corda.core.contracts/-net-type/-c-l-o-s-e_-o-u-t.html new file mode 100644 index 0000000000..b1c11c7347 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-net-type/-c-l-o-s-e_-o-u-t.html @@ -0,0 +1,20 @@ + + +NetType.CLOSE_OUT - + + + +com.r3corda.core.contracts / NetType / CLOSE_OUT
+
+

CLOSE_OUT

+CLOSE_OUT
+

Close-out netting applies where one party is bankrupt or otherwise defaults (exact terms are contract specific), +and allows their counterparty to net obligations without requiring approval from all parties. For example, if +Bank A owes Bank B £1m, and Bank B owes Bank A £1m, in the case of Bank B defaulting this would enable Bank A +to net out the two obligations to zero, rather than being legally obliged to pay £1m without any realistic +expectation of the debt to them being paid. Realistically this is limited to bilateral netting, to simplify +determining which party must sign the netting transaction.

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-net-type/-p-a-y-m-e-n-t.html b/docs/build/html/api/com.r3corda.core.contracts/-net-type/-p-a-y-m-e-n-t.html new file mode 100644 index 0000000000..8d18b3c036 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-net-type/-p-a-y-m-e-n-t.html @@ -0,0 +1,16 @@ + + +NetType.PAYMENT - + + + +com.r3corda.core.contracts / NetType / PAYMENT
+
+

PAYMENT

+PAYMENT
+

"Payment" is used to refer to conventional netting, where all parties must confirm the netting transaction. This +can be a multilateral netting transaction, and may be created by a central clearing service.

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-net-type/index.html b/docs/build/html/api/com.r3corda.core.contracts/-net-type/index.html new file mode 100644 index 0000000000..54d9adf316 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-net-type/index.html @@ -0,0 +1,41 @@ + + +NetType - + + + +com.r3corda.core.contracts / NetType
+
+

NetType

+enum class NetType
+

Enum for the types of netting that can be applied to state objects. Exact behaviour +for each type of netting is left to the contract to determine.

+
+
+

Enum Values

+ + + + + + + + + + + +
+CLOSE_OUT +

Close-out netting applies where one party is bankrupt or otherwise defaults (exact terms are contract specific), +and allows their counterparty to net obligations without requiring approval from all parties. For example, if +Bank A owes Bank B £1m, and Bank B owes Bank A £1m, in the case of Bank B defaulting this would enable Bank A +to net out the two obligations to zero, rather than being legally obliged to pay £1m without any realistic +expectation of the debt to them being paid. Realistically this is limited to bilateral netting, to simplify +determining which party must sign the netting transaction.

+
+PAYMENT +

"Payment" is used to refer to conventional netting, where all parties must confirm the netting transaction. This +can be a multilateral netting transaction, and may be created by a central clearing service.

+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-ownable-state/index.html b/docs/build/html/api/com.r3corda.core.contracts/-ownable-state/index.html index f55cc49182..ba3ea8edf3 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-ownable-state/index.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-ownable-state/index.html @@ -30,14 +30,14 @@ contract -abstract val contract: Contract

Contract by which the state belongs

+abstract val contract: Contract

An instance of the contract class that will verify this state.

-notary +participants -abstract val notary: Party

Identity of the notary that ensures this state is not used as an input to a transaction more than once

+abstract val participants: List<PublicKey>

A participant is any party that is able to consume this state in a valid transaction.

@@ -66,9 +66,9 @@ -label +with notary -infix fun ContractState.label(label: String): LabeledOutput +infix fun ContractState.with notary(notary: Party): TransactionState<ContractState> @@ -77,13 +77,19 @@ -FungibleAssetState +FungibleAssetState -interface FungibleAssetState<T, I : AssetIssuanceDefinition<T>> : OwnableState

Common elements of cash contract states.

+interface FungibleAssetState<T, I> : OwnableState

Common elements of cash contract states.

+SingleOwnerState + +data class SingleOwnerState : OwnableState, State + + + State data class State : OwnableState diff --git a/docs/build/html/api/com.r3corda.core.contracts/-schedulable-state/index.html b/docs/build/html/api/com.r3corda.core.contracts/-schedulable-state/index.html new file mode 100644 index 0000000000..6447cb547f --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-schedulable-state/index.html @@ -0,0 +1,77 @@ + + +SchedulableState - + + + +com.r3corda.core.contracts / SchedulableState
+
+

SchedulableState

+interface SchedulableState : ContractState
+
+
+

Inherited Properties

+ + + + + + + + + + + +
+contract +abstract val contract: Contract

An instance of the contract class that will verify this state.

+
+participants +abstract val participants: List<PublicKey>

A participant is any party that is able to consume this state in a valid transaction.

+
+

Functions

+ + + + + + + +
+nextScheduledActivity +abstract fun nextScheduledActivity(thisStateRef: StateRef, protocolLogicRefFactory: ProtocolLogicRefFactory): ScheduledActivity?

Indicate whether there is some activity to be performed at some future point in time with respect to this +ContractState, what that activity is and at what point in time it should be initiated. +This can be used to implement deadlines for payment or processing of financial instruments according to a schedule.

+
+

Extension Functions

+ + + + + + + + + + + +
+hash +fun ContractState.hash(): SecureHash

Returns the SHA-256 hash of the serialised contents of this state (not cached)

+
+with notary +infix fun ContractState.with notary(notary: Party): TransactionState<ContractState>
+

Inheritors

+ + + + + + + +
+State +data class State : FixableDealState, SchedulableState

The state class contains the 4 major data classes

+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-schedulable-state/next-scheduled-activity.html b/docs/build/html/api/com.r3corda.core.contracts/-schedulable-state/next-scheduled-activity.html new file mode 100644 index 0000000000..7afd1dc545 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-schedulable-state/next-scheduled-activity.html @@ -0,0 +1,23 @@ + + +SchedulableState.nextScheduledActivity - + + + +com.r3corda.core.contracts / SchedulableState / nextScheduledActivity
+
+

nextScheduledActivity

+ +abstract fun nextScheduledActivity(thisStateRef: StateRef, protocolLogicRefFactory: ProtocolLogicRefFactory): ScheduledActivity?
+

Indicate whether there is some activity to be performed at some future point in time with respect to this +ContractState, what that activity is and at what point in time it should be initiated. +This can be used to implement deadlines for payment or processing of financial instruments according to a schedule.

+

The state has no reference to its own StateRef, so supply that for use as input to any ProtocolLogic constructed.

+
+
+

Return
+null if there is no activity to schedule

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-scheduled-activity/-init-.html b/docs/build/html/api/com.r3corda.core.contracts/-scheduled-activity/-init-.html new file mode 100644 index 0000000000..604f267215 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-scheduled-activity/-init-.html @@ -0,0 +1,23 @@ + + +ScheduledActivity.<init> - + + + +com.r3corda.core.contracts / ScheduledActivity / <init>
+
+

<init>

+ScheduledActivity(logicRef: ProtocolLogicRef, scheduledAt: Instant)
+

This class represents the lifecycle activity that a contract state of type LinearState would like to perform at a given point in time. +e.g. run a fixing protocol

+

Note the use of ProtocolLogicRef to represent a safe way to transport a ProtocolLogic out of the contract sandbox.

+

Currently we support only protocol based activities as we expect there to be a transaction generated off the back of +the activity, otherwise we have to start tracking secondary state on the platform of which scheduled activities +for a particular ContractState have been processed/fired etc. If the activity is not "on ledger" then the +scheduled activity shouldnt be either.

+
+
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-scheduled-activity/index.html b/docs/build/html/api/com.r3corda.core.contracts/-scheduled-activity/index.html new file mode 100644 index 0000000000..e7d1e45b83 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-scheduled-activity/index.html @@ -0,0 +1,53 @@ + + +ScheduledActivity - + + + +com.r3corda.core.contracts / ScheduledActivity
+
+

ScheduledActivity

+data class ScheduledActivity : Scheduled
+

This class represents the lifecycle activity that a contract state of type LinearState would like to perform at a given point in time. +e.g. run a fixing protocol

+

Note the use of ProtocolLogicRef to represent a safe way to transport a ProtocolLogic out of the contract sandbox.

+

Currently we support only protocol based activities as we expect there to be a transaction generated off the back of +the activity, otherwise we have to start tracking secondary state on the platform of which scheduled activities +for a particular ContractState have been processed/fired etc. If the activity is not "on ledger" then the +scheduled activity shouldnt be either.

+
+
+
+
+

Constructors

+ + + + + + + +
+<init> +ScheduledActivity(logicRef: ProtocolLogicRef, scheduledAt: Instant)

This class represents the lifecycle activity that a contract state of type LinearState would like to perform at a given point in time. +e.g. run a fixing protocol

+
+

Properties

+ + + + + + + + + + + +
+logicRef +val logicRef: ProtocolLogicRef
+scheduledAt +val scheduledAt: Instant
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-scheduled-activity/logic-ref.html b/docs/build/html/api/com.r3corda.core.contracts/-scheduled-activity/logic-ref.html new file mode 100644 index 0000000000..32742e0116 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-scheduled-activity/logic-ref.html @@ -0,0 +1,15 @@ + + +ScheduledActivity.logicRef - + + + +com.r3corda.core.contracts / ScheduledActivity / logicRef
+
+

logicRef

+ +val logicRef: ProtocolLogicRef
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-scheduled-activity/scheduled-at.html b/docs/build/html/api/com.r3corda.core.contracts/-scheduled-activity/scheduled-at.html new file mode 100644 index 0000000000..be021fba3f --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-scheduled-activity/scheduled-at.html @@ -0,0 +1,16 @@ + + +ScheduledActivity.scheduledAt - + + + +com.r3corda.core.contracts / ScheduledActivity / scheduledAt
+
+

scheduledAt

+ +val scheduledAt: Instant
+Overrides Scheduled.scheduledAt
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-scheduled-state-ref/-init-.html b/docs/build/html/api/com.r3corda.core.contracts/-scheduled-state-ref/-init-.html new file mode 100644 index 0000000000..59f1ad274c --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-scheduled-state-ref/-init-.html @@ -0,0 +1,20 @@ + + +ScheduledStateRef.<init> - + + + +com.r3corda.core.contracts / ScheduledStateRef / <init>
+
+

<init>

+ScheduledStateRef(ref: StateRef, scheduledAt: Instant)
+

Represents a contract state (unconsumed output) of type LinearState and a point in time that a lifecycle event is expected to take place +for that contract state.

+

This is effectively the input to a scheduler, which wakes up at that point in time and asks the contract state what +lifecycle processing needs to take place. e.g. a fixing or a late payment etc.

+
+
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-scheduled-state-ref/index.html b/docs/build/html/api/com.r3corda.core.contracts/-scheduled-state-ref/index.html new file mode 100644 index 0000000000..4a4df2e7c2 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-scheduled-state-ref/index.html @@ -0,0 +1,50 @@ + + +ScheduledStateRef - + + + +com.r3corda.core.contracts / ScheduledStateRef
+
+

ScheduledStateRef

+data class ScheduledStateRef : Scheduled
+

Represents a contract state (unconsumed output) of type LinearState and a point in time that a lifecycle event is expected to take place +for that contract state.

+

This is effectively the input to a scheduler, which wakes up at that point in time and asks the contract state what +lifecycle processing needs to take place. e.g. a fixing or a late payment etc.

+
+
+
+
+

Constructors

+ + + + + + + +
+<init> +ScheduledStateRef(ref: StateRef, scheduledAt: Instant)

Represents a contract state (unconsumed output) of type LinearState and a point in time that a lifecycle event is expected to take place +for that contract state.

+
+

Properties

+ + + + + + + + + + + +
+ref +val ref: StateRef
+scheduledAt +val scheduledAt: Instant
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-scheduled-state-ref/ref.html b/docs/build/html/api/com.r3corda.core.contracts/-scheduled-state-ref/ref.html new file mode 100644 index 0000000000..5f2c7932f3 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-scheduled-state-ref/ref.html @@ -0,0 +1,15 @@ + + +ScheduledStateRef.ref - + + + +com.r3corda.core.contracts / ScheduledStateRef / ref
+
+

ref

+ +val ref: StateRef
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-scheduled-state-ref/scheduled-at.html b/docs/build/html/api/com.r3corda.core.contracts/-scheduled-state-ref/scheduled-at.html new file mode 100644 index 0000000000..8680d93656 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-scheduled-state-ref/scheduled-at.html @@ -0,0 +1,16 @@ + + +ScheduledStateRef.scheduledAt - + + + +com.r3corda.core.contracts / ScheduledStateRef / scheduledAt
+
+

scheduledAt

+ +val scheduledAt: Instant
+Overrides Scheduled.scheduledAt
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-scheduled/index.html b/docs/build/html/api/com.r3corda.core.contracts/-scheduled/index.html new file mode 100644 index 0000000000..66a480fa8d --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-scheduled/index.html @@ -0,0 +1,47 @@ + + +Scheduled - + + + +com.r3corda.core.contracts / Scheduled
+
+

Scheduled

+interface Scheduled
+

Something which is scheduled to happen at a point in time

+
+
+

Properties

+ + + + + + + +
+scheduledAt +abstract val scheduledAt: Instant
+

Inheritors

+ + + + + + + + + + + +
+ScheduledActivity +data class ScheduledActivity : Scheduled

This class represents the lifecycle activity that a contract state of type LinearState would like to perform at a given point in time. +e.g. run a fixing protocol

+
+ScheduledStateRef +data class ScheduledStateRef : Scheduled

Represents a contract state (unconsumed output) of type LinearState and a point in time that a lifecycle event is expected to take place +for that contract state.

+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-scheduled/scheduled-at.html b/docs/build/html/api/com.r3corda.core.contracts/-scheduled/scheduled-at.html new file mode 100644 index 0000000000..cbe74a1e93 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-scheduled/scheduled-at.html @@ -0,0 +1,15 @@ + + +Scheduled.scheduledAt - + + + +com.r3corda.core.contracts / Scheduled / scheduledAt
+
+

scheduledAt

+ +abstract val scheduledAt: Instant
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-signed-transaction/get-missing-signatures.html b/docs/build/html/api/com.r3corda.core.contracts/-signed-transaction/get-missing-signatures.html index 90f1758b92..0c043b0153 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-signed-transaction/get-missing-signatures.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-signed-transaction/get-missing-signatures.html @@ -9,8 +9,7 @@

getMissingSignatures

fun getMissingSignatures(): Set<PublicKey>
-

Returns the set of missing signatures - a signature must be present for every command pub key -and the Notary (if it is specified)

+

Returns the set of missing signatures - a signature must be present for each signer public key



diff --git a/docs/build/html/api/com.r3corda.core.contracts/-signed-transaction/index.html b/docs/build/html/api/com.r3corda.core.contracts/-signed-transaction/index.html index dfccafff93..4d11ec7b27 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-signed-transaction/index.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-signed-transaction/index.html @@ -61,8 +61,7 @@ getMissingSignatures -fun getMissingSignatures(): Set<PublicKey>

Returns the set of missing signatures - a signature must be present for every command pub key -and the Notary (if it is specified)

+fun getMissingSignatures(): Set<PublicKey>

Returns the set of missing signatures - a signature must be present for each signer public key

@@ -70,14 +69,14 @@ and the Notary (if it is specified)

plus operator fun plus(sig: WithKey): SignedTransaction

Alias for withAdditionalSignature to let you use Kotlin operator overloading.

- +operator fun plus(sigList: Collection<WithKey>): SignedTransaction verify fun verify(throwIfSignaturesAreMissing: Boolean = true): Set<PublicKey>

Verify the signatures, deserialise the wire transaction and then check that the set of signatures found contains -the set of pubkeys in the commands. If any signatures are missing, either throws an exception (by default) or +the set of pubkeys in the signers list. If any signatures are missing, either throws an exception (by default) or returns the list of keys that have missing signatures, depending on the parameter.

@@ -97,6 +96,12 @@ checking a partially signed transaction being prepared by multiple co-operating fun withAdditionalSignature(sig: WithKey): SignedTransaction

Returns the same transaction but with an additional (unchecked) signature

+ + +withAdditionalSignatures + +fun withAdditionalSignatures(sigList: Iterable<WithKey>): SignedTransaction +

Extension Functions

diff --git a/docs/build/html/api/com.r3corda.core.contracts/-signed-transaction/plus.html b/docs/build/html/api/com.r3corda.core.contracts/-signed-transaction/plus.html index c450cf561e..d8e3ac543a 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-signed-transaction/plus.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-signed-transaction/plus.html @@ -12,5 +12,9 @@

Alias for withAdditionalSignature to let you use Kotlin operator overloading.



+ +operator fun plus(sigList: Collection<WithKey>): SignedTransaction
+
+
diff --git a/docs/build/html/api/com.r3corda.core.contracts/-signed-transaction/tx.html b/docs/build/html/api/com.r3corda.core.contracts/-signed-transaction/tx.html index 4b97256695..b2e2811d52 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-signed-transaction/tx.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-signed-transaction/tx.html @@ -10,9 +10,9 @@ val tx: WireTransaction

Lazily calculated access to the deserialised/hashed transaction data.

-Getter
+

Getter

Lazily calculated access to the deserialised/hashed transaction data.

-
+



diff --git a/docs/build/html/api/com.r3corda.core.contracts/-signed-transaction/verify.html b/docs/build/html/api/com.r3corda.core.contracts/-signed-transaction/verify.html index c7caf39669..a2e9064ac6 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-signed-transaction/verify.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-signed-transaction/verify.html @@ -10,7 +10,7 @@ fun verify(throwIfSignaturesAreMissing: Boolean = true): Set<PublicKey>

Verify the signatures, deserialise the wire transaction and then check that the set of signatures found contains -the set of pubkeys in the commands. If any signatures are missing, either throws an exception (by default) or +the set of pubkeys in the signers list. If any signatures are missing, either throws an exception (by default) or returns the list of keys that have missing signatures, depending on the parameter.

Exceptions

diff --git a/docs/build/html/api/com.r3corda.core.contracts/-signed-transaction/with-additional-signatures.html b/docs/build/html/api/com.r3corda.core.contracts/-signed-transaction/with-additional-signatures.html new file mode 100644 index 0000000000..32618083f0 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-signed-transaction/with-additional-signatures.html @@ -0,0 +1,15 @@ + + +SignedTransaction.withAdditionalSignatures - + + + +com.r3corda.core.contracts / SignedTransaction / withAdditionalSignatures
+
+

withAdditionalSignatures

+ +fun withAdditionalSignatures(sigList: Iterable<WithKey>): SignedTransaction
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-state-and-ref/-init-.html b/docs/build/html/api/com.r3corda.core.contracts/-state-and-ref/-init-.html index 3e25b05185..f247f2f7c4 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-state-and-ref/-init-.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-state-and-ref/-init-.html @@ -7,7 +7,7 @@ com.r3corda.core.contracts / StateAndRef / <init>

<init>

-StateAndRef(state: T, ref: StateRef)
+StateAndRef(state: TransactionState<T>, ref: StateRef)

A StateAndRef is simply a (state, ref) pair. For instance, a wallet (which holds available assets) contains these.



diff --git a/docs/build/html/api/com.r3corda.core.contracts/-state-and-ref/index.html b/docs/build/html/api/com.r3corda.core.contracts/-state-and-ref/index.html index ef748018a2..e02e74e348 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-state-and-ref/index.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-state-and-ref/index.html @@ -18,7 +18,7 @@ <init> -StateAndRef(state: T, ref: StateRef)

A StateAndRef is simply a (state, ref) pair. For instance, a wallet (which holds available assets) contains these.

+StateAndRef(state: TransactionState<T>, ref: StateRef)

A StateAndRef is simply a (state, ref) pair. For instance, a wallet (which holds available assets) contains these.

@@ -36,7 +36,7 @@ state -val state: T +val state: TransactionState<T> diff --git a/docs/build/html/api/com.r3corda.core.contracts/-state-and-ref/state.html b/docs/build/html/api/com.r3corda.core.contracts/-state-and-ref/state.html index 3d6a1637d9..1518f2e0b3 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-state-and-ref/state.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-state-and-ref/state.html @@ -8,7 +8,7 @@

state

-val state: T
+val state: TransactionState<T>


diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/-init-.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/-init-.html index 7ef194a8f8..1e4803e179 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/-init-.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/-init-.html @@ -7,11 +7,19 @@ com.r3corda.core.contracts / TransactionBuilder / <init>

<init>

-TransactionBuilder(inputs: MutableList<StateRef> = arrayListOf(), attachments: MutableList<SecureHash> = arrayListOf(), outputs: MutableList<ContractState> = arrayListOf(), commands: MutableList<Command> = arrayListOf())
+TransactionBuilder(type: TransactionType = TransactionType.General(), notary: Party? = null)

A TransactionBuilder is a transaction class thats mutable (unlike the others which are all immutable). It is -intended to be passed around contracts that may edit it by adding new states/commands or modifying the existing set. -Then once the states and commands are right, this class can be used as a holding bucket to gather signatures from -multiple parties.

+intended to be passed around contracts 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.

+

The builder can be customised for specific transaction types, e.g. where additional processing is needed +before adding a state/command.

+
+
+

Parameters

+ +notary - The default notary that will be used for outputs that dont have a notary specified. When this is set, +an output state can be added by just passing in a ContractState – a TransactionState with the +default notary will be generated automatically.


diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/add-input-state.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/add-input-state.html index 7e4d4e16de..7196d6a1d4 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/add-input-state.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/add-input-state.html @@ -7,8 +7,8 @@ com.r3corda.core.contracts / TransactionBuilder / addInputState

addInputState

- -fun addInputState(ref: StateRef): Unit
+ +open fun addInputState(stateAndRef: StateAndRef<*>): Unit


diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/add-output-state.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/add-output-state.html index 36e9cd001b..14e1ef2f1c 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/add-output-state.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/add-output-state.html @@ -7,8 +7,15 @@ com.r3corda.core.contracts / TransactionBuilder / addOutputState

addOutputState

+ +fun addOutputState(state: TransactionState<*>): Unit
+ +fun addOutputState(state: ContractState, notary: Party): Unit
+
+
fun addOutputState(state: ContractState): Unit
+

A default notary must be specified during builder construction to use this method



diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/attachments.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/attachments.html index 62c96d769f..03f7b1559e 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/attachments.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/attachments.html @@ -7,6 +7,8 @@ com.r3corda.core.contracts / TransactionBuilder / attachments

attachments

+ +protected val attachments: MutableList<SecureHash>
fun attachments(): List<SecureHash>

diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/commands.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/commands.html index 436ed87251..eeed2f65d1 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/commands.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/commands.html @@ -7,6 +7,8 @@ com.r3corda.core.contracts / TransactionBuilder / commands

commands

+ +protected val commands: MutableList<Command>
fun commands(): List<Command>

diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/current-sigs.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/current-sigs.html new file mode 100644 index 0000000000..fe2ffdc034 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/current-sigs.html @@ -0,0 +1,16 @@ + + +TransactionBuilder.currentSigs - + + + +com.r3corda.core.contracts / TransactionBuilder / currentSigs
+
+

currentSigs

+ +protected val currentSigs: <ERROR CLASS>
+

The signatures that have been collected so far - might be incomplete

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/index.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/index.html index 4039741152..7b5f97a21f 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/index.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/index.html @@ -7,11 +7,19 @@ com.r3corda.core.contracts / TransactionBuilder

TransactionBuilder

-class TransactionBuilder
+abstract class TransactionBuilder

A TransactionBuilder is a transaction class thats mutable (unlike the others which are all immutable). It is -intended to be passed around contracts that may edit it by adding new states/commands or modifying the existing set. -Then once the states and commands are right, this class can be used as a holding bucket to gather signatures from -multiple parties.

+intended to be passed around contracts 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.

+

The builder can be customised for specific transaction types, e.g. where additional processing is needed +before adding a state/command.

+
+
+

Parameters

+ +notary - The default notary that will be used for outputs that dont have a notary specified. When this is set, +an output state can be added by just passing in a ContractState – a TransactionState with the +default notary will be generated automatically.


Constructors

@@ -21,10 +29,9 @@ multiple parties.

<init> -TransactionBuilder(inputs: MutableList<StateRef> = arrayListOf(), attachments: MutableList<SecureHash> = arrayListOf(), outputs: MutableList<ContractState> = arrayListOf(), commands: MutableList<Command> = arrayListOf())

A TransactionBuilder is a transaction class thats mutable (unlike the others which are all immutable). It is -intended to be passed around contracts that may edit it by adding new states/commands or modifying the existing set. -Then once the states and commands are right, this class can be used as a holding bucket to gather signatures from -multiple parties.

+TransactionBuilder(type: TransactionType = TransactionType.General(), notary: Party? = null)

A TransactionBuilder is a transaction class thats mutable (unlike the others which are all immutable). It is +intended to be passed around contracts 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.

@@ -34,10 +41,59 @@ multiple parties.

+attachments + +val attachments: MutableList<SecureHash> + + + +commands + +val commands: MutableList<Command> + + + +currentSigs + +val currentSigs: <ERROR CLASS>

The signatures that have been collected so far - might be incomplete

+ + + + +inputs + +val inputs: MutableList<StateRef> + + + +notary + +val notary: Party? + + + +outputs + +val outputs: MutableList<TransactionState<ContractState>> + + + +signers + +val signers: MutableSet<PublicKey> + + + time val time: TimestampCommand? + + +type + +val type: TransactionType +

Functions

@@ -61,13 +117,15 @@ multiple parties.

addInputState -fun addInputState(ref: StateRef): Unit +open fun addInputState(stateAndRef: StateAndRef<*>): Unit addOutputState -fun addOutputState(state: ContractState): Unit +fun addOutputState(state: TransactionState<*>): Unit
+fun addOutputState(state: ContractState, notary: Party): Unitfun addOutputState(state: ContractState): Unit

A default notary must be specified during builder construction to use this method

+ @@ -113,7 +171,7 @@ adds it.

outputStates -fun outputStates(): List<ContractState> +fun outputStates(): List<TransactionState<*>> @@ -151,5 +209,25 @@ The signature can be obtained using NotaryProtocol.

+

Inheritors

+ + + + + + + + + + + +
+Builder +class Builder : TransactionBuilder

Just uses the default TransactionBuilder with no special logic

+
+Builder +class Builder : TransactionBuilder

A transaction builder that automatically sets the transaction type to NotaryChange +and adds the list of participants to the signers set for every input state.

+
diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/inputs.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/inputs.html new file mode 100644 index 0000000000..0fe3c2ebc8 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/inputs.html @@ -0,0 +1,15 @@ + + +TransactionBuilder.inputs - + + + +com.r3corda.core.contracts / TransactionBuilder / inputs
+
+

inputs

+ +protected val inputs: MutableList<StateRef>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/notary.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/notary.html new file mode 100644 index 0000000000..c1b9529273 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/notary.html @@ -0,0 +1,15 @@ + + +TransactionBuilder.notary - + + + +com.r3corda.core.contracts / TransactionBuilder / notary
+
+

notary

+ +protected val notary: Party?
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/output-states.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/output-states.html index 9eae76eb5f..927518ba49 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/output-states.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/output-states.html @@ -8,7 +8,7 @@

outputStates

-fun outputStates(): List<ContractState>
+fun outputStates(): List<TransactionState<*>>


diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/outputs.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/outputs.html new file mode 100644 index 0000000000..7467bf59d1 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/outputs.html @@ -0,0 +1,15 @@ + + +TransactionBuilder.outputs - + + + +com.r3corda.core.contracts / TransactionBuilder / outputs
+
+

outputs

+ +protected val outputs: MutableList<TransactionState<ContractState>>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/signers.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/signers.html new file mode 100644 index 0000000000..0829ae968c --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/signers.html @@ -0,0 +1,15 @@ + + +TransactionBuilder.signers - + + + +com.r3corda.core.contracts / TransactionBuilder / signers
+
+

signers

+ +protected val signers: MutableSet<PublicKey>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/type.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/type.html new file mode 100644 index 0000000000..7665ef3de4 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-builder/type.html @@ -0,0 +1,15 @@ + + +TransactionBuilder.type - + + + +com.r3corda.core.contracts / TransactionBuilder / type
+
+

type

+ +protected val type: TransactionType
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/-in-out-group/-init-.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/-in-out-group/-init-.html new file mode 100644 index 0000000000..96a3372ada --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/-in-out-group/-init-.html @@ -0,0 +1,19 @@ + + +TransactionForContract.InOutGroup.<init> - + + + +com.r3corda.core.contracts / TransactionForContract / InOutGroup / <init>
+
+

<init>

+InOutGroup(inputs: List<T>, outputs: List<T>, groupingKey: K)
+

A set of related inputs and outputs that are connected by some common attributes. An InOutGroup is calculated +using groupStates and is useful for handling cases where a transaction may contain similar but unrelated +state evolutions, for example, a transaction that moves cash in two different currencies. The numbers must add +up on both sides of the transaction, but the values must be summed independently per currency. Grouping can +be used to simplify this logic.

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/-in-out-group/grouping-key.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/-in-out-group/grouping-key.html new file mode 100644 index 0000000000..be2fab9b3b --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/-in-out-group/grouping-key.html @@ -0,0 +1,15 @@ + + +TransactionForContract.InOutGroup.groupingKey - + + + +com.r3corda.core.contracts / TransactionForContract / InOutGroup / groupingKey
+
+

groupingKey

+ +val groupingKey: K
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/-in-out-group/index.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/-in-out-group/index.html new file mode 100644 index 0000000000..8856eb2045 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/-in-out-group/index.html @@ -0,0 +1,58 @@ + + +TransactionForContract.InOutGroup - + + + +com.r3corda.core.contracts / TransactionForContract / InOutGroup
+
+

InOutGroup

+data class InOutGroup<T : ContractState, K : Any>
+

A set of related inputs and outputs that are connected by some common attributes. An InOutGroup is calculated +using groupStates and is useful for handling cases where a transaction may contain similar but unrelated +state evolutions, for example, a transaction that moves cash in two different currencies. The numbers must add +up on both sides of the transaction, but the values must be summed independently per currency. Grouping can +be used to simplify this logic.

+
+
+

Constructors

+ + + + + + + +
+<init> +InOutGroup(inputs: List<T>, outputs: List<T>, groupingKey: K)

A set of related inputs and outputs that are connected by some common attributes. An InOutGroup is calculated +using groupStates and is useful for handling cases where a transaction may contain similar but unrelated +state evolutions, for example, a transaction that moves cash in two different currencies. The numbers must add +up on both sides of the transaction, but the values must be summed independently per currency. Grouping can +be used to simplify this logic.

+
+

Properties

+ + + + + + + + + + + + + + + +
+groupingKey +val groupingKey: K
+inputs +val inputs: List<T>
+outputs +val outputs: List<T>
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/-in-out-group/inputs.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/-in-out-group/inputs.html new file mode 100644 index 0000000000..18918db151 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/-in-out-group/inputs.html @@ -0,0 +1,15 @@ + + +TransactionForContract.InOutGroup.inputs - + + + +com.r3corda.core.contracts / TransactionForContract / InOutGroup / inputs
+
+

inputs

+ +val inputs: List<T>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/-in-out-group/outputs.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/-in-out-group/outputs.html new file mode 100644 index 0000000000..4ba426e1f0 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/-in-out-group/outputs.html @@ -0,0 +1,15 @@ + + +TransactionForContract.InOutGroup.outputs - + + + +com.r3corda.core.contracts / TransactionForContract / InOutGroup / outputs
+
+

outputs

+ +val outputs: List<T>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/-init-.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/-init-.html new file mode 100644 index 0000000000..fdaec02495 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/-init-.html @@ -0,0 +1,16 @@ + + +TransactionForContract.<init> - + + + +com.r3corda.core.contracts / TransactionForContract / <init>
+
+

<init>

+TransactionForContract(inputs: List<ContractState>, outputs: List<ContractState>, attachments: List<Attachment>, commands: List<AuthenticatedObject<CommandData>>, origHash: SecureHash)
+

A transaction to be passed as input to a contract verification function. Defines helper methods to +simplify verification logic in contracts.

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/attachments.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/attachments.html new file mode 100644 index 0000000000..19a708f007 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/attachments.html @@ -0,0 +1,15 @@ + + +TransactionForContract.attachments - + + + +com.r3corda.core.contracts / TransactionForContract / attachments
+
+

attachments

+ +val attachments: List<Attachment>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/commands.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/commands.html new file mode 100644 index 0000000000..83eb9249d2 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/commands.html @@ -0,0 +1,15 @@ + + +TransactionForContract.commands - + + + +com.r3corda.core.contracts / TransactionForContract / commands
+
+

commands

+ +val commands: List<AuthenticatedObject<CommandData>>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/equals.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/equals.html new file mode 100644 index 0000000000..21e9265538 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/equals.html @@ -0,0 +1,15 @@ + + +TransactionForContract.equals - + + + +com.r3corda.core.contracts / TransactionForContract / equals
+
+

equals

+ +fun equals(other: Any?): Boolean
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/get-timestamp-by-name.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/get-timestamp-by-name.html new file mode 100644 index 0000000000..e733a73c40 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/get-timestamp-by-name.html @@ -0,0 +1,16 @@ + + +TransactionForContract.getTimestampByName - + + + +com.r3corda.core.contracts / TransactionForContract / getTimestampByName
+
+

getTimestampByName

+ +fun getTimestampByName(vararg authorityName: String): TimestampCommand?
+

Simply calls commands.getTimestampByName as a shortcut to make code completion more intuitive.

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/get-timestamp-by.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/get-timestamp-by.html new file mode 100644 index 0000000000..d37ebd5123 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/get-timestamp-by.html @@ -0,0 +1,16 @@ + + +TransactionForContract.getTimestampBy - + + + +com.r3corda.core.contracts / TransactionForContract / getTimestampBy
+
+

getTimestampBy

+ +fun getTimestampBy(timestampingAuthority: Party): TimestampCommand?
+

Simply calls commands.getTimestampBy as a shortcut to make code completion more intuitive.

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/group-commands.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/group-commands.html new file mode 100644 index 0000000000..eee8109e42 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/group-commands.html @@ -0,0 +1,15 @@ + + +TransactionForContract.groupCommands - + + + +com.r3corda.core.contracts / TransactionForContract / groupCommands
+
+

groupCommands

+ +inline fun <reified T : CommandData, K> groupCommands(keySelector: (AuthenticatedObject<T>) -> K): Map<K, List<AuthenticatedObject<T>>>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/group-states-internal.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/group-states-internal.html new file mode 100644 index 0000000000..b111392d3b --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/group-states-internal.html @@ -0,0 +1,17 @@ + + +TransactionForContract.groupStatesInternal - + + + +com.r3corda.core.contracts / TransactionForContract / groupStatesInternal
+
+

groupStatesInternal

+ +fun <T : ContractState, K : Any> groupStatesInternal(inGroups: Map<K, List<T>>, outGroups: Map<K, List<T>>): List<InOutGroup<T, K>>
+Deprecated: Do not use this directly: exposed as public only due to function inlining
+
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/group-states.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/group-states.html new file mode 100644 index 0000000000..d1e842e179 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/group-states.html @@ -0,0 +1,33 @@ + + +TransactionForContract.groupStates - + + + +com.r3corda.core.contracts / TransactionForContract / groupStates
+
+

groupStates

+ +fun <T : ContractState, K : Any> groupStates(ofType: Class<T>, selector: (T) -> K): List<InOutGroup<T, K>>
+

Given a type and a function that returns a grouping key, associates inputs and outputs together so that they +can be processed as one. The grouping key is any arbitrary object that can act as a map key (so must implement +equals and hashCode).

+

The purpose of this function is to simplify the writing of verification logic for transactions that may contain +similar but unrelated state evolutions which need to be checked independently. Consider a transaction that +simultaneously moves both dollars and euros (e.g. is an atomic FX trade). There may be multiple dollar inputs and +multiple dollar outputs, depending on things like how fragmented the owners wallet is and whether various privacy +techniques are in use. The quantity of dollars on the output side must sum to the same as on the input side, to +ensure no money is being lost track of. This summation and checking must be repeated independently for each +currency. To solve this, you would use groupStates with a type of Cash.State and a selector that returns the +currency field: the resulting list can then be iterated over to perform the per-currency calculation.

+
+
+
+
+ +inline fun <reified T : ContractState, K : Any> groupStates(selector: (T) -> K): List<InOutGroup<T, K>>
+

See the documentation for the reflection-based version of groupStates

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/hash-code.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/hash-code.html new file mode 100644 index 0000000000..849bb50f94 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/hash-code.html @@ -0,0 +1,15 @@ + + +TransactionForContract.hashCode - + + + +com.r3corda.core.contracts / TransactionForContract / hashCode
+
+

hashCode

+ +fun hashCode(): Int
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/in-states.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/in-states.html new file mode 100644 index 0000000000..b50ec12d39 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/in-states.html @@ -0,0 +1,17 @@ + + +TransactionForContract.inStates - + + + +com.r3corda.core.contracts / TransactionForContract / inStates
+
+

inStates

+ +val inStates: List<ContractState>
+Deprecated: This property was renamed to inputs
+
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/index.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/index.html new file mode 100644 index 0000000000..f319ef5b32 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/index.html @@ -0,0 +1,145 @@ + + +TransactionForContract - + + + +com.r3corda.core.contracts / TransactionForContract
+
+

TransactionForContract

+data class TransactionForContract
+

A transaction to be passed as input to a contract verification function. Defines helper methods to +simplify verification logic in contracts.

+
+
+

Types

+ + + + + + + +
+InOutGroup +data class InOutGroup<T : ContractState, K : Any>

A set of related inputs and outputs that are connected by some common attributes. An InOutGroup is calculated +using groupStates and is useful for handling cases where a transaction may contain similar but unrelated +state evolutions, for example, a transaction that moves cash in two different currencies. The numbers must add +up on both sides of the transaction, but the values must be summed independently per currency. Grouping can +be used to simplify this logic.

+
+

Constructors

+ + + + + + + +
+<init> +TransactionForContract(inputs: List<ContractState>, outputs: List<ContractState>, attachments: List<Attachment>, commands: List<AuthenticatedObject<CommandData>>, origHash: SecureHash)

A transaction to be passed as input to a contract verification function. Defines helper methods to +simplify verification logic in contracts.

+
+

Properties

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+attachments +val attachments: List<Attachment>
+commands +val commands: List<AuthenticatedObject<CommandData>>
+inStates +val inStates: List<ContractState>
+inputs +val inputs: List<ContractState>
+origHash +val origHash: SecureHash
+outStates +val outStates: List<ContractState>
+outputs +val outputs: List<ContractState>
+

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+equals +fun equals(other: Any?): Boolean
+getTimestampBy +fun getTimestampBy(timestampingAuthority: Party): TimestampCommand?

Simply calls commands.getTimestampBy as a shortcut to make code completion more intuitive.

+
+getTimestampByName +fun getTimestampByName(vararg authorityName: String): TimestampCommand?

Simply calls commands.getTimestampByName as a shortcut to make code completion more intuitive.

+
+groupCommands +fun <T : CommandData, K> groupCommands(keySelector: (AuthenticatedObject<T>) -> K): Map<K, List<AuthenticatedObject<T>>>
+groupStates +fun <T : ContractState, K : Any> groupStates(ofType: Class<T>, selector: (T) -> K): List<InOutGroup<T, K>>

Given a type and a function that returns a grouping key, associates inputs and outputs together so that they +can be processed as one. The grouping key is any arbitrary object that can act as a map key (so must implement +equals and hashCode).

+fun <T : ContractState, K : Any> groupStates(selector: (T) -> K): List<InOutGroup<T, K>>

See the documentation for the reflection-based version of groupStates

+
+groupStatesInternal +fun <T : ContractState, K : Any> groupStatesInternal(inGroups: Map<K, List<T>>, outGroups: Map<K, List<T>>): List<InOutGroup<T, K>>
+hashCode +fun hashCode(): Int
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/inputs.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/inputs.html new file mode 100644 index 0000000000..e28849f290 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/inputs.html @@ -0,0 +1,15 @@ + + +TransactionForContract.inputs - + + + +com.r3corda.core.contracts / TransactionForContract / inputs
+
+

inputs

+ +val inputs: List<ContractState>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/orig-hash.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/orig-hash.html new file mode 100644 index 0000000000..357cc8b5da --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/orig-hash.html @@ -0,0 +1,15 @@ + + +TransactionForContract.origHash - + + + +com.r3corda.core.contracts / TransactionForContract / origHash
+
+

origHash

+ +val origHash: SecureHash
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/out-states.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/out-states.html new file mode 100644 index 0000000000..818d806c08 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/out-states.html @@ -0,0 +1,17 @@ + + +TransactionForContract.outStates - + + + +com.r3corda.core.contracts / TransactionForContract / outStates
+
+

outStates

+ +val outStates: List<ContractState>
+Deprecated: This property was renamed to outputs
+
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/outputs.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/outputs.html new file mode 100644 index 0000000000..3ff5ac87d8 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-contract/outputs.html @@ -0,0 +1,15 @@ + + +TransactionForContract.outputs - + + + +com.r3corda.core.contracts / TransactionForContract / outputs
+
+

outputs

+ +val outputs: List<ContractState>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-verification/-init-.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-verification/-init-.html index ed7278a674..f89bdd0b79 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-verification/-init-.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-verification/-init-.html @@ -7,7 +7,7 @@ com.r3corda.core.contracts / TransactionForVerification / <init>

<init>

-TransactionForVerification(inStates: List<ContractState>, outStates: List<ContractState>, attachments: List<Attachment>, commands: List<AuthenticatedObject<CommandData>>, origHash: SecureHash)
+TransactionForVerification(inputs: List<TransactionState<ContractState>>, outputs: List<TransactionState<ContractState>>, attachments: List<Attachment>, commands: List<AuthenticatedObject<CommandData>>, origHash: SecureHash, signers: List<PublicKey>, type: TransactionType)

A transaction in fully resolved and sig-checked form, ready for passing as input to a verification function.



diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-verification/index.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-verification/index.html index eb16604591..466707e09e 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-verification/index.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-verification/index.html @@ -11,22 +11,6 @@

A transaction in fully resolved and sig-checked form, ready for passing as input to a verification function.



-

Types

- - - - - - - -
-InOutGroup -data class InOutGroup<T : ContractState, K : Any>

A set of related inputs and outputs that are connected by some common attributes. An InOutGroup is calculated -using groupStates and is useful for handling cases where a transaction may contain similar but unrelated -state evolutions, for example, a transaction that moves cash in two different currencies. The numbers must add -up on both sides of the transaction, but the values must be summed independently per currency. Grouping can -be used to simplify this logic.

-

Constructors

@@ -34,7 +18,7 @@ be used to simplify this logic.

@@ -56,9 +40,9 @@ be used to simplify this logic.

+inputs +val inputs: List<TransactionState<ContractState>> +outputs +val outputs: List<TransactionState<ContractState>> + + + + + + + +
<init> -TransactionForVerification(inStates: List<ContractState>, outStates: List<ContractState>, attachments: List<Attachment>, commands: List<AuthenticatedObject<CommandData>>, origHash: SecureHash)

A transaction in fully resolved and sig-checked form, ready for passing as input to a verification function.

+TransactionForVerification(inputs: List<TransactionState<ContractState>>, outputs: List<TransactionState<ContractState>>, attachments: List<Attachment>, commands: List<AuthenticatedObject<CommandData>>, origHash: SecureHash, signers: List<PublicKey>, type: TransactionType)

A transaction in fully resolved and sig-checked form, ready for passing as input to a verification function.

-inStates -val inStates: List<ContractState>
@@ -68,9 +52,21 @@ be used to simplify this logic.

-outStates -val outStates: List<ContractState>
+signers +val signers: List<PublicKey>
+type +val type: TransactionType
@@ -85,45 +81,21 @@ be used to simplify this logic.

-getTimestampBy - -fun getTimestampBy(timestampingAuthority: Party): TimestampCommand?

Simply calls commands.getTimestampBy as a shortcut to make code completion more intuitive.

- - - - -getTimestampByName - -fun getTimestampByName(vararg authorityName: String): TimestampCommand?

Simply calls commands.getTimestampByName as a shortcut to make code completion more intuitive.

- - - - -groupStates - -fun <T : ContractState, K : Any> groupStates(ofType: Class<T>, selector: (T) -> K): List<InOutGroup<T, K>>

Given a type and a function that returns a grouping key, associates inputs and outputs together so that they -can be processed as one. The grouping key is any arbitrary object that can act as a map key (so must implement -equals and hashCode).

-fun <T : ContractState, K : Any> groupStates(selector: (T) -> K): List<InOutGroup<T, K>>

See the documentation for the reflection-based version of groupStates

- - - - -groupStatesInternal - -fun <T : ContractState, K : Any> groupStatesInternal(inGroups: Map<K, List<T>>, outGroups: Map<K, List<T>>): List<InOutGroup<T, K>> - - - hashCode fun hashCode(): Int +toTransactionForContract + +fun toTransactionForContract(): TransactionForContract + + + verify -fun verify(): Unit

Verifies that the transaction is valid:

+fun verify(): Unit

Verifies that the transaction is valid by running type-specific validation logic.

diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-verification/inputs.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-verification/inputs.html new file mode 100644 index 0000000000..b4e9b297db --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-verification/inputs.html @@ -0,0 +1,15 @@ + + +TransactionForVerification.inputs - + + + +com.r3corda.core.contracts / TransactionForVerification / inputs
+
+

inputs

+ +val inputs: List<TransactionState<ContractState>>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-verification/outputs.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-verification/outputs.html new file mode 100644 index 0000000000..377942f9f1 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-verification/outputs.html @@ -0,0 +1,15 @@ + + +TransactionForVerification.outputs - + + + +com.r3corda.core.contracts / TransactionForVerification / outputs
+
+

outputs

+ +val outputs: List<TransactionState<ContractState>>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-verification/signers.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-verification/signers.html new file mode 100644 index 0000000000..39cdb34a00 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-verification/signers.html @@ -0,0 +1,15 @@ + + +TransactionForVerification.signers - + + + +com.r3corda.core.contracts / TransactionForVerification / signers
+
+

signers

+ +val signers: List<PublicKey>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-verification/to-transaction-for-contract.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-verification/to-transaction-for-contract.html new file mode 100644 index 0000000000..9402ba4104 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-verification/to-transaction-for-contract.html @@ -0,0 +1,15 @@ + + +TransactionForVerification.toTransactionForContract - + + + +com.r3corda.core.contracts / TransactionForVerification / toTransactionForContract
+
+

toTransactionForContract

+ +fun toTransactionForContract(): TransactionForContract
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-verification/type.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-verification/type.html new file mode 100644 index 0000000000..4701b978a0 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-verification/type.html @@ -0,0 +1,15 @@ + + +TransactionForVerification.type - + + + +com.r3corda.core.contracts / TransactionForVerification / type
+
+

type

+ +val type: TransactionType
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-verification/verify.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-verification/verify.html index f4dc759e64..0da45f7da3 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-verification/verify.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-for-verification/verify.html @@ -9,17 +9,14 @@

verify

fun verify(): Unit
-

Verifies that the transaction is valid:

-
  • Checks that the input states and the timestamp point to the same Notary

    -
  • Runs the contracts for this transaction. If any contract fails to verify, the whole transaction -is considered to be invalid

    -

TODO: Move this out of the core data structure definitions, once unit tests are more cleanly separated.

+

Verifies that the transaction is valid by running type-specific validation logic.

+

TODO: Move this out of the core data structure definitions, once unit tests are more cleanly separated.



Exceptions

-TransactionVerificationException - if a contract throws an exception (the original is in the cause field) -or the transaction has references to more than one Notary
+TransactionVerificationException - if validation logic fails or if a contract throws an exception +(the original is in the cause field)


diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-graph-search/-init-.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-graph-search/-init-.html index 31823daa39..8cf8a88d68 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-transaction-graph-search/-init-.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-graph-search/-init-.html @@ -7,7 +7,7 @@ com.r3corda.core.contracts / TransactionGraphSearch / <init>

<init>

-TransactionGraphSearch(transactions: TransactionStorage, startPoints: List<WireTransaction>)
+TransactionGraphSearch(transactions: ReadOnlyTransactionStorage, startPoints: List<WireTransaction>)

Given a map of transaction id to SignedTransaction, performs a breadth first search of the dependency graph from the starting point down in order to find transactions that match the given query criteria.

Currently, only one kind of query is supported: find any transaction that contains a command of the given type.

diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-graph-search/index.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-graph-search/index.html index 82a98bfee1..198da1e902 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-transaction-graph-search/index.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-graph-search/index.html @@ -40,7 +40,7 @@ the starting point down in order to find transactions that match the given query <init> -TransactionGraphSearch(transactions: TransactionStorage, startPoints: List<WireTransaction>)

Given a map of transaction id to SignedTransaction, performs a breadth first search of the dependency graph from +TransactionGraphSearch(transactions: ReadOnlyTransactionStorage, startPoints: List<WireTransaction>)

Given a map of transaction id to SignedTransaction, performs a breadth first search of the dependency graph from the starting point down in order to find transactions that match the given query criteria.

@@ -65,7 +65,7 @@ the starting point down in order to find transactions that match the given query transactions -val transactions: TransactionStorage +val transactions: ReadOnlyTransactionStorage diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-graph-search/transactions.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-graph-search/transactions.html index 509377a577..9edf4da5cd 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-transaction-graph-search/transactions.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-graph-search/transactions.html @@ -8,7 +8,7 @@

transactions

-val transactions: TransactionStorage
+val transactions: ReadOnlyTransactionStorage


diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-state/-init-.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-state/-init-.html new file mode 100644 index 0000000000..a0c8154444 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-state/-init-.html @@ -0,0 +1,16 @@ + + +TransactionState.<init> - + + + +com.r3corda.core.contracts / TransactionState / <init>
+
+

<init>

+TransactionState(data: T, notary: Party)
+

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.

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-state/data.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-state/data.html new file mode 100644 index 0000000000..9282d0fd9c --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-state/data.html @@ -0,0 +1,16 @@ + + +TransactionState.data - + + + +com.r3corda.core.contracts / TransactionState / data
+
+

data

+ +val data: T
+

The custom contract state

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-state/index.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-state/index.html new file mode 100644 index 0000000000..773cb36464 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-state/index.html @@ -0,0 +1,72 @@ + + +TransactionState - + + + +com.r3corda.core.contracts / TransactionState
+
+

TransactionState

+data class TransactionState<out T : ContractState>
+

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.

+
+
+

Constructors

+ + + + + + + +
+<init> +TransactionState(data: T, notary: Party)

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.

+
+

Properties

+ + + + + + + + + + + +
+data +val data: T

The custom contract state

+
+notary +val notary: Party

Identity of the notary that ensures the state is not used as an input to a transaction more than once

+
+

Functions

+ + + + + + + +
+withNewNotary +fun withNewNotary(newNotary: Party): TransactionState<T>

Copies the underlying state, replacing the notary field with the new value. +To replace the notary, we need an approval (signature) from all participants of the ContractState

+
+

Extension Functions

+ + + + + + + +
+label +infix fun TransactionState<*>.label(label: String): LabeledOutput
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-state/notary.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-state/notary.html new file mode 100644 index 0000000000..ede4deb099 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-state/notary.html @@ -0,0 +1,16 @@ + + +TransactionState.notary - + + + +com.r3corda.core.contracts / TransactionState / notary
+
+

notary

+ +val notary: Party
+

Identity of the notary that ensures the state is not used as an input to a transaction more than once

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-state/with-new-notary.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-state/with-new-notary.html new file mode 100644 index 0000000000..342ddf25fc --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-state/with-new-notary.html @@ -0,0 +1,17 @@ + + +TransactionState.withNewNotary - + + + +com.r3corda.core.contracts / TransactionState / withNewNotary
+
+

withNewNotary

+ +fun withNewNotary(newNotary: Party): TransactionState<T>
+

Copies the underlying state, replacing the notary field with the new value. +To replace the notary, we need an approval (signature) from all participants of the ContractState

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-general/-builder/-init-.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-general/-builder/-init-.html new file mode 100644 index 0000000000..bcc673c2e5 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-general/-builder/-init-.html @@ -0,0 +1,15 @@ + + +TransactionType.General.Builder.<init> - + + + +com.r3corda.core.contracts / TransactionType / General / Builder / <init>
+
+

<init>

+Builder(notary: Party? = null)
+

Just uses the default TransactionBuilder with no special logic

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-general/-builder/index.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-general/-builder/index.html new file mode 100644 index 0000000000..ea582cc3a6 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-general/-builder/index.html @@ -0,0 +1,200 @@ + + +TransactionType.General.Builder - + + + +com.r3corda.core.contracts / TransactionType / General / Builder
+
+

Builder

+class Builder : TransactionBuilder
+

Just uses the default TransactionBuilder with no special logic

+
+
+

Constructors

+ + + + + + + +
+<init> +Builder(notary: Party? = null)

Just uses the default TransactionBuilder with no special logic

+
+

Inherited Properties

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+attachments +val attachments: MutableList<SecureHash>
+commands +val commands: MutableList<Command>
+currentSigs +val currentSigs: <ERROR CLASS>

The signatures that have been collected so far - might be incomplete

+
+inputs +val inputs: MutableList<StateRef>
+notary +val notary: Party?
+outputs +val outputs: MutableList<TransactionState<ContractState>>
+signers +val signers: MutableSet<PublicKey>
+time +val time: TimestampCommand?
+type +val type: TransactionType
+

Inherited Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+addAttachment +fun addAttachment(attachment: Attachment): Unit
+addCommand +fun addCommand(arg: Command): Unit
+fun addCommand(data: CommandData, vararg keys: PublicKey): <ERROR CLASS>
+fun addCommand(data: CommandData, keys: List<PublicKey>): Unit
+addInputState +open fun addInputState(stateAndRef: StateAndRef<*>): Unit
+addOutputState +fun addOutputState(state: TransactionState<*>): Unit
+fun addOutputState(state: ContractState, notary: Party): Unitfun addOutputState(state: ContractState): Unit

A default notary must be specified during builder construction to use this method

+
+addSignatureUnchecked +fun addSignatureUnchecked(sig: WithKey): Unit

Adds the signature directly to the transaction, without checking it for validity.

+
+attachments +fun attachments(): List<SecureHash>
+checkAndAddSignature +fun checkAndAddSignature(sig: WithKey): Unit

Checks that the given signature matches one of the commands and that it is a correct signature over the tx, then +adds it.

+
+checkSignature +fun checkSignature(sig: WithKey): Unit

Checks that the given signature matches one of the commands and that it is a correct signature over the tx.

+
+commands +fun commands(): List<Command>
+inputStates +fun inputStates(): List<StateRef>
+outputStates +fun outputStates(): List<TransactionState<*>>
+setTime +fun setTime(time: Instant, authority: Party, timeTolerance: Duration): Unit

Places a TimestampCommand in this transaction, removing any existing command if there is one. +The command requires a signature from the Notary service, which acts as a Timestamp Authority. +The signature can be obtained using NotaryProtocol.

+
+signWith +fun signWith(key: KeyPair): Unit
+toSignedTransaction +fun toSignedTransaction(checkSufficientSignatures: Boolean = true): SignedTransaction
+toWireTransaction +fun toWireTransaction(): WireTransaction
+withItems +fun withItems(vararg items: Any): TransactionBuilder

A more convenient way to add items to this transaction that calls the add* methods for you based on type

+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-general/-init-.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-general/-init-.html new file mode 100644 index 0000000000..eaabe68ed1 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-general/-init-.html @@ -0,0 +1,15 @@ + + +TransactionType.General.<init> - + + + +com.r3corda.core.contracts / TransactionType / General / <init>
+
+

<init>

+General()
+

A general transaction type where transaction validity is determined by custom contract code

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-general/get-required-signers.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-general/get-required-signers.html new file mode 100644 index 0000000000..f8f3e117b7 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-general/get-required-signers.html @@ -0,0 +1,18 @@ + + +TransactionType.General.getRequiredSigners - + + + +com.r3corda.core.contracts / TransactionType / General / getRequiredSigners
+
+

getRequiredSigners

+ +fun getRequiredSigners(tx: TransactionForVerification): Set<PublicKey>
+Overrides TransactionType.getRequiredSigners
+

Return the list of public keys that that require signatures for the transaction type. +Note: the notary key is checked separately for all transactions and need not be included

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-general/index.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-general/index.html new file mode 100644 index 0000000000..aaff72fddc --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-general/index.html @@ -0,0 +1,91 @@ + + +TransactionType.General - + + + +com.r3corda.core.contracts / TransactionType / General
+
+

General

+class General : TransactionType
+

A general transaction type where transaction validity is determined by custom contract code

+
+
+

Types

+ + + + + + + +
+Builder +class Builder : TransactionBuilder

Just uses the default TransactionBuilder with no special logic

+
+

Constructors

+ + + + + + + +
+<init> +General()

A general transaction type where transaction validity is determined by custom contract code

+
+

Functions

+ + + + + + + + + + + +
+getRequiredSigners +fun getRequiredSigners(tx: TransactionForVerification): Set<PublicKey>

Return the list of public keys that that require signatures for the transaction type. +Note: the notary key is checked separately for all transactions and need not be included

+
+verifyTransaction +fun verifyTransaction(tx: TransactionForVerification): Unit

Check the transaction is contract-valid by running the verify() for each input and output state contract. +If any contract fails to verify, the whole transaction is considered to be invalid

+
+

Inherited Functions

+ + + + + + + + + + + + + + + + + + + +
+equals +open fun equals(other: Any?): Boolean
+hashCode +open fun hashCode(): <ERROR CLASS>
+verify +fun verify(tx: TransactionForVerification): Unit

Check that the transaction is valid based on:

+
+verifySigners +fun verifySigners(tx: TransactionForVerification): Set<PublicKey>

Check that the list of signers includes all the necessary keys

+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-general/verify-transaction.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-general/verify-transaction.html new file mode 100644 index 0000000000..9903d6ba36 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-general/verify-transaction.html @@ -0,0 +1,18 @@ + + +TransactionType.General.verifyTransaction - + + + +com.r3corda.core.contracts / TransactionType / General / verifyTransaction
+
+

verifyTransaction

+ +fun verifyTransaction(tx: TransactionForVerification): Unit
+Overrides TransactionType.verifyTransaction
+

Check the transaction is contract-valid by running the verify() for each input and output state contract. +If any contract fails to verify, the whole transaction is considered to be invalid

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-notary-change/-builder/-init-.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-notary-change/-builder/-init-.html new file mode 100644 index 0000000000..1f23f39a59 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-notary-change/-builder/-init-.html @@ -0,0 +1,16 @@ + + +TransactionType.NotaryChange.Builder.<init> - + + + +com.r3corda.core.contracts / TransactionType / NotaryChange / Builder / <init>
+
+

<init>

+Builder(notary: Party? = null)
+

A transaction builder that automatically sets the transaction type to NotaryChange +and adds the list of participants to the signers set for every input state.

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-notary-change/-builder/add-input-state.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-notary-change/-builder/add-input-state.html new file mode 100644 index 0000000000..96ab591cc3 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-notary-change/-builder/add-input-state.html @@ -0,0 +1,16 @@ + + +TransactionType.NotaryChange.Builder.addInputState - + + + +com.r3corda.core.contracts / TransactionType / NotaryChange / Builder / addInputState
+
+

addInputState

+ +fun addInputState(stateAndRef: StateAndRef<*>): Unit
+Overrides TransactionBuilder.addInputState
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-notary-change/-builder/index.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-notary-change/-builder/index.html new file mode 100644 index 0000000000..5e19c55e1a --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-notary-change/-builder/index.html @@ -0,0 +1,207 @@ + + +TransactionType.NotaryChange.Builder - + + + +com.r3corda.core.contracts / TransactionType / NotaryChange / Builder
+
+

Builder

+class Builder : TransactionBuilder
+

A transaction builder that automatically sets the transaction type to NotaryChange +and adds the list of participants to the signers set for every input state.

+
+
+

Constructors

+ + + + + + + +
+<init> +Builder(notary: Party? = null)

A transaction builder that automatically sets the transaction type to NotaryChange +and adds the list of participants to the signers set for every input state.

+
+

Inherited Properties

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+attachments +val attachments: MutableList<SecureHash>
+commands +val commands: MutableList<Command>
+currentSigs +val currentSigs: <ERROR CLASS>

The signatures that have been collected so far - might be incomplete

+
+inputs +val inputs: MutableList<StateRef>
+notary +val notary: Party?
+outputs +val outputs: MutableList<TransactionState<ContractState>>
+signers +val signers: MutableSet<PublicKey>
+time +val time: TimestampCommand?
+type +val type: TransactionType
+

Functions

+ + + + + + + +
+addInputState +fun addInputState(stateAndRef: StateAndRef<*>): Unit
+

Inherited Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+addAttachment +fun addAttachment(attachment: Attachment): Unit
+addCommand +fun addCommand(arg: Command): Unit
+fun addCommand(data: CommandData, vararg keys: PublicKey): <ERROR CLASS>
+fun addCommand(data: CommandData, keys: List<PublicKey>): Unit
+addOutputState +fun addOutputState(state: TransactionState<*>): Unit
+fun addOutputState(state: ContractState, notary: Party): Unitfun addOutputState(state: ContractState): Unit

A default notary must be specified during builder construction to use this method

+
+addSignatureUnchecked +fun addSignatureUnchecked(sig: WithKey): Unit

Adds the signature directly to the transaction, without checking it for validity.

+
+attachments +fun attachments(): List<SecureHash>
+checkAndAddSignature +fun checkAndAddSignature(sig: WithKey): Unit

Checks that the given signature matches one of the commands and that it is a correct signature over the tx, then +adds it.

+
+checkSignature +fun checkSignature(sig: WithKey): Unit

Checks that the given signature matches one of the commands and that it is a correct signature over the tx.

+
+commands +fun commands(): List<Command>
+inputStates +fun inputStates(): List<StateRef>
+outputStates +fun outputStates(): List<TransactionState<*>>
+setTime +fun setTime(time: Instant, authority: Party, timeTolerance: Duration): Unit

Places a TimestampCommand in this transaction, removing any existing command if there is one. +The command requires a signature from the Notary service, which acts as a Timestamp Authority. +The signature can be obtained using NotaryProtocol.

+
+signWith +fun signWith(key: KeyPair): Unit
+toSignedTransaction +fun toSignedTransaction(checkSufficientSignatures: Boolean = true): SignedTransaction
+toWireTransaction +fun toWireTransaction(): WireTransaction
+withItems +fun withItems(vararg items: Any): TransactionBuilder

A more convenient way to add items to this transaction that calls the add* methods for you based on type

+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-notary-change/-init-.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-notary-change/-init-.html new file mode 100644 index 0000000000..f188ceeb25 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-notary-change/-init-.html @@ -0,0 +1,16 @@ + + +TransactionType.NotaryChange.<init> - + + + +com.r3corda.core.contracts / TransactionType / NotaryChange / <init>
+
+

<init>

+NotaryChange()
+

A special transaction type for reassigning a notary for a state. Validation does not involve running +any contract code, it just checks that the states are unmodified apart from the notary field.

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-notary-change/get-required-signers.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-notary-change/get-required-signers.html new file mode 100644 index 0000000000..1db269a937 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-notary-change/get-required-signers.html @@ -0,0 +1,18 @@ + + +TransactionType.NotaryChange.getRequiredSigners - + + + +com.r3corda.core.contracts / TransactionType / NotaryChange / getRequiredSigners
+
+

getRequiredSigners

+ +fun getRequiredSigners(tx: TransactionForVerification): Set<PublicKey>
+Overrides TransactionType.getRequiredSigners
+

Return the list of public keys that that require signatures for the transaction type. +Note: the notary key is checked separately for all transactions and need not be included

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-notary-change/index.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-notary-change/index.html new file mode 100644 index 0000000000..73c0837fab --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-notary-change/index.html @@ -0,0 +1,94 @@ + + +TransactionType.NotaryChange - + + + +com.r3corda.core.contracts / TransactionType / NotaryChange
+
+

NotaryChange

+class NotaryChange : TransactionType
+

A special transaction type for reassigning a notary for a state. Validation does not involve running +any contract code, it just checks that the states are unmodified apart from the notary field.

+
+
+

Types

+ + + + + + + +
+Builder +class Builder : TransactionBuilder

A transaction builder that automatically sets the transaction type to NotaryChange +and adds the list of participants to the signers set for every input state.

+
+

Constructors

+ + + + + + + +
+<init> +NotaryChange()

A special transaction type for reassigning a notary for a state. Validation does not involve running +any contract code, it just checks that the states are unmodified apart from the notary field.

+
+

Functions

+ + + + + + + + + + + +
+getRequiredSigners +fun getRequiredSigners(tx: TransactionForVerification): Set<PublicKey>

Return the list of public keys that that require signatures for the transaction type. +Note: the notary key is checked separately for all transactions and need not be included

+
+verifyTransaction +fun verifyTransaction(tx: TransactionForVerification): Unit

Check that the difference between inputs and outputs is only the notary field, +and that all required signing public keys are present

+
+

Inherited Functions

+ + + + + + + + + + + + + + + + + + + +
+equals +open fun equals(other: Any?): Boolean
+hashCode +open fun hashCode(): <ERROR CLASS>
+verify +fun verify(tx: TransactionForVerification): Unit

Check that the transaction is valid based on:

+
+verifySigners +fun verifySigners(tx: TransactionForVerification): Set<PublicKey>

Check that the list of signers includes all the necessary keys

+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-notary-change/verify-transaction.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-notary-change/verify-transaction.html new file mode 100644 index 0000000000..a208072678 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/-notary-change/verify-transaction.html @@ -0,0 +1,18 @@ + + +TransactionType.NotaryChange.verifyTransaction - + + + +com.r3corda.core.contracts / TransactionType / NotaryChange / verifyTransaction
+
+

verifyTransaction

+ +fun verifyTransaction(tx: TransactionForVerification): Unit
+Overrides TransactionType.verifyTransaction
+

Check that the difference between inputs and outputs is only the notary field, +and that all required signing public keys are present

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/equals.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/equals.html new file mode 100644 index 0000000000..d6960ac1c4 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/equals.html @@ -0,0 +1,15 @@ + + +TransactionType.equals - + + + +com.r3corda.core.contracts / TransactionType / equals
+
+

equals

+ +open fun equals(other: Any?): Boolean
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/get-required-signers.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/get-required-signers.html new file mode 100644 index 0000000000..0dfce701c2 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/get-required-signers.html @@ -0,0 +1,17 @@ + + +TransactionType.getRequiredSigners - + + + +com.r3corda.core.contracts / TransactionType / getRequiredSigners
+
+

getRequiredSigners

+ +abstract fun getRequiredSigners(tx: TransactionForVerification): Set<PublicKey>
+

Return the list of public keys that that require signatures for the transaction type. +Note: the notary key is checked separately for all transactions and need not be included

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/hash-code.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/hash-code.html new file mode 100644 index 0000000000..e8d52895a8 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/hash-code.html @@ -0,0 +1,15 @@ + + +TransactionType.hashCode - + + + +com.r3corda.core.contracts / TransactionType / hashCode
+
+

hashCode

+ +open fun hashCode(): <ERROR CLASS>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/index.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/index.html new file mode 100644 index 0000000000..88315146bc --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/index.html @@ -0,0 +1,101 @@ + + +TransactionType - + + + +com.r3corda.core.contracts / TransactionType
+
+

TransactionType

+sealed class TransactionType
+

Defines transaction build & validation logic for a specific transaction type

+
+
+

Types

+ + + + + + + + + + + +
+General +class General : TransactionType

A general transaction type where transaction validity is determined by custom contract code

+
+NotaryChange +class NotaryChange : TransactionType

A special transaction type for reassigning a notary for a state. Validation does not involve running +any contract code, it just checks that the states are unmodified apart from the notary field.

+
+

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+equals +open fun equals(other: Any?): Boolean
+getRequiredSigners +abstract fun getRequiredSigners(tx: TransactionForVerification): Set<PublicKey>

Return the list of public keys that that require signatures for the transaction type. +Note: the notary key is checked separately for all transactions and need not be included

+
+hashCode +open fun hashCode(): <ERROR CLASS>
+verify +fun verify(tx: TransactionForVerification): Unit

Check that the transaction is valid based on:

+
+verifySigners +fun verifySigners(tx: TransactionForVerification): Set<PublicKey>

Check that the list of signers includes all the necessary keys

+
+verifyTransaction +abstract fun verifyTransaction(tx: TransactionForVerification): Unit

Implement type specific transaction validation logic

+
+

Inheritors

+ + + + + + + + + + + +
+General +class General : TransactionType

A general transaction type where transaction validity is determined by custom contract code

+
+NotaryChange +class NotaryChange : TransactionType

A special transaction type for reassigning a notary for a state. Validation does not involve running +any contract code, it just checks that the states are unmodified apart from the notary field.

+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/verify-signers.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/verify-signers.html new file mode 100644 index 0000000000..46b5b6f76e --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/verify-signers.html @@ -0,0 +1,16 @@ + + +TransactionType.verifySigners - + + + +com.r3corda.core.contracts / TransactionType / verifySigners
+
+

verifySigners

+ +fun verifySigners(tx: TransactionForVerification): Set<PublicKey>
+

Check that the list of signers includes all the necessary keys

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/verify-transaction.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/verify-transaction.html new file mode 100644 index 0000000000..522e3fe365 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/verify-transaction.html @@ -0,0 +1,16 @@ + + +TransactionType.verifyTransaction - + + + +com.r3corda.core.contracts / TransactionType / verifyTransaction
+
+

verifyTransaction

+ +abstract fun verifyTransaction(tx: TransactionForVerification): Unit
+

Implement type specific transaction validation logic

+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/verify.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/verify.html new file mode 100644 index 0000000000..b12ac7e8c4 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-type/verify.html @@ -0,0 +1,21 @@ + + +TransactionType.verify - + + + +com.r3corda.core.contracts / TransactionType / verify
+
+

verify

+ +fun verify(tx: TransactionForVerification): Unit
+

Check that the transaction is valid based on:

+
  • General platform rules

    +
  • Rules for the specific transaction type

    +

Note: Presence of signatures is not checked, only the public keys to be signed for.

+
+
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-verification-exception/-invalid-notary-change/-init-.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-verification-exception/-invalid-notary-change/-init-.html new file mode 100644 index 0000000000..53d5735b7f --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-verification-exception/-invalid-notary-change/-init-.html @@ -0,0 +1,14 @@ + + +TransactionVerificationException.InvalidNotaryChange.<init> - + + + +com.r3corda.core.contracts / TransactionVerificationException / InvalidNotaryChange / <init>
+
+

<init>

+InvalidNotaryChange(tx: TransactionForVerification)
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-verification-exception/-invalid-notary-change/index.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-verification-exception/-invalid-notary-change/index.html new file mode 100644 index 0000000000..a4382418e2 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-verification-exception/-invalid-notary-change/index.html @@ -0,0 +1,36 @@ + + +TransactionVerificationException.InvalidNotaryChange - + + + +com.r3corda.core.contracts / TransactionVerificationException / InvalidNotaryChange
+
+

InvalidNotaryChange

+class InvalidNotaryChange : TransactionVerificationException
+
+
+

Constructors

+ + + + + + + +
+<init> +InvalidNotaryChange(tx: TransactionForVerification)
+

Inherited Properties

+ + + + + + + +
+tx +val tx: TransactionForVerification
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-verification-exception/-signers-missing/-init-.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-verification-exception/-signers-missing/-init-.html new file mode 100644 index 0000000000..1b23a7c3f6 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-verification-exception/-signers-missing/-init-.html @@ -0,0 +1,14 @@ + + +TransactionVerificationException.SignersMissing.<init> - + + + +com.r3corda.core.contracts / TransactionVerificationException / SignersMissing / <init>
+
+

<init>

+SignersMissing(tx: TransactionForVerification, missing: List<PublicKey>)
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-verification-exception/-signers-missing/index.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-verification-exception/-signers-missing/index.html new file mode 100644 index 0000000000..05d27eb3d1 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-verification-exception/-signers-missing/index.html @@ -0,0 +1,36 @@ + + +TransactionVerificationException.SignersMissing - + + + +com.r3corda.core.contracts / TransactionVerificationException / SignersMissing
+
+

SignersMissing

+class SignersMissing : TransactionVerificationException
+
+
+

Constructors

+ + + + + + + +
+<init> +SignersMissing(tx: TransactionForVerification, missing: List<PublicKey>)
+

Inherited Properties

+ + + + + + + +
+tx +val tx: TransactionForVerification
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-transaction-verification-exception/index.html b/docs/build/html/api/com.r3corda.core.contracts/-transaction-verification-exception/index.html index 32267c16e2..2a2f62dd72 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-transaction-verification-exception/index.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-transaction-verification-exception/index.html @@ -21,10 +21,22 @@ +InvalidNotaryChange + +class InvalidNotaryChange : TransactionVerificationException + + + MoreThanOneNotary class MoreThanOneNotary : TransactionVerificationException + + +SignersMissing + +class SignersMissing : TransactionVerificationException +

Properties

@@ -49,10 +61,22 @@ +InvalidNotaryChange + +class InvalidNotaryChange : TransactionVerificationException + + + MoreThanOneNotary class MoreThanOneNotary : TransactionVerificationException + + +SignersMissing + +class SignersMissing : TransactionVerificationException + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-type-only-command-data/index.html b/docs/build/html/api/com.r3corda.core.contracts/-type-only-command-data/index.html index 67efeab009..e2bc710ee6 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-type-only-command-data/index.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-type-only-command-data/index.html @@ -75,9 +75,9 @@ -Move +Move -class Move : TypeOnlyCommandData, Move +class Move : TypeOnlyCommandData, Commands diff --git a/docs/build/html/api/com.r3corda.core.contracts/-wire-transaction/-init-.html b/docs/build/html/api/com.r3corda.core.contracts/-wire-transaction/-init-.html index 7344247951..2c42283bf9 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-wire-transaction/-init-.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-wire-transaction/-init-.html @@ -7,7 +7,7 @@ com.r3corda.core.contracts / WireTransaction / <init>

<init>

-WireTransaction(inputs: List<StateRef>, attachments: List<SecureHash>, outputs: List<ContractState>, commands: List<Command>)
+WireTransaction(inputs: List<StateRef>, attachments: List<SecureHash>, outputs: List<TransactionState<ContractState>>, commands: List<Command>, signers: List<PublicKey>, type: TransactionType)

Transaction ready for serialisation, without any signatures attached.



diff --git a/docs/build/html/api/com.r3corda.core.contracts/-wire-transaction/index.html b/docs/build/html/api/com.r3corda.core.contracts/-wire-transaction/index.html index 5323ea23ff..34d702e991 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-wire-transaction/index.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-wire-transaction/index.html @@ -18,7 +18,7 @@ <init> -WireTransaction(inputs: List<StateRef>, attachments: List<SecureHash>, outputs: List<ContractState>, commands: List<Command>)

Transaction ready for serialisation, without any signatures attached.

+WireTransaction(inputs: List<StateRef>, attachments: List<SecureHash>, outputs: List<TransactionState<ContractState>>, commands: List<Command>, signers: List<PublicKey>, type: TransactionType)

Transaction ready for serialisation, without any signatures attached.

@@ -54,7 +54,7 @@ outputs -val outputs: List<ContractState> +val outputs: List<TransactionState<ContractState>> @@ -62,6 +62,18 @@ val serialized: SerializedBytes<WireTransaction> + + +signers + +val signers: List<PublicKey> + + + +type + +val type: TransactionType +

Functions

diff --git a/docs/build/html/api/com.r3corda.core.contracts/-wire-transaction/outputs.html b/docs/build/html/api/com.r3corda.core.contracts/-wire-transaction/outputs.html index c480b02af7..c40c443489 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/-wire-transaction/outputs.html +++ b/docs/build/html/api/com.r3corda.core.contracts/-wire-transaction/outputs.html @@ -8,7 +8,7 @@

outputs

-val outputs: List<ContractState>
+val outputs: List<TransactionState<ContractState>>


diff --git a/docs/build/html/api/com.r3corda.core.contracts/-wire-transaction/signers.html b/docs/build/html/api/com.r3corda.core.contracts/-wire-transaction/signers.html new file mode 100644 index 0000000000..a7ffee8878 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-wire-transaction/signers.html @@ -0,0 +1,15 @@ + + +WireTransaction.signers - + + + +com.r3corda.core.contracts / WireTransaction / signers
+
+

signers

+ +val signers: List<PublicKey>
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/-wire-transaction/type.html b/docs/build/html/api/com.r3corda.core.contracts/-wire-transaction/type.html new file mode 100644 index 0000000000..80029b131a --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/-wire-transaction/type.html @@ -0,0 +1,15 @@ + + +WireTransaction.type - + + + +com.r3corda.core.contracts / WireTransaction / type
+
+

type

+ +val type: TransactionType
+
+
+ + diff --git a/docs/build/html/api/com.r3corda.core.contracts/currency.html b/docs/build/html/api/com.r3corda.core.contracts/currency.html index 8161420868..8827660e1b 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/currency.html +++ b/docs/build/html/api/com.r3corda.core.contracts/currency.html @@ -9,7 +9,7 @@

currency

fun currency(code: String): Currency
-

Defines a simple domain specific language for the specificiation of financial contracts. Currently covers:

+

Defines a simple domain specific language for the specification of financial contracts. Currently covers:

  • Some utilities for working with commands.

  • Code for working with currencies.

  • An Amount type that represents a positive quantity of a specific currency.

    diff --git a/docs/build/html/api/com.r3corda.core.contracts/index.html b/docs/build/html/api/com.r3corda.core.contracts/index.html index 5fecc707d7..17b5c043b0 100644 --- a/docs/build/html/api/com.r3corda.core.contracts/index.html +++ b/docs/build/html/api/com.r3corda.core.contracts/index.html @@ -45,6 +45,13 @@ of how attachments are meant to be used include:

    +BilateralNettableState + +interface BilateralNettableState<T : BilateralNettableState<T>>

    Interface for state objects that support being netted with other state objects.

    + + + + BusinessCalendar open class BusinessCalendar

    A business calendar performs date calculations that take into account national holidays and weekends. This is a @@ -82,15 +89,9 @@ timestamp attached to the transaction itself i.e. it is NOT necessarily the curr interface ContractState

    A contract state (or just "state") contains opaque data used by a contract program. It can be thought of as a disk file that the program can use to persist data across transactions. States are immutable: once created they are never -updated, instead, any changes must generate a new successor state.

    - - - - -DateOffset - -enum class DateOffset

    Date offset that the fixing is done prior to the accrual start date. -Currently not used in the calculation.

    +updated, instead, any changes must generate a new successor state. States can be updated (consumed) only once: the +notary is responsible for ensuring there is no "double spending" by only signing a transaction if the input states +are all free.

    @@ -142,6 +143,13 @@ implementation of general protocols that manipulate many agreement types.

    +DummyState + +data class DummyState : ContractState

    Dummy state for use in testing. Not part of any real contract.

    + + + + Expression data class Expression

    Represents a textual expression of e.g. a formula

    @@ -198,6 +206,27 @@ from which the state object is initialised.

    +IssueCommand + +interface IssueCommand : CommandData

    A common issue command, to enforce that issue commands have a nonce value.

    + + + + +Issued + +data class Issued<P>

    Definition for an issued product, which can be cash, a cash-like thing, assets, or generally anything else thats +quantifiable with integer quantities.

    + + + + +JavaTestHelpers + +object JavaTestHelpers + + + LedgerTransaction data class LedgerTransaction : NamedByHash

    A LedgerTransaction wraps the data needed to calculate one or more successor states from a set of input states. @@ -214,6 +243,13 @@ with the commands from the wire, and verified/looked up.

    +MoveCommand + +interface MoveCommand : CommandData

    A common move command for contracts which can change owner.

    + + + + NamedByHash interface NamedByHash

    Implemented by anything that can be named by a secure hash value (e.g. transactions, attachments).

    @@ -221,6 +257,14 @@ with the commands from the wire, and verified/looked up.

    +NetType + +enum class NetType

    Enum for the types of netting that can be applied to state objects. Exact behaviour +for each type of netting is left to the contract to determine.

    + + + + OwnableState interface OwnableState : ContractState

    A contract state that can have a single owner.

    @@ -249,6 +293,35 @@ ledger. The reference is intended to be encrypted so its meaningless to anyone o +SchedulableState + +interface SchedulableState : ContractState + + + +Scheduled + +interface Scheduled

    Something which is scheduled to happen at a point in time

    + + + + +ScheduledActivity + +data class ScheduledActivity : Scheduled

    This class represents the lifecycle activity that a contract state of type LinearState would like to perform at a given point in time. +e.g. run a fixing protocol

    + + + + +ScheduledStateRef + +data class ScheduledStateRef : Scheduled

    Represents a contract state (unconsumed output) of type LinearState and a point in time that a lifecycle event is expected to take place +for that contract state.

    + + + + SignedTransaction data class SignedTransaction : NamedByHash

    Container for a WireTransaction and attached signatures.

    @@ -288,10 +361,17 @@ public keys are identified in the containing Comma TransactionBuilder -class TransactionBuilder

    A TransactionBuilder is a transaction class thats mutable (unlike the others which are all immutable). It is -intended to be passed around contracts that may edit it by adding new states/commands or modifying the existing set. -Then once the states and commands are right, this class can be used as a holding bucket to gather signatures from -multiple parties.

    +abstract class TransactionBuilder

    A TransactionBuilder is a transaction class thats mutable (unlike the others which are all immutable). It is +intended to be passed around contracts 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.

    + + + + +TransactionForContract + +data class TransactionForContract

    A transaction to be passed as input to a contract verification function. Defines helper methods to +simplify verification logic in contracts.

    @@ -320,6 +400,21 @@ this subgraph does not contain conflicts and is accepted by the involved contrac +TransactionState + +data class TransactionState<out T : ContractState>

    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.

    + + + + +TransactionType + +sealed class TransactionType

    Defines transaction build & validation logic for a specific transaction type

    + + + + TypeOnlyCommandData abstract class TypeOnlyCommandData : CommandData

    Commands that inherit from this are intended to have no data items: its only their presence that matters.

    @@ -368,6 +463,12 @@ this subgraph does not contain conflicts and is accepted by the involved contrac +java.util.Currency + + + + + kotlin.Double @@ -440,7 +541,7 @@ this subgraph does not contain conflicts and is accepted by the involved contrac currency -fun currency(code: String): Currency

    Defines a simple domain specific language for the specificiation of financial contracts. Currently covers:

    +fun currency(code: String): Currency

    Defines a simple domain specific language for the specification of financial contracts. Currently covers:

    @@ -452,6 +553,12 @@ this subgraph does not contain conflicts and is accepted by the involved contrac +issued by + +infix fun Amount<Currency>.issued by(deposit: PartyAndReference): Amount<Issued<Currency>> + + + requireThat fun <R> requireThat(body: Requirements.() -> R): R @@ -465,9 +572,10 @@ this subgraph does not contain conflicts and is accepted by the involved contrac -verifyMoveCommands +verifyMoveCommand -fun <T : CommandData> verifyMoveCommands(inputs: List<OwnableState>, tx: TransactionForVerification): Unit

    Simple functionality for verifying a move command. Verifies that each input has a signature from its owning key.

    +fun <T : CommandData> verifyMoveCommand(inputs: List<OwnableState>, tx: TransactionForContract): Unit
    +fun <T : CommandData> verifyMoveCommand(inputs: List<OwnableState>, commands: List<AuthenticatedObject<CommandData>>): Unit

    Simple functionality for verifying a move command. Verifies that each input has a signature from its owning key.

    diff --git a/docs/build/html/api/com.r3corda.core.contracts/issued by.html b/docs/build/html/api/com.r3corda.core.contracts/issued by.html new file mode 100644 index 0000000000..15f0831011 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/issued by.html @@ -0,0 +1,15 @@ + + +issued by - + + + +com.r3corda.core.contracts / issued by
    +
    +

    issued by

    + +infix fun Amount<Currency>.issued by(deposit: PartyAndReference): Amount<Issued<Currency>>
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.contracts/java.util.-currency/index.html b/docs/build/html/api/com.r3corda.core.contracts/java.util.-currency/index.html new file mode 100644 index 0000000000..078d92a92b --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/java.util.-currency/index.html @@ -0,0 +1,21 @@ + + +com.r3corda.core.contracts.java.util.Currency - + + + +com.r3corda.core.contracts / java.util.Currency
    +
    +

    Extensions for java.util.Currency

    + + + + + + + +
    +issued by +infix fun Currency.issued by(deposit: PartyAndReference): Issued<Currency>
    + + diff --git a/docs/build/html/api/com.r3corda.core.contracts/java.util.-currency/issued by.html b/docs/build/html/api/com.r3corda.core.contracts/java.util.-currency/issued by.html new file mode 100644 index 0000000000..5e3e67e7c7 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/java.util.-currency/issued by.html @@ -0,0 +1,15 @@ + + +issued by - + + + +com.r3corda.core.contracts / java.util.Currency / issued by
    +
    +

    issued by

    + +infix fun Currency.issued by(deposit: PartyAndReference): Issued<Currency>
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.contracts/verify-move-command.html b/docs/build/html/api/com.r3corda.core.contracts/verify-move-command.html new file mode 100644 index 0000000000..4ea9ee100d --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.contracts/verify-move-command.html @@ -0,0 +1,21 @@ + + +verifyMoveCommand - + + + +com.r3corda.core.contracts / verifyMoveCommand
    +
    +

    verifyMoveCommand

    + +inline fun <reified T : CommandData> verifyMoveCommand(inputs: List<OwnableState>, tx: TransactionForContract): Unit
    + +inline fun <reified T : CommandData> verifyMoveCommand(inputs: List<OwnableState>, commands: List<AuthenticatedObject<CommandData>>): Unit
    +

    Simple functionality for verifying a move command. Verifies that each input has a signature from its owning key.

    +

    Parameters

    + +T - the type of the move command
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.crypto/generate-key-pair.html b/docs/build/html/api/com.r3corda.core.crypto/generate-key-pair.html index cbee03c2dd..b38bd5802b 100644 --- a/docs/build/html/api/com.r3corda.core.crypto/generate-key-pair.html +++ b/docs/build/html/api/com.r3corda.core.crypto/generate-key-pair.html @@ -8,7 +8,7 @@

    generateKeyPair

    -fun generateKeyPair(): KeyPair
    +fun generateKeyPair(): <ERROR CLASS>

    A simple wrapper that will make it easier to swap out the EC algorithm we use in future



    diff --git a/docs/build/html/api/com.r3corda.core.crypto/index.html b/docs/build/html/api/com.r3corda.core.crypto/index.html index 34c0e7c860..26adee50d7 100644 --- a/docs/build/html/api/com.r3corda.core.crypto/index.html +++ b/docs/build/html/api/com.r3corda.core.crypto/index.html @@ -90,11 +90,17 @@ contained within.

    generateKeyPair -fun generateKeyPair(): KeyPair

    A simple wrapper that will make it easier to swap out the EC algorithm we use in future

    +fun generateKeyPair(): <ERROR CLASS>

    A simple wrapper that will make it easier to swap out the EC algorithm we use in future

    +newSecureRandom + +fun newSecureRandom(): SecureRandom + + + sha256 fun OpaqueBytes.sha256(): SHA256 diff --git a/docs/build/html/api/com.r3corda.core.crypto/new-secure-random.html b/docs/build/html/api/com.r3corda.core.crypto/new-secure-random.html new file mode 100644 index 0000000000..b2828bae9e --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.crypto/new-secure-random.html @@ -0,0 +1,15 @@ + + +newSecureRandom - + + + +com.r3corda.core.crypto / newSecureRandom
    +
    +

    newSecureRandom

    + +fun newSecureRandom(): SecureRandom
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.messaging/-ack.html b/docs/build/html/api/com.r3corda.core.messaging/-ack.html new file mode 100644 index 0000000000..4ab479fc9a --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.messaging/-ack.html @@ -0,0 +1,16 @@ + + +Ack - + + + +com.r3corda.core.messaging / Ack
    +
    +

    Ack

    +object Ack : DeserializeAsKotlinObjectDef
    +

    A general Ack message that conveys no content other than its presence for use when you want an acknowledgement +from a recipient. Using Unit can be ambiguous as it is similar to Void and so could mean no response.

    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.messaging/index.html b/docs/build/html/api/com.r3corda.core.messaging/index.html index c997a762b5..c0a7bd6dce 100644 --- a/docs/build/html/api/com.r3corda.core.messaging/index.html +++ b/docs/build/html/api/com.r3corda.core.messaging/index.html @@ -12,6 +12,14 @@ +Ack + +object Ack : DeserializeAsKotlinObjectDef

    A general Ack message that conveys no content other than its presence for use when you want an acknowledgement +from a recipient. Using Unit can be ambiguous as it is similar to Void and so could mean no response.

    + + + + AllPossibleRecipients interface AllPossibleRecipients : MessageRecipients

    A special base class for the set of all possible recipients, without having to identify who they all are.

    diff --git a/docs/build/html/api/com.r3corda.core.node.services.testing/-mock-attachment-storage/index.html b/docs/build/html/api/com.r3corda.core.node.services.testing/-mock-attachment-storage/index.html index 68951a71a0..dd67c061d4 100644 --- a/docs/build/html/api/com.r3corda.core.node.services.testing/-mock-attachment-storage/index.html +++ b/docs/build/html/api/com.r3corda.core.node.services.testing/-mock-attachment-storage/index.html @@ -47,10 +47,8 @@ operation due to the need to copy the bytes to disk and hash them along the way. openAttachment -fun openAttachment(id: SecureHash): Attachment?

    Returns a newly opened stream for the given locally stored attachment, or null if no such attachment is known. -The returned stream must be closed when you are done with it to avoid resource leaks. You should probably wrap -the result in a JarInputStream unless youre sending it somewhere, there is a convenience helper for this -on Attachment.

    +fun openAttachment(id: SecureHash): Attachment?

    Returns a handle to a locally stored attachment, or null if its not known. The handle can be used to open +a stream for the data, which will be a zip/jar file.

    diff --git a/docs/build/html/api/com.r3corda.core.node.services.testing/-mock-attachment-storage/open-attachment.html b/docs/build/html/api/com.r3corda.core.node.services.testing/-mock-attachment-storage/open-attachment.html index 83881f585c..82b57d800d 100644 --- a/docs/build/html/api/com.r3corda.core.node.services.testing/-mock-attachment-storage/open-attachment.html +++ b/docs/build/html/api/com.r3corda.core.node.services.testing/-mock-attachment-storage/open-attachment.html @@ -10,10 +10,8 @@ fun openAttachment(id: SecureHash): Attachment?
    Overrides AttachmentStorage.openAttachment
    -

    Returns a newly opened stream for the given locally stored attachment, or null if no such attachment is known. -The returned stream must be closed when you are done with it to avoid resource leaks. You should probably wrap -the result in a JarInputStream unless youre sending it somewhere, there is a convenience helper for this -on Attachment.

    +

    Returns a handle to a locally stored attachment, or null if its not known. The handle can be used to open +a stream for the data, which will be a zip/jar file.



    diff --git a/docs/build/html/api/com.r3corda.core.node.services.testing/-mock-storage-service/index.html b/docs/build/html/api/com.r3corda.core.node.services.testing/-mock-storage-service/index.html index 720872b62d..d033940e28 100644 --- a/docs/build/html/api/com.r3corda.core.node.services.testing/-mock-storage-service/index.html +++ b/docs/build/html/api/com.r3corda.core.node.services.testing/-mock-storage-service/index.html @@ -7,7 +7,7 @@ com.r3corda.core.node.services.testing / MockStorageService

    MockStorageService

    -class MockStorageService : SingletonSerializeAsToken, StorageService
    +class MockStorageService : SingletonSerializeAsToken, TxWritableStorageService


    Constructors

    diff --git a/docs/build/html/api/com.r3corda.core.node.services.testing/-mock-storage-service/validated-transactions.html b/docs/build/html/api/com.r3corda.core.node.services.testing/-mock-storage-service/validated-transactions.html index 95345c0308..c91ef2bebf 100644 --- a/docs/build/html/api/com.r3corda.core.node.services.testing/-mock-storage-service/validated-transactions.html +++ b/docs/build/html/api/com.r3corda.core.node.services.testing/-mock-storage-service/validated-transactions.html @@ -9,7 +9,7 @@

    validatedTransactions

    val validatedTransactions: TransactionStorage
    -Overrides StorageService.validatedTransactions
    +Overrides TxWritableStorageService.validatedTransactions

    A map of hash->tx where tx has been signature/contract validated and the states are known to be correct. The signatures arent technically needed after that point, but we keep them around so that we can relay the transaction data to other nodes that need it.

    diff --git a/docs/build/html/api/com.r3corda.core.node.services.testing/-mock-transaction-storage/get-transaction.html b/docs/build/html/api/com.r3corda.core.node.services.testing/-mock-transaction-storage/get-transaction.html index ec2be5c7db..e50af76719 100644 --- a/docs/build/html/api/com.r3corda.core.node.services.testing/-mock-transaction-storage/get-transaction.html +++ b/docs/build/html/api/com.r3corda.core.node.services.testing/-mock-transaction-storage/get-transaction.html @@ -9,7 +9,7 @@

    getTransaction

    open fun getTransaction(id: SecureHash): SignedTransaction?
    -Overrides TransactionStorage.getTransaction
    +Overrides ReadOnlyTransactionStorage.getTransaction

    Return the transaction with the given id, or null if no such transaction exists.



    diff --git a/docs/build/html/api/com.r3corda.core.node.services.testing/index.html b/docs/build/html/api/com.r3corda.core.node.services.testing/index.html index 4d41f89fd6..435aae0e05 100644 --- a/docs/build/html/api/com.r3corda.core.node.services.testing/index.html +++ b/docs/build/html/api/com.r3corda.core.node.services.testing/index.html @@ -32,7 +32,7 @@ MockStorageService -class MockStorageService : SingletonSerializeAsToken, StorageService +class MockStorageService : SingletonSerializeAsToken, TxWritableStorageService diff --git a/docs/build/html/api/com.r3corda.core.node.services/-attachment-storage/index.html b/docs/build/html/api/com.r3corda.core.node.services/-attachment-storage/index.html index d3f8a6011c..008415df37 100644 --- a/docs/build/html/api/com.r3corda.core.node.services/-attachment-storage/index.html +++ b/docs/build/html/api/com.r3corda.core.node.services/-attachment-storage/index.html @@ -8,8 +8,7 @@

    AttachmentStorage

    interface AttachmentStorage
    -

    An attachment store records potentially large binary objects, identified by their hash. Note that attachments are -immutable and can never be erased once inserted

    +

    An attachment store records potentially large binary objects, identified by their hash.



    Functions

    @@ -27,10 +26,8 @@ operation due to the need to copy the bytes to disk and hash them along the way. openAttachment -abstract fun openAttachment(id: SecureHash): Attachment?

    Returns a newly opened stream for the given locally stored attachment, or null if no such attachment is known. -The returned stream must be closed when you are done with it to avoid resource leaks. You should probably wrap -the result in a JarInputStream unless youre sending it somewhere, there is a convenience helper for this -on Attachment.

    +abstract fun openAttachment(id: SecureHash): Attachment?

    Returns a handle to a locally stored attachment, or null if its not known. The handle can be used to open +a stream for the data, which will be a zip/jar file.

    diff --git a/docs/build/html/api/com.r3corda.core.node.services/-attachment-storage/open-attachment.html b/docs/build/html/api/com.r3corda.core.node.services/-attachment-storage/open-attachment.html index d39ae99d17..8c8aceecfd 100644 --- a/docs/build/html/api/com.r3corda.core.node.services/-attachment-storage/open-attachment.html +++ b/docs/build/html/api/com.r3corda.core.node.services/-attachment-storage/open-attachment.html @@ -9,10 +9,8 @@

    openAttachment

    abstract fun openAttachment(id: SecureHash): Attachment?
    -

    Returns a newly opened stream for the given locally stored attachment, or null if no such attachment is known. -The returned stream must be closed when you are done with it to avoid resource leaks. You should probably wrap -the result in a JarInputStream unless youre sending it somewhere, there is a convenience helper for this -on Attachment.

    +

    Returns a handle to a locally stored attachment, or null if its not known. The handle can be used to open +a stream for the data, which will be a zip/jar file.



    diff --git a/docs/build/html/api/com.r3corda.core.node.services/-read-only-transaction-storage/get-transaction.html b/docs/build/html/api/com.r3corda.core.node.services/-read-only-transaction-storage/get-transaction.html new file mode 100644 index 0000000000..d9aaeed402 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.node.services/-read-only-transaction-storage/get-transaction.html @@ -0,0 +1,16 @@ + + +ReadOnlyTransactionStorage.getTransaction - + + + +com.r3corda.core.node.services / ReadOnlyTransactionStorage / getTransaction
    +
    +

    getTransaction

    + +abstract fun getTransaction(id: SecureHash): SignedTransaction?
    +

    Return the transaction with the given id, or null if no such transaction exists.

    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.node.services/-read-only-transaction-storage/index.html b/docs/build/html/api/com.r3corda.core.node.services/-read-only-transaction-storage/index.html new file mode 100644 index 0000000000..d48a918cf6 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.node.services/-read-only-transaction-storage/index.html @@ -0,0 +1,39 @@ + + +ReadOnlyTransactionStorage - + + + +com.r3corda.core.node.services / ReadOnlyTransactionStorage
    +
    +

    ReadOnlyTransactionStorage

    +interface ReadOnlyTransactionStorage
    +

    Thread-safe storage of transactions.

    +
    +
    +

    Functions

    + + + + + + + +
    +getTransaction +abstract fun getTransaction(id: SecureHash): SignedTransaction?

    Return the transaction with the given id, or null if no such transaction exists.

    +
    +

    Inheritors

    + + + + + + + +
    +TransactionStorage +interface TransactionStorage : ReadOnlyTransactionStorage

    Thread-safe storage of transactions.

    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.node.services/-scheduler-service/index.html b/docs/build/html/api/com.r3corda.core.node.services/-scheduler-service/index.html new file mode 100644 index 0000000000..45874f344b --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.node.services/-scheduler-service/index.html @@ -0,0 +1,53 @@ + + +SchedulerService - + + + +com.r3corda.core.node.services / SchedulerService
    +
    +

    SchedulerService

    +interface SchedulerService
    +

    Provides access to schedule activity at some point in time. This interface might well be expanded to +increase the feature set in the future.

    +

    If the point in time is in the past, the expectation is that the activity will happen shortly after it is scheduled.

    +

    The main consumer initially is an observer of the wallet to schedule activities based on transactions as they are +recorded.

    +
    +
    +
    +
    +

    Functions

    + + + + + + + + + + + +
    +scheduleStateActivity +abstract fun scheduleStateActivity(action: ScheduledStateRef): Unit

    Schedule a new activity for a TX output, probably because it was just produced.

    +
    +unscheduleStateActivity +abstract fun unscheduleStateActivity(ref: StateRef): Unit

    Unschedule all activity for a TX output, probably because it was consumed.

    +
    +

    Inheritors

    + + + + + + + +
    +NodeSchedulerService +class NodeSchedulerService : SchedulerService, SingletonSerializeAsToken

    A first pass of a simple SchedulerService that works with MutableClocks for testing, demonstrations and simulations +that also encompasses the Wallet observer for processing transactions.

    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.node.services/-scheduler-service/schedule-state-activity.html b/docs/build/html/api/com.r3corda.core.node.services/-scheduler-service/schedule-state-activity.html new file mode 100644 index 0000000000..01eb9b8b8c --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.node.services/-scheduler-service/schedule-state-activity.html @@ -0,0 +1,20 @@ + + +SchedulerService.scheduleStateActivity - + + + +com.r3corda.core.node.services / SchedulerService / scheduleStateActivity
    +
    +

    scheduleStateActivity

    + +abstract fun scheduleStateActivity(action: ScheduledStateRef): Unit
    +

    Schedule a new activity for a TX output, probably because it was just produced.

    +

    Only one activity can be scheduled for a particular StateRef at any one time. Scheduling a ScheduledStateRef +replaces any previously scheduled ScheduledStateRef for any one StateRef.

    +
    +
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.node.services/-scheduler-service/unschedule-state-activity.html b/docs/build/html/api/com.r3corda.core.node.services/-scheduler-service/unschedule-state-activity.html new file mode 100644 index 0000000000..8ce0c44839 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.node.services/-scheduler-service/unschedule-state-activity.html @@ -0,0 +1,16 @@ + + +SchedulerService.unscheduleStateActivity - + + + +com.r3corda.core.node.services / SchedulerService / unscheduleStateActivity
    +
    +

    unscheduleStateActivity

    + +abstract fun unscheduleStateActivity(ref: StateRef): Unit
    +

    Unschedule all activity for a TX output, probably because it was consumed.

    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.node.services/-storage-service/index.html b/docs/build/html/api/com.r3corda.core.node.services/-storage-service/index.html index 6476695f86..31570ced80 100644 --- a/docs/build/html/api/com.r3corda.core.node.services/-storage-service/index.html +++ b/docs/build/html/api/com.r3corda.core.node.services/-storage-service/index.html @@ -41,7 +41,7 @@ first installed.

    validatedTransactions -abstract val validatedTransactions: TransactionStorage

    A map of hash->tx where tx has been signature/contract validated and the states are known to be correct. +abstract val validatedTransactions: ReadOnlyTransactionStorage

    A map of hash->tx where tx has been signature/contract validated and the states are known to be correct. The signatures arent technically needed after that point, but we keep them around so that we can relay the transaction data to other nodes that need it.

    @@ -53,15 +53,10 @@ the transaction data to other nodes that need it.

    -MockStorageService +TxWritableStorageService -class MockStorageService : SingletonSerializeAsToken, StorageService - - - -StorageServiceImpl - -open class StorageServiceImpl : SingletonSerializeAsToken, StorageService +interface TxWritableStorageService : StorageService

    Storage service, with extensions to allow validated transactions to be added to. For use only within ServiceHub.

    + diff --git a/docs/build/html/api/com.r3corda.core.node.services/-storage-service/validated-transactions.html b/docs/build/html/api/com.r3corda.core.node.services/-storage-service/validated-transactions.html index 9da34f2922..71a78bb151 100644 --- a/docs/build/html/api/com.r3corda.core.node.services/-storage-service/validated-transactions.html +++ b/docs/build/html/api/com.r3corda.core.node.services/-storage-service/validated-transactions.html @@ -8,7 +8,7 @@

    validatedTransactions

    -abstract val validatedTransactions: TransactionStorage
    +abstract val validatedTransactions: ReadOnlyTransactionStorage

    A map of hash->tx where tx has been signature/contract validated and the states are known to be correct. The signatures arent technically needed after that point, but we keep them around so that we can relay the transaction data to other nodes that need it.

    diff --git a/docs/build/html/api/com.r3corda.core.node.services/-transaction-storage/index.html b/docs/build/html/api/com.r3corda.core.node.services/-transaction-storage/index.html index d03a4902ea..8fbaa5dcdb 100644 --- a/docs/build/html/api/com.r3corda.core.node.services/-transaction-storage/index.html +++ b/docs/build/html/api/com.r3corda.core.node.services/-transaction-storage/index.html @@ -7,7 +7,7 @@ com.r3corda.core.node.services / TransactionStorage

    TransactionStorage

    -interface TransactionStorage
    +interface TransactionStorage : ReadOnlyTransactionStorage

    Thread-safe storage of transactions.



    @@ -22,11 +22,16 @@ overwritten.

    + + +

    Inherited Functions

    + + +getTransaction diff --git a/docs/build/html/api/com.r3corda.core.node.services/-tx-writable-storage-service/index.html b/docs/build/html/api/com.r3corda.core.node.services/-tx-writable-storage-service/index.html new file mode 100644 index 0000000000..afdc8ad5bd --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.node.services/-tx-writable-storage-service/index.html @@ -0,0 +1,72 @@ + + +TxWritableStorageService - + + + +com.r3corda.core.node.services / TxWritableStorageService
    +
    +

    TxWritableStorageService

    +interface TxWritableStorageService : StorageService
    +

    Storage service, with extensions to allow validated transactions to be added to. For use only within ServiceHub.

    +
    +
    +

    Properties

    +
    -getTransaction -abstract fun getTransaction(id: SecureHash): SignedTransaction?

    Return the transaction with the given id, or null if no such transaction exists.

    +abstract fun getTransaction(id: SecureHash): SignedTransaction?

    Return the transaction with the given id, or null if no such transaction exists.

    + + + + + + +
    +validatedTransactions +abstract val validatedTransactions: TransactionStorage

    A map of hash->tx where tx has been signature/contract validated and the states are known to be correct. +The signatures arent technically needed after that point, but we keep them around so that we can relay +the transaction data to other nodes that need it.

    +
    +

    Inherited Properties

    + + + + + + + + + + + + + + + +
    +attachments +abstract val attachments: AttachmentStorage

    Provides access to storage of arbitrary JAR files (which may contain only data, no code).

    +
    +myLegalIdentity +abstract val myLegalIdentity: Party

    Returns the legal identity that this node is configured with. Assumed to be initialised when the node is +first installed.

    +
    +myLegalIdentityKey +abstract val myLegalIdentityKey: KeyPair
    +

    Inheritors

    + + + + + + + + + + + +
    +MockStorageService +class MockStorageService : SingletonSerializeAsToken, TxWritableStorageService
    +StorageServiceImpl +open class StorageServiceImpl : SingletonSerializeAsToken, TxWritableStorageService
    + + diff --git a/docs/build/html/api/com.r3corda.core.node.services/-tx-writable-storage-service/validated-transactions.html b/docs/build/html/api/com.r3corda.core.node.services/-tx-writable-storage-service/validated-transactions.html new file mode 100644 index 0000000000..5e2ecae0c3 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.node.services/-tx-writable-storage-service/validated-transactions.html @@ -0,0 +1,19 @@ + + +TxWritableStorageService.validatedTransactions - + + + +com.r3corda.core.node.services / TxWritableStorageService / validatedTransactions
    +
    +

    validatedTransactions

    + +abstract val validatedTransactions: TransactionStorage
    +Overrides StorageService.validatedTransactions
    +

    A map of hash->tx where tx has been signature/contract validated and the states are known to be correct. +The signatures arent technically needed after that point, but we keep them around so that we can relay +the transaction data to other nodes that need it.

    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.node.services/-uniqueness-provider/commit.html b/docs/build/html/api/com.r3corda.core.node.services/-uniqueness-provider/commit.html index 9a37fd6072..e52620df81 100644 --- a/docs/build/html/api/com.r3corda.core.node.services/-uniqueness-provider/commit.html +++ b/docs/build/html/api/com.r3corda.core.node.services/-uniqueness-provider/commit.html @@ -7,8 +7,8 @@ com.r3corda.core.node.services / UniquenessProvider / commit

    commit

    - -abstract fun commit(tx: WireTransaction, callerIdentity: Party): Unit
    + +abstract fun commit(states: List<StateRef>, txId: SecureHash, callerIdentity: Party): Unit

    Commits all input states of the given transaction



    diff --git a/docs/build/html/api/com.r3corda.core.node.services/-uniqueness-provider/index.html b/docs/build/html/api/com.r3corda.core.node.services/-uniqueness-provider/index.html index b0659ef567..a76462c1ab 100644 --- a/docs/build/html/api/com.r3corda.core.node.services/-uniqueness-provider/index.html +++ b/docs/build/html/api/com.r3corda.core.node.services/-uniqueness-provider/index.html @@ -39,7 +39,7 @@ the caller identity requesting the commit

    commit -abstract fun commit(tx: WireTransaction, callerIdentity: Party): Unit

    Commits all input states of the given transaction

    +abstract fun commit(states: List<StateRef>, txId: SecureHash, callerIdentity: Party): Unit

    Commits all input states of the given transaction

    diff --git a/docs/build/html/api/com.r3corda.core.node.services/-wallet-service/index.html b/docs/build/html/api/com.r3corda.core.node.services/-wallet-service/index.html index 68504524cf..34505ae7e1 100644 --- a/docs/build/html/api/com.r3corda.core.node.services/-wallet-service/index.html +++ b/docs/build/html/api/com.r3corda.core.node.services/-wallet-service/index.html @@ -19,14 +19,6 @@ consumed by someone else first

    -cashBalances - -abstract val cashBalances: Map<Currency, Amount<Currency>>

    Returns a snapshot of how much cash we have in each currency, ignoring details like issuer. Note: currencies for -which we have no cash evaluate to null, not 0.

    - - - - currentWallet abstract val currentWallet: Wallet

    Returns a read-only snapshot of the wallet at the time the call is made. Note that if you consume states or @@ -79,7 +71,14 @@ new states that they create. You should only insert transactions that have been statesForRefs -open fun statesForRefs(refs: List<StateRef>): Map<StateRef, ContractState?> +open fun statesForRefs(refs: List<StateRef>): Map<StateRef, TransactionState<*>?> + + + +whenConsumed + +open fun whenConsumed(ref: StateRef): <ERROR CLASS><Update>

    Provide a Future for when a StateRef is consumed, which can be very useful in building tests.

    + @@ -99,9 +98,9 @@ new states that they create. You should only insert transactions that have been -NodeWalletService +InMemoryWalletService -class NodeWalletService : SingletonSerializeAsToken, WalletService

    This class implements a simple, in memory wallet that tracks states that are owned by us, and also has a convenience +open class InMemoryWalletService : SingletonSerializeAsToken, WalletService

    This class implements a simple, in memory wallet that tracks states that are owned by us, and also has a convenience method to auto-generate some self-issued cash states that can be used for test trading. A real wallet would persist states relevant to us into a database and once such a wallet is implemented, this scaffolding can be removed.

    diff --git a/docs/build/html/api/com.r3corda.core.node.services/-wallet-service/states-for-refs.html b/docs/build/html/api/com.r3corda.core.node.services/-wallet-service/states-for-refs.html index 879e850f2a..455112fee1 100644 --- a/docs/build/html/api/com.r3corda.core.node.services/-wallet-service/states-for-refs.html +++ b/docs/build/html/api/com.r3corda.core.node.services/-wallet-service/states-for-refs.html @@ -8,7 +8,7 @@

    statesForRefs

    -open fun statesForRefs(refs: List<StateRef>): Map<StateRef, ContractState?>
    +open fun statesForRefs(refs: List<StateRef>): Map<StateRef, TransactionState<*>?>


    diff --git a/docs/build/html/api/com.r3corda.core.node.services/-wallet-service/when-consumed.html b/docs/build/html/api/com.r3corda.core.node.services/-wallet-service/when-consumed.html new file mode 100644 index 0000000000..60012714d5 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.node.services/-wallet-service/when-consumed.html @@ -0,0 +1,16 @@ + + +WalletService.whenConsumed - + + + +com.r3corda.core.node.services / WalletService / whenConsumed
    +
    +

    whenConsumed

    + +open fun whenConsumed(ref: StateRef): <ERROR CLASS><Update>
    +

    Provide a Future for when a StateRef is consumed, which can be very useful in building tests.

    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.node.services/-wallet/-init-.html b/docs/build/html/api/com.r3corda.core.node.services/-wallet/-init-.html index b677b4c24c..132d9e3ea2 100644 --- a/docs/build/html/api/com.r3corda.core.node.services/-wallet/-init-.html +++ b/docs/build/html/api/com.r3corda.core.node.services/-wallet/-init-.html @@ -7,12 +7,15 @@ com.r3corda.core.node.services / Wallet / <init>

    <init>

    -Wallet()
    +Wallet(states: List<StateAndRef<ContractState>>)

    A wallet (name may be temporary) wraps a set of states that are useful for us to keep track of, for instance, because we own them. This class represents an immutable, stable state of a wallet: it is guaranteed not to change out from underneath you, even though the canonical currently-best-known wallet may change as we learn about new transactions from our peers and generate new transactions that consume states ourselves.

    -

    This absract class has no references to Cash contracts.

    +

    This abstract class has no references to Cash contracts.

    +

    states Holds the list of states that are active and relevant. +Active means they havent been consumed yet (or we dont know about it). +Relevant means they contain at least one of our pubkeys




    diff --git a/docs/build/html/api/com.r3corda.core.node.services/-wallet/index.html b/docs/build/html/api/com.r3corda.core.node.services/-wallet/index.html index ffca4a47e5..eb3084d5cb 100644 --- a/docs/build/html/api/com.r3corda.core.node.services/-wallet/index.html +++ b/docs/build/html/api/com.r3corda.core.node.services/-wallet/index.html @@ -7,12 +7,15 @@ com.r3corda.core.node.services / Wallet

    Wallet

    -abstract class Wallet
    +class Wallet

    A wallet (name may be temporary) wraps a set of states that are useful for us to keep track of, for instance, because we own them. This class represents an immutable, stable state of a wallet: it is guaranteed not to change out from underneath you, even though the canonical currently-best-known wallet may change as we learn about new transactions from our peers and generate new transactions that consume states ourselves.

    -

    This absract class has no references to Cash contracts.

    +

    This abstract class has no references to Cash contracts.

    +

    states Holds the list of states that are active and relevant. +Active means they havent been consumed yet (or we dont know about it). +Relevant means they contain at least one of our pubkeys




    @@ -38,7 +41,7 @@ or transactions observed and the Wallet.

    <init> -Wallet()

    A wallet (name may be temporary) wraps a set of states that are useful for us to keep track of, for instance, +Wallet(states: List<StateAndRef<ContractState>>)

    A wallet (name may be temporary) wraps a set of states that are useful for us to keep track of, for instance, because we own them. This class represents an immutable, stable state of a wallet: it is guaranteed not to change out from underneath you, even though the canonical currently-best-known wallet may change as we learn about new transactions from our peers and generate new transactions that consume states ourselves.

    @@ -51,17 +54,9 @@ about new transactions from our peers and generate new transactions that consume -cashBalances - -abstract val cashBalances: Map<Currency, Amount<Currency>>

    Returns a map of how much cash we have in each currency, ignoring details like issuer. Note: currencies for -which we have no cash evaluate to null (not present in map), not 0.

    - - - - states -abstract val states: List<StateAndRef<ContractState>> +val states: List<StateAndRef<ContractState>> @@ -87,20 +82,29 @@ which we have no cash evaluate to null (not present in map), not 0.

    -

    Inheritors

    +

    Extension Properties

    +cashBalances
    -WalletImpl -class WalletImpl : Wallet

    A wallet (name may be temporary) wraps a set of states that are useful for us to keep track of, for instance, -because we own them. This class represents an immutable, stable state of a wallet: it is guaranteed not to -change out from underneath you, even though the canonical currently-best-known wallet may change as we learn -about new transactions from our peers and generate new transactions that consume states ourselves.

    +val Wallet.cashBalances: Map<Currency, Amount<Currency>>

    Returns a map of how much cash we have in each currency, ignoring details like issuer. Note: currencies for +which we have no cash evaluate to null (not present in map), not 0.

    +

    Companion Object Extension Properties

    + + + + + + + +
    +clashingThreads +val Wallet.clashingThreads: Set<SecureHash>
    diff --git a/docs/build/html/api/com.r3corda.core.node.services/-wallet/states.html b/docs/build/html/api/com.r3corda.core.node.services/-wallet/states.html index a7759e18b8..00e945e833 100644 --- a/docs/build/html/api/com.r3corda.core.node.services/-wallet/states.html +++ b/docs/build/html/api/com.r3corda.core.node.services/-wallet/states.html @@ -8,7 +8,7 @@

    states

    -abstract val states: List<StateAndRef<ContractState>>
    +val states: List<StateAndRef<ContractState>>


    diff --git a/docs/build/html/api/com.r3corda.core.node.services/index.html b/docs/build/html/api/com.r3corda.core.node.services/index.html index 50447bd74b..1731fddb92 100644 --- a/docs/build/html/api/com.r3corda.core.node.services/index.html +++ b/docs/build/html/api/com.r3corda.core.node.services/index.html @@ -14,8 +14,7 @@ AttachmentStorage -interface AttachmentStorage

    An attachment store records potentially large binary objects, identified by their hash. Note that attachments are -immutable and can never be erased once inserted

    +interface AttachmentStorage

    An attachment store records potentially large binary objects, identified by their hash.

    @@ -47,6 +46,21 @@ with a specified network map service, which it fetches data from and then subscr +ReadOnlyTransactionStorage + +interface ReadOnlyTransactionStorage

    Thread-safe storage of transactions.

    + + + + +SchedulerService + +interface SchedulerService

    Provides access to schedule activity at some point in time. This interface might well be expanded to +increase the feature set in the future.

    + + + + ServiceType abstract class ServiceType

    Identifier for service types a node can expose over the network to other peers. These types are placed into network @@ -74,7 +88,14 @@ anything like that, this interface is only big enough to support the prototyping TransactionStorage -interface TransactionStorage

    Thread-safe storage of transactions.

    +interface TransactionStorage : ReadOnlyTransactionStorage

    Thread-safe storage of transactions.

    + + + + +TxWritableStorageService + +interface TxWritableStorageService : StorageService

    Storage service, with extensions to allow validated transactions to be added to. For use only within ServiceHub.

    @@ -89,7 +110,7 @@ if any of the inputs have already been used in another transaction

    Wallet -abstract class Wallet

    A wallet (name may be temporary) wraps a set of states that are useful for us to keep track of, for instance, +class Wallet

    A wallet (name may be temporary) wraps a set of states that are useful for us to keep track of, for instance, because we own them. This class represents an immutable, stable state of a wallet: it is guaranteed not to change out from underneath you, even though the canonical currently-best-known wallet may change as we learn about new transactions from our peers and generate new transactions that consume states ourselves.

    diff --git a/docs/build/html/api/com.r3corda.core.node/-service-hub/index.html b/docs/build/html/api/com.r3corda.core.node/-service-hub/index.html index 80d113581d..51888af6c6 100644 --- a/docs/build/html/api/com.r3corda.core.node/-service-hub/index.html +++ b/docs/build/html/api/com.r3corda.core.node/-service-hub/index.html @@ -52,6 +52,12 @@ state from being serialized in checkpoints.

    +schedulerService + +abstract val schedulerService: SchedulerService + + + storageService abstract val storageService: StorageService @@ -71,14 +77,16 @@ state from being serialized in checkpoints.

    loadState -open fun loadState(stateRef: StateRef): ContractState

    Given a StateRef loads the referenced transaction and looks up the specified output ContractState

    +open fun loadState(stateRef: StateRef): TransactionState<*>

    Given a StateRef loads the referenced transaction and looks up the specified output ContractState

    recordTransactions -open fun recordTransactions(txs: List<SignedTransaction>): Unit

    Given a list of SignedTransactions, writes them to the local storage for validated transactions and then +abstract fun recordTransactions(txs: Iterable<SignedTransaction>): Unit

    Given a list of SignedTransactions, writes them to the local storage for validated transactions and then +sends them to the wallet for further processing.

    +open fun recordTransactions(vararg txs: SignedTransaction): <ERROR CLASS>

    Given some SignedTransactions, writes them to the local storage for validated transactions and then sends them to the wallet for further processing.

    @@ -93,6 +101,19 @@ transaction. If no exception is thrown, the transaction is valid.

    +

    Extension Functions

    + + + + + + + +
    +fillWithSomeTestCash +fun ServiceHub.fillWithSomeTestCash(howMuch: Amount<Currency>, notary: Party = DUMMY_NOTARY, atLeastThisManyStates: Int = 3, atMostThisManyStates: Int = 10, rng: Random = Random(), ref: OpaqueBytes = OpaqueBytes(ByteArray(1, { 0 }))): Wallet

    Creates a random set of between (by default) 3 and 10 cash states that add up to the given amount and adds them +to the wallet. This is intended for unit tests.

    +

    Inheritors

    @@ -100,7 +121,7 @@ transaction. If no exception is thrown, the transaction is valid.

    +abstract class ServiceHubInternal : ServiceHub
    ServiceHubInternal -interface ServiceHubInternal : ServiceHub
    diff --git a/docs/build/html/api/com.r3corda.core.node/-service-hub/load-state.html b/docs/build/html/api/com.r3corda.core.node/-service-hub/load-state.html index 9ea5448d29..72652b2df8 100644 --- a/docs/build/html/api/com.r3corda.core.node/-service-hub/load-state.html +++ b/docs/build/html/api/com.r3corda.core.node/-service-hub/load-state.html @@ -8,7 +8,7 @@

    loadState

    -open fun loadState(stateRef: StateRef): ContractState
    +open fun loadState(stateRef: StateRef): TransactionState<*>

    Given a StateRef loads the referenced transaction and looks up the specified output ContractState

    Exceptions

    diff --git a/docs/build/html/api/com.r3corda.core.node/-service-hub/record-transactions.html b/docs/build/html/api/com.r3corda.core.node/-service-hub/record-transactions.html index 0b1b605ee6..70b19b6fa5 100644 --- a/docs/build/html/api/com.r3corda.core.node/-service-hub/record-transactions.html +++ b/docs/build/html/api/com.r3corda.core.node/-service-hub/record-transactions.html @@ -7,13 +7,19 @@ com.r3corda.core.node / ServiceHub / recordTransactions

    recordTransactions

    - -open fun recordTransactions(txs: List<SignedTransaction>): Unit
    + +abstract fun recordTransactions(txs: Iterable<SignedTransaction>): Unit

    Given a list of SignedTransactions, writes them to the local storage for validated transactions and then sends them to the wallet for further processing.

    -

    TODO: Need to come up with a way for preventing transactions being written other than by this method.

    +

    Parameters

    + +txs - The transactions to record


    + +open fun recordTransactions(vararg txs: SignedTransaction): <ERROR CLASS>
    +

    Given some SignedTransactions, writes them to the local storage for validated transactions and then +sends them to the wallet for further processing.

    Parameters

    txs - The transactions to record
    diff --git a/docs/build/html/api/com.r3corda.core.node/-service-hub/scheduler-service.html b/docs/build/html/api/com.r3corda.core.node/-service-hub/scheduler-service.html new file mode 100644 index 0000000000..8c1d545883 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.node/-service-hub/scheduler-service.html @@ -0,0 +1,15 @@ + + +ServiceHub.schedulerService - + + + +com.r3corda.core.node / ServiceHub / schedulerService
    +
    +

    schedulerService

    + +abstract val schedulerService: SchedulerService
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.protocols/-app-context/-init-.html b/docs/build/html/api/com.r3corda.core.protocols/-app-context/-init-.html new file mode 100644 index 0000000000..7f3939f4b5 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.protocols/-app-context/-init-.html @@ -0,0 +1,16 @@ + + +AppContext.<init> - + + + +com.r3corda.core.protocols / AppContext / <init>
    +
    +

    <init>

    +AppContext(attachments: List<SecureHash>)
    +

    This is just some way to track what attachments need to be in the class loader, but may later include some app +properties loaded from the attachments. And perhaps the authenticated user for an API call?

    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.protocols/-app-context/attachments.html b/docs/build/html/api/com.r3corda.core.protocols/-app-context/attachments.html new file mode 100644 index 0000000000..4c8bde1693 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.protocols/-app-context/attachments.html @@ -0,0 +1,15 @@ + + +AppContext.attachments - + + + +com.r3corda.core.protocols / AppContext / attachments
    +
    +

    attachments

    + +val attachments: List<SecureHash>
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.protocols/-app-context/class-loader.html b/docs/build/html/api/com.r3corda.core.protocols/-app-context/class-loader.html new file mode 100644 index 0000000000..d3da155f97 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.protocols/-app-context/class-loader.html @@ -0,0 +1,15 @@ + + +AppContext.classLoader - + + + +com.r3corda.core.protocols / AppContext / classLoader
    +
    +

    classLoader

    + +val classLoader: ClassLoader
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.protocols/-app-context/index.html b/docs/build/html/api/com.r3corda.core.protocols/-app-context/index.html new file mode 100644 index 0000000000..4ceb94f3e3 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.protocols/-app-context/index.html @@ -0,0 +1,46 @@ + + +AppContext - + + + +com.r3corda.core.protocols / AppContext
    +
    +

    AppContext

    +data class AppContext
    +

    This is just some way to track what attachments need to be in the class loader, but may later include some app +properties loaded from the attachments. And perhaps the authenticated user for an API call?

    +
    +
    +

    Constructors

    + + + + + + + +
    +<init> +AppContext(attachments: List<SecureHash>)

    This is just some way to track what attachments need to be in the class loader, but may later include some app +properties loaded from the attachments. And perhaps the authenticated user for an API call?

    +
    +

    Properties

    + + + + + + + + + + + +
    +attachments +val attachments: List<SecureHash>
    +classLoader +val classLoader: ClassLoader
    + + diff --git a/docs/build/html/api/com.r3corda.core.protocols/-illegal-protocol-logic-exception/-init-.html b/docs/build/html/api/com.r3corda.core.protocols/-illegal-protocol-logic-exception/-init-.html new file mode 100644 index 0000000000..3b3ce12894 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.protocols/-illegal-protocol-logic-exception/-init-.html @@ -0,0 +1,14 @@ + + +IllegalProtocolLogicException.<init> - + + + +com.r3corda.core.protocols / IllegalProtocolLogicException / <init>
    +
    +

    <init>

    +IllegalProtocolLogicException(type: Class<*>, msg: String)
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.protocols/-illegal-protocol-logic-exception/index.html b/docs/build/html/api/com.r3corda.core.protocols/-illegal-protocol-logic-exception/index.html new file mode 100644 index 0000000000..daccd9c4d8 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.protocols/-illegal-protocol-logic-exception/index.html @@ -0,0 +1,25 @@ + + +IllegalProtocolLogicException - + + + +com.r3corda.core.protocols / IllegalProtocolLogicException
    +
    +

    IllegalProtocolLogicException

    +class IllegalProtocolLogicException : IllegalArgumentException
    +
    +
    +

    Constructors

    + + + + + + + +
    +<init> +IllegalProtocolLogicException(type: Class<*>, msg: String)
    + + diff --git a/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic-ref-factory/-init-.html b/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic-ref-factory/-init-.html new file mode 100644 index 0000000000..c2e8360e32 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic-ref-factory/-init-.html @@ -0,0 +1,26 @@ + + +ProtocolLogicRefFactory.<init> - + + + +com.r3corda.core.protocols / ProtocolLogicRefFactory / <init>
    +
    +

    <init>

    +ProtocolLogicRefFactory()
    +
    +
    +ProtocolLogicRefFactory(protocolLogicClassNameWhitelist: Set<String>, argsClassNameWhitelist: Set<String>)
    +

    A class for conversion to and from ProtocolLogic and ProtocolLogicRef instances

    +

    Validation of types is performed on the way in and way out in case this object is passed between JVMs which might have differing +whitelists.

    +

    TODO: Ways to populate whitelist of "blessed" protocols per node/party +TODO: Ways to populate argument types whitelist. Per node/party or global? +TODO: Align with API related logic for passing in ProtocolLogic references (ProtocolRef) +TODO: Actual support for AppContext / AttachmentsClassLoader

    +
    +
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic-ref-factory/create-kotlin.html b/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic-ref-factory/create-kotlin.html new file mode 100644 index 0000000000..bcdf3e2429 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic-ref-factory/create-kotlin.html @@ -0,0 +1,19 @@ + + +ProtocolLogicRefFactory.createKotlin - + + + +com.r3corda.core.protocols / ProtocolLogicRefFactory / createKotlin
    +
    +

    createKotlin

    + +fun createKotlin(type: Class<out ProtocolLogic<*>>, args: Map<String, Any?>): ProtocolLogicRef
    +

    Create a ProtocolLogicRef by trying to find a Kotlin constructor that matches the given args.

    +

    TODO: Rethink language specific naming.

    +
    +
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic-ref-factory/create.html b/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic-ref-factory/create.html new file mode 100644 index 0000000000..bfef9758d2 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic-ref-factory/create.html @@ -0,0 +1,16 @@ + + +ProtocolLogicRefFactory.create - + + + +com.r3corda.core.protocols / ProtocolLogicRefFactory / create
    +
    +

    create

    + +fun create(type: Class<out ProtocolLogic<*>>, vararg args: Any?): ProtocolLogicRef
    +

    Create a ProtocolLogicRef for the Kotlin primary constructor or Java constructor and the given args.

    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic-ref-factory/index.html b/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic-ref-factory/index.html new file mode 100644 index 0000000000..f14b826acf --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic-ref-factory/index.html @@ -0,0 +1,71 @@ + + +ProtocolLogicRefFactory - + + + +com.r3corda.core.protocols / ProtocolLogicRefFactory
    +
    +

    ProtocolLogicRefFactory

    +class ProtocolLogicRefFactory : SingletonSerializeAsToken
    +

    A class for conversion to and from ProtocolLogic and ProtocolLogicRef instances

    +

    Validation of types is performed on the way in and way out in case this object is passed between JVMs which might have differing +whitelists.

    +

    TODO: Ways to populate whitelist of "blessed" protocols per node/party +TODO: Ways to populate argument types whitelist. Per node/party or global? +TODO: Align with API related logic for passing in ProtocolLogic references (ProtocolRef) +TODO: Actual support for AppContext / AttachmentsClassLoader

    +
    +
    +
    +
    +

    Constructors

    + + + + + + + +
    +<init> +ProtocolLogicRefFactory()ProtocolLogicRefFactory(protocolLogicClassNameWhitelist: Set<String>, argsClassNameWhitelist: Set<String>)

    A class for conversion to and from ProtocolLogic and ProtocolLogicRef instances

    +
    +

    Functions

    + + + + + + + + + + + + + + + +
    +create +fun create(type: Class<out ProtocolLogic<*>>, vararg args: Any?): ProtocolLogicRef

    Create a ProtocolLogicRef for the Kotlin primary constructor or Java constructor and the given args.

    +
    +createKotlin +fun createKotlin(type: Class<out ProtocolLogic<*>>, args: Map<String, Any?>): ProtocolLogicRef

    Create a ProtocolLogicRef by trying to find a Kotlin constructor that matches the given args.

    +
    +toProtocolLogic +fun toProtocolLogic(ref: ProtocolLogicRef): ProtocolLogic<*>
    +

    Inherited Functions

    + + + + + + + +
    +toToken +open fun toToken(context: SerializeAsTokenContext): SerializationToken
    + + diff --git a/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic-ref-factory/to-protocol-logic.html b/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic-ref-factory/to-protocol-logic.html new file mode 100644 index 0000000000..22cad2ce08 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic-ref-factory/to-protocol-logic.html @@ -0,0 +1,15 @@ + + +ProtocolLogicRefFactory.toProtocolLogic - + + + +com.r3corda.core.protocols / ProtocolLogicRefFactory / toProtocolLogic
    +
    +

    toProtocolLogic

    + +fun toProtocolLogic(ref: ProtocolLogicRef): ProtocolLogic<*>
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic-ref/app-context.html b/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic-ref/app-context.html new file mode 100644 index 0000000000..5feed5296a --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic-ref/app-context.html @@ -0,0 +1,15 @@ + + +ProtocolLogicRef.appContext - + + + +com.r3corda.core.protocols / ProtocolLogicRef / appContext
    +
    +

    appContext

    + +val appContext: AppContext
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic-ref/args.html b/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic-ref/args.html new file mode 100644 index 0000000000..8610f882a1 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic-ref/args.html @@ -0,0 +1,15 @@ + + +ProtocolLogicRef.args - + + + +com.r3corda.core.protocols / ProtocolLogicRef / args
    +
    +

    args

    + +val args: Map<String, Any?>
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic-ref/index.html b/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic-ref/index.html new file mode 100644 index 0000000000..570352d5d2 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic-ref/index.html @@ -0,0 +1,41 @@ + + +ProtocolLogicRef - + + + +com.r3corda.core.protocols / ProtocolLogicRef
    +
    +

    ProtocolLogicRef

    +data class ProtocolLogicRef
    +

    A class representing a ProtocolLogic instance which would be possible to safely pass out of the contract sandbox

    +

    Only allows a String reference to the ProtocolLogic class, and only allows restricted argument types as per ProtocolLogicRefFactory

    +
    +
    +
    +
    +

    Properties

    + + + + + + + + + + + + + + + +
    +appContext +val appContext: AppContext
    +args +val args: Map<String, Any?>
    +protocolLogicClassName +val protocolLogicClassName: String
    + + diff --git a/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic-ref/protocol-logic-class-name.html b/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic-ref/protocol-logic-class-name.html new file mode 100644 index 0000000000..9cc5eb55ca --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic-ref/protocol-logic-class-name.html @@ -0,0 +1,15 @@ + + +ProtocolLogicRef.protocolLogicClassName - + + + +com.r3corda.core.protocols / ProtocolLogicRef / protocolLogicClassName
    +
    +

    protocolLogicClassName

    + +val protocolLogicClassName: String
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic/index.html b/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic/index.html index 25dd4ce6d3..3ad85c9833 100644 --- a/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic/index.html +++ b/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic/index.html @@ -69,7 +69,9 @@ progress.

    serviceHub -val serviceHub: ServiceHub

    Provides access to big, heavy classes that may be reconstructed from time to time, e.g. across restarts

    +val serviceHub: ServiceHub

    Provides access to big, heavy classes that may be reconstructed from time to time, e.g. across restarts. It is +only available once the protocol has started, which means it cannnot be accessed in the constructor. Either +access this lazily or from inside call.

    @@ -95,13 +97,13 @@ progress.

    send -fun send(topic: String, destination: MessageRecipients, sessionID: Long, obj: Any): Unit +fun send(topic: String, destination: Party, sessionID: Long, payload: Any): Unit sendAndReceive -fun <T : Any> sendAndReceive(topic: String, destination: MessageRecipients, sessionIDForSend: Long, sessionIDForReceive: Long, obj: Any): UntrustworthyData<T> +fun <T : Any> sendAndReceive(topic: String, destination: Party, sessionIDForSend: Long, sessionIDForReceive: Long, payload: Any): UntrustworthyData<T> @@ -118,6 +120,12 @@ progress.

    +Acceptor + +abstract class Acceptor<T> : ProtocolLogic<Unit> + + + Broadcast class Broadcast : ProtocolLogic<Boolean>

    This takes a Java Integer rather than Kotlin Int as that is what we end up with in the calling map and currently @@ -128,7 +136,7 @@ we do not support coercing numeric types in the reflective search for matching c Broadcast -class Broadcast : ProtocolLogic<Boolean> +class Broadcast : ProtocolLogic<Unit> @@ -153,6 +161,19 @@ timestamp is correct and none of its inputs have been used in another completed +FixingRoleDecider + +class FixingRoleDecider : ProtocolLogic<Unit>

    This protocol looks at the deal and decides whether to be the Fixer or Floater role in agreeing a fixing.

    + + + + +Instigator + +abstract class Instigator<S : ContractState, T> : ProtocolLogic<StateAndRef<S>> + + + Primary abstract class Primary<U> : ProtocolLogic<SignedTransaction>

    Abstracted bilateral deal protocol participant that initiates communication/handshake.

    @@ -172,7 +193,7 @@ for each step.

    Requester -class Requester<T> : ProtocolLogic<SignedTransaction> +class Requester : ProtocolLogic<SignedTransaction> @@ -204,24 +225,6 @@ all the transactions have been successfully verified and inserted into the local if any of the input states have been previously committed.

    - - -TraderDemoProtocolBuyer - -class TraderDemoProtocolBuyer : ProtocolLogic<Unit> - - - -TraderDemoProtocolSeller - -class TraderDemoProtocolSeller : ProtocolLogic<Unit> - - - -Updater - -class Updater : ProtocolLogic<Boolean> - diff --git a/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic/send-and-receive.html b/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic/send-and-receive.html index d04c258dac..8e1c8b402d 100644 --- a/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic/send-and-receive.html +++ b/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic/send-and-receive.html @@ -7,8 +7,8 @@ com.r3corda.core.protocols / ProtocolLogic / sendAndReceive

    sendAndReceive

    - -inline fun <reified T : Any> sendAndReceive(topic: String, destination: MessageRecipients, sessionIDForSend: Long, sessionIDForReceive: Long, obj: Any): UntrustworthyData<T>
    + +inline fun <reified T : Any> sendAndReceive(topic: String, destination: Party, sessionIDForSend: Long, sessionIDForReceive: Long, payload: Any): UntrustworthyData<T>


    diff --git a/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic/send.html b/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic/send.html index 18cbc9cbab..be065bd959 100644 --- a/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic/send.html +++ b/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic/send.html @@ -7,8 +7,8 @@ com.r3corda.core.protocols / ProtocolLogic / send

    send

    - -fun send(topic: String, destination: MessageRecipients, sessionID: Long, obj: Any): Unit
    + +fun send(topic: String, destination: Party, sessionID: Long, payload: Any): Unit


    diff --git a/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic/service-hub.html b/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic/service-hub.html index 732a0c9098..cfecaade40 100644 --- a/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic/service-hub.html +++ b/docs/build/html/api/com.r3corda.core.protocols/-protocol-logic/service-hub.html @@ -9,7 +9,9 @@

    serviceHub

    val serviceHub: ServiceHub
    -

    Provides access to big, heavy classes that may be reconstructed from time to time, e.g. across restarts

    +

    Provides access to big, heavy classes that may be reconstructed from time to time, e.g. across restarts. It is +only available once the protocol has started, which means it cannnot be accessed in the constructor. Either +access this lazily or from inside call.



    diff --git a/docs/build/html/api/com.r3corda.core.protocols/-protocol-state-machine/index.html b/docs/build/html/api/com.r3corda.core.protocols/-protocol-state-machine/index.html index e6cdd513ca..68c1b25b10 100644 --- a/docs/build/html/api/com.r3corda.core.protocols/-protocol-state-machine/index.html +++ b/docs/build/html/api/com.r3corda.core.protocols/-protocol-state-machine/index.html @@ -41,13 +41,13 @@ send -abstract fun send(topic: String, destination: MessageRecipients, sessionID: Long, obj: Any): Unit +abstract fun send(topic: String, destination: Party, sessionID: Long, payload: Any): Unit sendAndReceive -abstract fun <T : Any> sendAndReceive(topic: String, destination: MessageRecipients, sessionIDForSend: Long, sessionIDForReceive: Long, obj: Any, recvType: Class<T>): UntrustworthyData<T> +abstract fun <T : Any> sendAndReceive(topic: String, destination: Party, sessionIDForSend: Long, sessionIDForReceive: Long, payload: Any, recvType: Class<T>): UntrustworthyData<T> diff --git a/docs/build/html/api/com.r3corda.core.protocols/-protocol-state-machine/send-and-receive.html b/docs/build/html/api/com.r3corda.core.protocols/-protocol-state-machine/send-and-receive.html index f0a652fe04..1977e31a8a 100644 --- a/docs/build/html/api/com.r3corda.core.protocols/-protocol-state-machine/send-and-receive.html +++ b/docs/build/html/api/com.r3corda.core.protocols/-protocol-state-machine/send-and-receive.html @@ -7,8 +7,8 @@ com.r3corda.core.protocols / ProtocolStateMachine / sendAndReceive

    sendAndReceive

    - -abstract fun <T : Any> sendAndReceive(topic: String, destination: MessageRecipients, sessionIDForSend: Long, sessionIDForReceive: Long, obj: Any, recvType: Class<T>): UntrustworthyData<T>
    + +abstract fun <T : Any> sendAndReceive(topic: String, destination: Party, sessionIDForSend: Long, sessionIDForReceive: Long, payload: Any, recvType: Class<T>): UntrustworthyData<T>


    diff --git a/docs/build/html/api/com.r3corda.core.protocols/-protocol-state-machine/send.html b/docs/build/html/api/com.r3corda.core.protocols/-protocol-state-machine/send.html index 0b35e7f501..9f38e34e50 100644 --- a/docs/build/html/api/com.r3corda.core.protocols/-protocol-state-machine/send.html +++ b/docs/build/html/api/com.r3corda.core.protocols/-protocol-state-machine/send.html @@ -7,8 +7,8 @@ com.r3corda.core.protocols / ProtocolStateMachine / send

    send

    - -abstract fun send(topic: String, destination: MessageRecipients, sessionID: Long, obj: Any): Unit
    + +abstract fun send(topic: String, destination: Party, sessionID: Long, payload: Any): Unit


    diff --git a/docs/build/html/api/com.r3corda.core.protocols/index.html b/docs/build/html/api/com.r3corda.core.protocols/index.html index 0b1a935fa1..4bc918e6fc 100644 --- a/docs/build/html/api/com.r3corda.core.protocols/index.html +++ b/docs/build/html/api/com.r3corda.core.protocols/index.html @@ -12,6 +12,14 @@ +AppContext + +data class AppContext

    This is just some way to track what attachments need to be in the class loader, but may later include some app +properties loaded from the attachments. And perhaps the authenticated user for an API call?

    + + + + ProtocolLogic abstract class ProtocolLogic<T>

    A sub-class of ProtocolLogic implements a protocol flow using direct, straight line blocking code. Thus you @@ -21,6 +29,20 @@ a node crash, how many instances of your protocol there are running and so on. +ProtocolLogicRef + +data class ProtocolLogicRef

    A class representing a ProtocolLogic instance which would be possible to safely pass out of the contract sandbox

    + + + + +ProtocolLogicRefFactory + +class ProtocolLogicRefFactory : SingletonSerializeAsToken

    A class for conversion to and from ProtocolLogic and ProtocolLogicRef instances

    + + + + ProtocolStateMachine interface ProtocolStateMachine<R>

    The interface of ProtocolStateMachineImpl exposing methods and properties required by ProtocolLogic for compilation

    @@ -28,5 +50,16 @@ a node crash, how many instances of your protocol there are running and so on. +

    Exceptions

    + + + + + + + +
    +IllegalProtocolLogicException +class IllegalProtocolLogicException : IllegalArgumentException
    diff --git a/docs/build/html/api/com.r3corda.core.serialization/-deserialize-as-kotlin-object-def.html b/docs/build/html/api/com.r3corda.core.serialization/-deserialize-as-kotlin-object-def.html new file mode 100644 index 0000000000..1d2fb41a74 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.serialization/-deserialize-as-kotlin-object-def.html @@ -0,0 +1,28 @@ + + +DeserializeAsKotlinObjectDef - + + + +com.r3corda.core.serialization / DeserializeAsKotlinObjectDef
    +
    +

    DeserializeAsKotlinObjectDef

    +interface DeserializeAsKotlinObjectDef
    +

    Marker interface for kotlin object definitions so that they are deserialized as the singleton instance.

    +
    +
    +

    Inheritors

    + + + + + + + +
    +Ack +object Ack : DeserializeAsKotlinObjectDef

    A general Ack message that conveys no content other than its presence for use when you want an acknowledgement +from a recipient. Using Unit can be ambiguous as it is similar to Void and so could mean no response.

    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.serialization/-ed25519-private-key-serializer/ed25519-curve.html b/docs/build/html/api/com.r3corda.core.serialization/-ed25519-private-key-serializer/ed25519-curve.html new file mode 100644 index 0000000000..cdf43d0e49 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.serialization/-ed25519-private-key-serializer/ed25519-curve.html @@ -0,0 +1,15 @@ + + +Ed25519PrivateKeySerializer.ed25519Curve - + + + +com.r3corda.core.serialization / Ed25519PrivateKeySerializer / ed25519Curve
    +
    +

    ed25519Curve

    + +val ed25519Curve: <ERROR CLASS>
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.serialization/-ed25519-private-key-serializer/index.html b/docs/build/html/api/com.r3corda.core.serialization/-ed25519-private-key-serializer/index.html new file mode 100644 index 0000000000..d79a256142 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.serialization/-ed25519-private-key-serializer/index.html @@ -0,0 +1,43 @@ + + +Ed25519PrivateKeySerializer - + + + +com.r3corda.core.serialization / Ed25519PrivateKeySerializer
    +
    +

    Ed25519PrivateKeySerializer

    +object Ed25519PrivateKeySerializer
    +

    For serialising an ed25519 private key

    +
    +
    +

    Properties

    + + + + + + + +
    +ed25519Curve +val ed25519Curve: <ERROR CLASS>
    +

    Functions

    + + + + + + + + + + + +
    +read +fun read(kryo: <ERROR CLASS>, input: <ERROR CLASS>, type: Class<<ERROR CLASS>>): <ERROR CLASS>
    +write +fun write(kryo: <ERROR CLASS>, output: <ERROR CLASS>, obj: <ERROR CLASS>): Unit
    + + diff --git a/docs/build/html/api/com.r3corda.core.serialization/-ed25519-private-key-serializer/read.html b/docs/build/html/api/com.r3corda.core.serialization/-ed25519-private-key-serializer/read.html new file mode 100644 index 0000000000..20b106d766 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.serialization/-ed25519-private-key-serializer/read.html @@ -0,0 +1,15 @@ + + +Ed25519PrivateKeySerializer.read - + + + +com.r3corda.core.serialization / Ed25519PrivateKeySerializer / read
    +
    +

    read

    + +fun read(kryo: <ERROR CLASS>, input: <ERROR CLASS>, type: Class<<ERROR CLASS>>): <ERROR CLASS>
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.serialization/-ed25519-private-key-serializer/write.html b/docs/build/html/api/com.r3corda.core.serialization/-ed25519-private-key-serializer/write.html new file mode 100644 index 0000000000..507b1a88b5 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.serialization/-ed25519-private-key-serializer/write.html @@ -0,0 +1,15 @@ + + +Ed25519PrivateKeySerializer.write - + + + +com.r3corda.core.serialization / Ed25519PrivateKeySerializer / write
    +
    +

    write

    + +fun write(kryo: <ERROR CLASS>, output: <ERROR CLASS>, obj: <ERROR CLASS>): Unit
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.serialization/-ed25519-public-key-serializer/ed25519-curve.html b/docs/build/html/api/com.r3corda.core.serialization/-ed25519-public-key-serializer/ed25519-curve.html new file mode 100644 index 0000000000..45242ffe71 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.serialization/-ed25519-public-key-serializer/ed25519-curve.html @@ -0,0 +1,15 @@ + + +Ed25519PublicKeySerializer.ed25519Curve - + + + +com.r3corda.core.serialization / Ed25519PublicKeySerializer / ed25519Curve
    +
    +

    ed25519Curve

    + +val ed25519Curve: <ERROR CLASS>
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.serialization/-ed25519-public-key-serializer/index.html b/docs/build/html/api/com.r3corda.core.serialization/-ed25519-public-key-serializer/index.html new file mode 100644 index 0000000000..f99f8480a9 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.serialization/-ed25519-public-key-serializer/index.html @@ -0,0 +1,43 @@ + + +Ed25519PublicKeySerializer - + + + +com.r3corda.core.serialization / Ed25519PublicKeySerializer
    +
    +

    Ed25519PublicKeySerializer

    +object Ed25519PublicKeySerializer
    +

    For serialising an ed25519 public key

    +
    +
    +

    Properties

    + + + + + + + +
    +ed25519Curve +val ed25519Curve: <ERROR CLASS>
    +

    Functions

    + + + + + + + + + + + +
    +read +fun read(kryo: <ERROR CLASS>, input: <ERROR CLASS>, type: Class<<ERROR CLASS>>): <ERROR CLASS>
    +write +fun write(kryo: <ERROR CLASS>, output: <ERROR CLASS>, obj: <ERROR CLASS>): Unit
    + + diff --git a/docs/build/html/api/com.r3corda.core.serialization/-ed25519-public-key-serializer/read.html b/docs/build/html/api/com.r3corda.core.serialization/-ed25519-public-key-serializer/read.html new file mode 100644 index 0000000000..df058dc263 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.serialization/-ed25519-public-key-serializer/read.html @@ -0,0 +1,15 @@ + + +Ed25519PublicKeySerializer.read - + + + +com.r3corda.core.serialization / Ed25519PublicKeySerializer / read
    +
    +

    read

    + +fun read(kryo: <ERROR CLASS>, input: <ERROR CLASS>, type: Class<<ERROR CLASS>>): <ERROR CLASS>
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.serialization/-ed25519-public-key-serializer/write.html b/docs/build/html/api/com.r3corda.core.serialization/-ed25519-public-key-serializer/write.html new file mode 100644 index 0000000000..65743cb547 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.serialization/-ed25519-public-key-serializer/write.html @@ -0,0 +1,15 @@ + + +Ed25519PublicKeySerializer.write - + + + +com.r3corda.core.serialization / Ed25519PublicKeySerializer / write
    +
    +

    write

    + +fun write(kryo: <ERROR CLASS>, output: <ERROR CLASS>, obj: <ERROR CLASS>): Unit
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.serialization/-kotlin-object-serializer/index.html b/docs/build/html/api/com.r3corda.core.serialization/-kotlin-object-serializer/index.html new file mode 100644 index 0000000000..cb338eb85d --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.serialization/-kotlin-object-serializer/index.html @@ -0,0 +1,32 @@ + + +KotlinObjectSerializer - + + + +com.r3corda.core.serialization / KotlinObjectSerializer
    +
    +

    KotlinObjectSerializer

    +object KotlinObjectSerializer
    +

    Serializer to deserialize kotlin object definitions marked with DeserializeAsKotlinObjectDef.

    +
    +
    +

    Functions

    + + + + + + + + + + + +
    +read +fun read(kryo: <ERROR CLASS>, input: <ERROR CLASS>, type: Class<DeserializeAsKotlinObjectDef>): DeserializeAsKotlinObjectDef
    +write +fun write(kryo: <ERROR CLASS>, output: <ERROR CLASS>, obj: DeserializeAsKotlinObjectDef): Unit
    + + diff --git a/docs/build/html/api/com.r3corda.core.serialization/-kotlin-object-serializer/read.html b/docs/build/html/api/com.r3corda.core.serialization/-kotlin-object-serializer/read.html new file mode 100644 index 0000000000..00c090e9ab --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.serialization/-kotlin-object-serializer/read.html @@ -0,0 +1,15 @@ + + +KotlinObjectSerializer.read - + + + +com.r3corda.core.serialization / KotlinObjectSerializer / read
    +
    +

    read

    + +fun read(kryo: <ERROR CLASS>, input: <ERROR CLASS>, type: Class<DeserializeAsKotlinObjectDef>): DeserializeAsKotlinObjectDef
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.serialization/-kotlin-object-serializer/write.html b/docs/build/html/api/com.r3corda.core.serialization/-kotlin-object-serializer/write.html new file mode 100644 index 0000000000..995662f981 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.serialization/-kotlin-object-serializer/write.html @@ -0,0 +1,15 @@ + + +KotlinObjectSerializer.write - + + + +com.r3corda.core.serialization / KotlinObjectSerializer / write
    +
    +

    write

    + +fun write(kryo: <ERROR CLASS>, output: <ERROR CLASS>, obj: DeserializeAsKotlinObjectDef): Unit
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.serialization/-serialize-as-token/index.html b/docs/build/html/api/com.r3corda.core.serialization/-serialize-as-token/index.html index ccd7d2d4e3..c00132293c 100644 --- a/docs/build/html/api/com.r3corda.core.serialization/-serialize-as-token/index.html +++ b/docs/build/html/api/com.r3corda.core.serialization/-serialize-as-token/index.html @@ -51,6 +51,13 @@ they are serialized because they have a lot of internal state that does not seri to indicate which instance the token is a serialized form of.

    + + +TestClock + +class TestClock : MutableClock, SerializeAsToken

    A Clock that can have the time advanced for use in testing

    + + diff --git a/docs/build/html/api/com.r3corda.core.serialization/-singleton-serialize-as-token/index.html b/docs/build/html/api/com.r3corda.core.serialization/-singleton-serialize-as-token/index.html index 61af8bd89a..b7314a981d 100644 --- a/docs/build/html/api/com.r3corda.core.serialization/-singleton-serialize-as-token/index.html +++ b/docs/build/html/api/com.r3corda.core.serialization/-singleton-serialize-as-token/index.html @@ -41,6 +41,13 @@ to indicate which instance the token is a serialized form of.

    +AbstractNodeService + +abstract class AbstractNodeService : SingletonSerializeAsToken

    Abstract superclass for services that a node can host, which provides helper functions.

    + + + + ArtemisMessagingService class ArtemisMessagingService : SingletonSerializeAsToken, MessagingService

    This class implements the MessagingService API using Apache Artemis, the successor to their ActiveMQ product. @@ -92,6 +99,15 @@ testing).

    +InMemoryWalletService + +open class InMemoryWalletService : SingletonSerializeAsToken, WalletService

    This class implements a simple, in memory wallet that tracks states that are owned by us, and also has a convenience +method to auto-generate some self-issued cash states that can be used for test trading. A real wallet would persist +states relevant to us into a database and once such a wallet is implemented, this scaffolding can be removed.

    + + + + MockIdentityService class MockIdentityService : IdentityService, SingletonSerializeAsToken @@ -106,7 +122,7 @@ testing).

    MockStorageService -class MockStorageService : SingletonSerializeAsToken, StorageService +class MockStorageService : SingletonSerializeAsToken, TxWritableStorageService @@ -118,18 +134,24 @@ This is not an interface because it is too lightweight to bother mocking out.

    -NodeWalletService +NodeSchedulerService -class NodeWalletService : SingletonSerializeAsToken, WalletService

    This class implements a simple, in memory wallet that tracks states that are owned by us, and also has a convenience -method to auto-generate some self-issued cash states that can be used for test trading. A real wallet would persist -states relevant to us into a database and once such a wallet is implemented, this scaffolding can be removed.

    +class NodeSchedulerService : SchedulerService, SingletonSerializeAsToken

    A first pass of a simple SchedulerService that works with MutableClocks for testing, demonstrations and simulations +that also encompasses the Wallet observer for processing transactions.

    + + + + +ProtocolLogicRefFactory + +class ProtocolLogicRefFactory : SingletonSerializeAsToken

    A class for conversion to and from ProtocolLogic and ProtocolLogicRef instances

    StorageServiceImpl -open class StorageServiceImpl : SingletonSerializeAsToken, StorageService +open class StorageServiceImpl : SingletonSerializeAsToken, TxWritableStorageService diff --git a/docs/build/html/api/com.r3corda.core.serialization/index.html b/docs/build/html/api/com.r3corda.core.serialization/index.html index 1d88104185..eb33e0e054 100644 --- a/docs/build/html/api/com.r3corda.core.serialization/index.html +++ b/docs/build/html/api/com.r3corda.core.serialization/index.html @@ -12,6 +12,27 @@ +DeserializeAsKotlinObjectDef + +interface DeserializeAsKotlinObjectDef

    Marker interface for kotlin object definitions so that they are deserialized as the singleton instance.

    + + + + +Ed25519PrivateKeySerializer + +object Ed25519PrivateKeySerializer

    For serialising an ed25519 private key

    + + + + +Ed25519PublicKeySerializer + +object Ed25519PublicKeySerializer

    For serialising an ed25519 public key

    + + + + ImmutableClassSerializer class ImmutableClassSerializer<T : Any>

    Serializes properties and deserializes by using the constructor. This assumes that all backed properties are @@ -20,6 +41,13 @@ set via the constructor and the class is immutable.

    +KotlinObjectSerializer + +object KotlinObjectSerializer

    Serializer to deserialize kotlin object definitions marked with DeserializeAsKotlinObjectDef.

    + + + + NoReferencesSerializer class NoReferencesSerializer<T> @@ -186,6 +214,12 @@ references will throw a stack overflow exception during serialisation.

    +readBytesWithLength + +fun <ERROR CLASS>.readBytesWithLength(): ByteArray + + + serialize fun <T : Any> T.serialize(kryo: <ERROR CLASS> = THREAD_LOCAL_KRYO.get()): SerializedBytes<T>

    Can be called on any object to convert it to a byte array (wrapped by SerializedBytes), regardless of whether @@ -198,6 +232,12 @@ the type is marked as serializable or was designed for it (so be careful)

    fun <T> <ERROR CLASS>.useClassLoader(cl: ClassLoader, body: () -> T): T + + +writeBytesWithLength + +fun <ERROR CLASS>.writeBytesWithLength(byteArray: ByteArray): Unit + diff --git a/docs/build/html/api/com.r3corda.core.serialization/read-bytes-with-length.html b/docs/build/html/api/com.r3corda.core.serialization/read-bytes-with-length.html new file mode 100644 index 0000000000..bf1c76cc3d --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.serialization/read-bytes-with-length.html @@ -0,0 +1,15 @@ + + +readBytesWithLength - + + + +com.r3corda.core.serialization / readBytesWithLength
    +
    +

    readBytesWithLength

    + +fun <ERROR CLASS>.readBytesWithLength(): ByteArray
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.serialization/write-bytes-with-length.html b/docs/build/html/api/com.r3corda.core.serialization/write-bytes-with-length.html new file mode 100644 index 0000000000..8f4624d47b --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.serialization/write-bytes-with-length.html @@ -0,0 +1,15 @@ + + +writeBytesWithLength - + + + +com.r3corda.core.serialization / writeBytesWithLength
    +
    +

    writeBytesWithLength

    + +fun <ERROR CLASS>.writeBytesWithLength(byteArray: ByteArray): Unit
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-a-l-l_-t-e-s-t_-k-e-y-s.html b/docs/build/html/api/com.r3corda.core.testing/-a-l-l_-t-e-s-t_-k-e-y-s.html index 9876213963..cfca05a6d5 100644 --- a/docs/build/html/api/com.r3corda.core.testing/-a-l-l_-t-e-s-t_-k-e-y-s.html +++ b/docs/build/html/api/com.r3corda.core.testing/-a-l-l_-t-e-s-t_-k-e-y-s.html @@ -8,7 +8,7 @@

    ALL_TEST_KEYS

    -val ALL_TEST_KEYS: <ERROR CLASS>
    +val ALL_TEST_KEYS: List<KeyPair>


    diff --git a/docs/build/html/api/com.r3corda.core.testing/-abstract-transaction-for-test/add-command.html b/docs/build/html/api/com.r3corda.core.testing/-abstract-transaction-for-test/add-command.html new file mode 100644 index 0000000000..7effd7ce84 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-abstract-transaction-for-test/add-command.html @@ -0,0 +1,15 @@ + + +AbstractTransactionForTest.addCommand - + + + +com.r3corda.core.testing / AbstractTransactionForTest / addCommand
    +
    +

    addCommand

    + +fun addCommand(cmd: Command): Unit
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-abstract-transaction-for-test/arg.html b/docs/build/html/api/com.r3corda.core.testing/-abstract-transaction-for-test/arg.html index a179d38ef4..177006757d 100644 --- a/docs/build/html/api/com.r3corda.core.testing/-abstract-transaction-for-test/arg.html +++ b/docs/build/html/api/com.r3corda.core.testing/-abstract-transaction-for-test/arg.html @@ -8,7 +8,9 @@

    arg

    -fun arg(vararg key: PublicKey, c: () -> CommandData): Unit
    +fun arg(vararg keys: PublicKey, c: () -> CommandData): Unit
    + +fun arg(key: PublicKey, c: CommandData): Unit


    diff --git a/docs/build/html/api/com.r3corda.core.testing/-abstract-transaction-for-test/index.html b/docs/build/html/api/com.r3corda.core.testing/-abstract-transaction-for-test/index.html index 6db2b65487..64c1715f22 100644 --- a/docs/build/html/api/com.r3corda.core.testing/-abstract-transaction-for-test/index.html +++ b/docs/build/html/api/com.r3corda.core.testing/-abstract-transaction-for-test/index.html @@ -42,6 +42,18 @@ val outStates: ArrayList<LabeledOutput> + + +signers + +val signers: LinkedHashSet<PublicKey> + + + +type + +val type: General +

    Functions

    @@ -49,9 +61,16 @@ +addCommand + +fun addCommand(cmd: Command): Unit + + + arg -fun arg(vararg key: PublicKey, c: () -> CommandData): Unit +fun arg(vararg keys: PublicKey, c: () -> CommandData): Unit
    +fun arg(key: PublicKey, c: CommandData): Unit @@ -69,7 +88,8 @@ output -open fun output(label: String? = null, s: () -> ContractState): <ERROR CLASS> +open fun output(label: String? = null, s: () -> ContractState): <ERROR CLASS>
    +open fun output(label: String? = null, s: ContractState): <ERROR CLASS> @@ -82,7 +102,7 @@ transaction -fun transaction(body: TransactionForTest.() -> Unit): Unit +fun transaction(body: TransactionForTest.() -> LastLineShouldTestForAcceptOrFailure): Unit diff --git a/docs/build/html/api/com.r3corda.core.testing/-abstract-transaction-for-test/output.html b/docs/build/html/api/com.r3corda.core.testing/-abstract-transaction-for-test/output.html index b8b7474a18..de698b043c 100644 --- a/docs/build/html/api/com.r3corda.core.testing/-abstract-transaction-for-test/output.html +++ b/docs/build/html/api/com.r3corda.core.testing/-abstract-transaction-for-test/output.html @@ -9,6 +9,8 @@

    output

    open fun output(label: String? = null, s: () -> ContractState): <ERROR CLASS>
    + +open fun output(label: String? = null, s: ContractState): <ERROR CLASS>


    diff --git a/docs/build/html/api/com.r3corda.core.testing/-abstract-transaction-for-test/signers.html b/docs/build/html/api/com.r3corda.core.testing/-abstract-transaction-for-test/signers.html new file mode 100644 index 0000000000..6e4aedb0c9 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-abstract-transaction-for-test/signers.html @@ -0,0 +1,15 @@ + + +AbstractTransactionForTest.signers - + + + +com.r3corda.core.testing / AbstractTransactionForTest / signers
    +
    +

    signers

    + +protected val signers: LinkedHashSet<PublicKey>
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-abstract-transaction-for-test/transaction.html b/docs/build/html/api/com.r3corda.core.testing/-abstract-transaction-for-test/transaction.html index 8ccd4c8015..40923e52c0 100644 --- a/docs/build/html/api/com.r3corda.core.testing/-abstract-transaction-for-test/transaction.html +++ b/docs/build/html/api/com.r3corda.core.testing/-abstract-transaction-for-test/transaction.html @@ -7,8 +7,8 @@ com.r3corda.core.testing / AbstractTransactionForTest / transaction

    transaction

    - -fun transaction(body: TransactionForTest.() -> Unit): Unit
    + +fun transaction(body: TransactionForTest.() -> LastLineShouldTestForAcceptOrFailure): Unit
    Deprecated: Cannot nest transactions, use tweak


    diff --git a/docs/build/html/api/com.r3corda.core.testing/-abstract-transaction-for-test/type.html b/docs/build/html/api/com.r3corda.core.testing/-abstract-transaction-for-test/type.html new file mode 100644 index 0000000000..2550d0e3c0 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-abstract-transaction-for-test/type.html @@ -0,0 +1,15 @@ + + +AbstractTransactionForTest.type - + + + +com.r3corda.core.testing / AbstractTransactionForTest / type
    +
    +

    type

    + +protected val type: General
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-always-succeed-contract/-init-.html b/docs/build/html/api/com.r3corda.core.testing/-always-succeed-contract/-init-.html new file mode 100644 index 0000000000..e34050e4e9 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-always-succeed-contract/-init-.html @@ -0,0 +1,14 @@ + + +AlwaysSucceedContract.<init> - + + + +com.r3corda.core.testing / AlwaysSucceedContract / <init>
    +
    +

    <init>

    +AlwaysSucceedContract(legalContractReference: SecureHash = SecureHash.sha256("Always succeed contract"))
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-always-succeed-contract/index.html b/docs/build/html/api/com.r3corda.core.testing/-always-succeed-contract/index.html new file mode 100644 index 0000000000..ea2c7e7570 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-always-succeed-contract/index.html @@ -0,0 +1,53 @@ + + +AlwaysSucceedContract - + + + +com.r3corda.core.testing / AlwaysSucceedContract
    +
    +

    AlwaysSucceedContract

    +class AlwaysSucceedContract : Contract
    +
    +
    +

    Constructors

    + + + + + + + +
    +<init> +AlwaysSucceedContract(legalContractReference: SecureHash = SecureHash.sha256("Always succeed contract"))
    +

    Properties

    + + + + + + + +
    +legalContractReference +val legalContractReference: SecureHash

    Unparsed reference to the natural language contract that this code is supposed to express (usually a hash of +the contracts contents).

    +
    +

    Functions

    + + + + + + + +
    +verify +fun verify(tx: TransactionForContract): Unit

    Takes an object that represents a state transition, and ensures the inputs/outputs/commands make sense. +Must throw an exception if theres a problem that should prevent state transition. Takes a single object +rather than an argument so that additional data can be added without breaking binary compatibility with +existing contract code.

    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-always-succeed-contract/legal-contract-reference.html b/docs/build/html/api/com.r3corda.core.testing/-always-succeed-contract/legal-contract-reference.html new file mode 100644 index 0000000000..38c44cf4ad --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-always-succeed-contract/legal-contract-reference.html @@ -0,0 +1,18 @@ + + +AlwaysSucceedContract.legalContractReference - + + + +com.r3corda.core.testing / AlwaysSucceedContract / legalContractReference
    +
    +

    legalContractReference

    + +val legalContractReference: SecureHash
    +Overrides Contract.legalContractReference
    +

    Unparsed reference to the natural language contract that this code is supposed to express (usually a hash of +the contracts contents).

    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-always-succeed-contract/verify.html b/docs/build/html/api/com.r3corda.core.testing/-always-succeed-contract/verify.html new file mode 100644 index 0000000000..05c1367d5c --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-always-succeed-contract/verify.html @@ -0,0 +1,20 @@ + + +AlwaysSucceedContract.verify - + + + +com.r3corda.core.testing / AlwaysSucceedContract / verify
    +
    +

    verify

    + +fun verify(tx: TransactionForContract): Unit
    +Overrides Contract.verify
    +

    Takes an object that represents a state transition, and ensures the inputs/outputs/commands make sense. +Must throw an exception if theres a problem that should prevent state transition. Takes a single object +rather than an argument so that additional data can be added without breaking binary compatibility with +existing contract code.

    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-d-u-m-m-y_-p-u-b-k-e-y_1.html b/docs/build/html/api/com.r3corda.core.testing/-d-u-m-m-y_-p-u-b-k-e-y_1.html index cc4c410c59..0344fdfb15 100644 --- a/docs/build/html/api/com.r3corda.core.testing/-d-u-m-m-y_-p-u-b-k-e-y_1.html +++ b/docs/build/html/api/com.r3corda.core.testing/-d-u-m-m-y_-p-u-b-k-e-y_1.html @@ -8,7 +8,7 @@

    DUMMY_PUBKEY_1

    -val DUMMY_PUBKEY_1: DummyPublicKey
    +val DUMMY_PUBKEY_1: PublicKey


    diff --git a/docs/build/html/api/com.r3corda.core.testing/-d-u-m-m-y_-p-u-b-k-e-y_2.html b/docs/build/html/api/com.r3corda.core.testing/-d-u-m-m-y_-p-u-b-k-e-y_2.html index b7e7833b37..2f72d9c0c1 100644 --- a/docs/build/html/api/com.r3corda.core.testing/-d-u-m-m-y_-p-u-b-k-e-y_2.html +++ b/docs/build/html/api/com.r3corda.core.testing/-d-u-m-m-y_-p-u-b-k-e-y_2.html @@ -8,7 +8,7 @@

    DUMMY_PUBKEY_2

    -val DUMMY_PUBKEY_2: DummyPublicKey
    +val DUMMY_PUBKEY_2: PublicKey


    diff --git a/docs/build/html/api/com.r3corda.core.testing/-dummy-linear-state/-init-.html b/docs/build/html/api/com.r3corda.core.testing/-dummy-linear-state/-init-.html new file mode 100644 index 0000000000..34f9cffd86 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-dummy-linear-state/-init-.html @@ -0,0 +1,14 @@ + + +DummyLinearState.<init> - + + + +com.r3corda.core.testing / DummyLinearState / <init>
    +
    +

    <init>

    +DummyLinearState(thread: SecureHash = SecureHash.randomSHA256(), contract: Contract = AlwaysSucceedContract(), participants: List<PublicKey> = listOf(), nonce: SecureHash = SecureHash.randomSHA256())
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-dummy-linear-state/contract.html b/docs/build/html/api/com.r3corda.core.testing/-dummy-linear-state/contract.html new file mode 100644 index 0000000000..c86f9eefd6 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-dummy-linear-state/contract.html @@ -0,0 +1,43 @@ + + +DummyLinearState.contract - + + + +com.r3corda.core.testing / DummyLinearState / contract
    +
    +

    contract

    + +val contract: Contract
    +Overrides ContractState.contract
    +

    An instance of the contract class that will verify this state.

    +

    Discussion

    +

    This field is not the final design, its just a piece of temporary scaffolding. Once the contract sandbox is +further along, this field will become a description of which attachments are acceptable for defining the +contract.

    +

    Recall that an attachment is a zip file that can be referenced from any transaction. The contents of the +attachments are merged together and cannot define any overlapping files, thus for any given transaction there +is a miniature file system in which each file can be precisely mapped to the defining attachment.

    +

    Attachments may contain many things (data files, legal documents, etc) but mostly they contain JVM bytecode. +The class files inside define not only Contract implementations but also the classes that define the states. +Within the rest of a transaction, user-providable components are referenced by name only.

    +

    This means that a smart contract in Corda does two things:

    +
    1. Define the data structures that compose the ledger (the states)

      +
    2. Define the rules for updating those structures

      +

    The first is merely a utility role ... in theory contract code could manually parse byte streams by hand. +The second is vital to the integrity of the ledger. So this field needs to be able to express constraints like:

    +
    • Only attachment 733c350f396a727655be1363c06635ba355036bd54a5ed6e594fd0b5d05f42f6 may be used with this state.

      +
    • Any attachment signed by public key 2d1ce0e330c52b8055258d776c40 may be used with this state.

      +
    • Attachments (1, 2, 3) may all be used with this state.

      +

    and so on. In this way it becomes possible for the business logic governing a state to be evolved, if the +constraints are flexible enough.

    +

    Because contract classes often also define utilities that generate relevant transactions, and because attachments +cannot know their own hashes, we will have to provide various utilities to assist with obtaining the right +code constraints from within the contract code itself.

    +

    TODO: Implement the above description. See COR-226

    +
    +
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-dummy-linear-state/index.html b/docs/build/html/api/com.r3corda.core.testing/-dummy-linear-state/index.html new file mode 100644 index 0000000000..79dbcfd2b2 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-dummy-linear-state/index.html @@ -0,0 +1,87 @@ + + +DummyLinearState - + + + +com.r3corda.core.testing / DummyLinearState
    +
    +

    DummyLinearState

    +class DummyLinearState : LinearState
    +
    +
    +

    Constructors

    + + + + + + + +
    +<init> +DummyLinearState(thread: SecureHash = SecureHash.randomSHA256(), contract: Contract = AlwaysSucceedContract(), participants: List<PublicKey> = listOf(), nonce: SecureHash = SecureHash.randomSHA256())
    +

    Properties

    + + + + + + + + + + + + + + + + + + + +
    +contract +val contract: Contract

    An instance of the contract class that will verify this state.

    +
    +nonce +val nonce: SecureHash
    +participants +val participants: List<PublicKey>

    A participant is any party that is able to consume this state in a valid transaction.

    +
    +thread +val thread: SecureHash

    Unique thread id within the wallets of all parties

    +
    +

    Functions

    + + + + + + + +
    +isRelevant +fun isRelevant(ourKeys: Set<PublicKey>): Boolean

    true if this should be tracked by our wallet(s)

    +
    +

    Extension Functions

    + + + + + + + + + + + +
    +hash +fun ContractState.hash(): SecureHash

    Returns the SHA-256 hash of the serialised contents of this state (not cached)

    +
    +with notary +infix fun ContractState.with notary(notary: Party): TransactionState<ContractState>
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-dummy-linear-state/is-relevant.html b/docs/build/html/api/com.r3corda.core.testing/-dummy-linear-state/is-relevant.html new file mode 100644 index 0000000000..cc20a0b156 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-dummy-linear-state/is-relevant.html @@ -0,0 +1,17 @@ + + +DummyLinearState.isRelevant - + + + +com.r3corda.core.testing / DummyLinearState / isRelevant
    +
    +

    isRelevant

    + +fun isRelevant(ourKeys: Set<PublicKey>): Boolean
    +Overrides LinearState.isRelevant
    +

    true if this should be tracked by our wallet(s)

    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-dummy-linear-state/nonce.html b/docs/build/html/api/com.r3corda.core.testing/-dummy-linear-state/nonce.html new file mode 100644 index 0000000000..65100719da --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-dummy-linear-state/nonce.html @@ -0,0 +1,15 @@ + + +DummyLinearState.nonce - + + + +com.r3corda.core.testing / DummyLinearState / nonce
    +
    +

    nonce

    + +val nonce: SecureHash
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-dummy-linear-state/participants.html b/docs/build/html/api/com.r3corda.core.testing/-dummy-linear-state/participants.html new file mode 100644 index 0000000000..2c70d42cab --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-dummy-linear-state/participants.html @@ -0,0 +1,25 @@ + + +DummyLinearState.participants - + + + +com.r3corda.core.testing / DummyLinearState / participants
    +
    +

    participants

    + +val participants: List<PublicKey>
    +Overrides ContractState.participants
    +

    A participant is any party that is able to consume this state in a valid transaction.

    +

    The list of participants is required for certain types of transactions. For example, when changing the notary +for this state (TransactionType.NotaryChange), every participants has to be involved and approve the transaction +so that they receive the updated state, and dont end up in a situation where they can no longer use a state +they possess, since someone consumed that state during the notary change process.

    +

    The participants list should normally be derived from the contents of the state. E.g. for Cash the participants +list should just contain the owner.

    +
    +
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-dummy-linear-state/thread.html b/docs/build/html/api/com.r3corda.core.testing/-dummy-linear-state/thread.html new file mode 100644 index 0000000000..fe71473f89 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-dummy-linear-state/thread.html @@ -0,0 +1,17 @@ + + +DummyLinearState.thread - + + + +com.r3corda.core.testing / DummyLinearState / thread
    +
    +

    thread

    + +val thread: SecureHash
    +Overrides LinearState.thread
    +

    Unique thread id within the wallets of all parties

    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-in-memory-wallet-service/-clashing-threads/-init-.html b/docs/build/html/api/com.r3corda.core.testing/-in-memory-wallet-service/-clashing-threads/-init-.html new file mode 100644 index 0000000000..36c42a1c67 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-in-memory-wallet-service/-clashing-threads/-init-.html @@ -0,0 +1,14 @@ + + +InMemoryWalletService.ClashingThreads.<init> - + + + +com.r3corda.core.testing / InMemoryWalletService / ClashingThreads / <init>
    +
    +

    <init>

    +ClashingThreads(threads: Set<SecureHash>, transactions: Iterable<WireTransaction>)
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-in-memory-wallet-service/-clashing-threads/index.html b/docs/build/html/api/com.r3corda.core.testing/-in-memory-wallet-service/-clashing-threads/index.html new file mode 100644 index 0000000000..e1bd3df3f4 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-in-memory-wallet-service/-clashing-threads/index.html @@ -0,0 +1,25 @@ + + +InMemoryWalletService.ClashingThreads - + + + +com.r3corda.core.testing / InMemoryWalletService / ClashingThreads
    +
    +

    ClashingThreads

    +class ClashingThreads : Exception
    +
    +
    +

    Constructors

    + + + + + + + +
    +<init> +ClashingThreads(threads: Set<SecureHash>, transactions: Iterable<WireTransaction>)
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-in-memory-wallet-service/-init-.html b/docs/build/html/api/com.r3corda.core.testing/-in-memory-wallet-service/-init-.html new file mode 100644 index 0000000000..def33d7482 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-in-memory-wallet-service/-init-.html @@ -0,0 +1,17 @@ + + +InMemoryWalletService.<init> - + + + +com.r3corda.core.testing / InMemoryWalletService / <init>
    +
    +

    <init>

    +InMemoryWalletService(services: ServiceHub)
    +

    This class implements a simple, in memory wallet that tracks states that are owned by us, and also has a convenience +method to auto-generate some self-issued cash states that can be used for test trading. A real wallet would persist +states relevant to us into a database and once such a wallet is implemented, this scaffolding can be removed.

    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-in-memory-wallet-service/clashing-threads.html b/docs/build/html/api/com.r3corda.core.testing/-in-memory-wallet-service/clashing-threads.html new file mode 100644 index 0000000000..b154bbd28c --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-in-memory-wallet-service/clashing-threads.html @@ -0,0 +1,15 @@ + + +InMemoryWalletService.clashingThreads - + + + +com.r3corda.core.testing / InMemoryWalletService / clashingThreads
    +
    +

    clashingThreads

    + +val Wallet.clashingThreads: Set<SecureHash>
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-in-memory-wallet-service/current-wallet.html b/docs/build/html/api/com.r3corda.core.testing/-in-memory-wallet-service/current-wallet.html new file mode 100644 index 0000000000..4c8165450e --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-in-memory-wallet-service/current-wallet.html @@ -0,0 +1,22 @@ + + +InMemoryWalletService.currentWallet - + + + +com.r3corda.core.testing / InMemoryWalletService / currentWallet
    +
    +

    currentWallet

    + +open val currentWallet: Wallet
    +Overrides WalletService.currentWallet
    +

    Returns a read-only snapshot of the wallet at the time the call is made. Note that if you consume states or +keys in this wallet, you must inform the wallet service so it can update its internal state.

    +

    Getter
    +

    Returns a read-only snapshot of the wallet at the time the call is made. Note that if you consume states or +keys in this wallet, you must inform the wallet service so it can update its internal state.

    +

    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-in-memory-wallet-service/index.html b/docs/build/html/api/com.r3corda.core.testing/-in-memory-wallet-service/index.html new file mode 100644 index 0000000000..719b6f1ea4 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-in-memory-wallet-service/index.html @@ -0,0 +1,156 @@ + + +InMemoryWalletService - + + + +com.r3corda.core.testing / InMemoryWalletService
    +
    +

    InMemoryWalletService

    +open class InMemoryWalletService : SingletonSerializeAsToken, WalletService
    +

    This class implements a simple, in memory wallet that tracks states that are owned by us, and also has a convenience +method to auto-generate some self-issued cash states that can be used for test trading. A real wallet would persist +states relevant to us into a database and once such a wallet is implemented, this scaffolding can be removed.

    +
    +
    +

    Exceptions

    + + + + + + + +
    +ClashingThreads +class ClashingThreads : Exception
    +

    Constructors

    + + + + + + + +
    +<init> +InMemoryWalletService(services: ServiceHub)

    This class implements a simple, in memory wallet that tracks states that are owned by us, and also has a convenience +method to auto-generate some self-issued cash states that can be used for test trading. A real wallet would persist +states relevant to us into a database and once such a wallet is implemented, this scaffolding can be removed.

    +
    +

    Properties

    + + + + + + + + + + + + + + + +
    +currentWallet +open val currentWallet: Wallet

    Returns a read-only snapshot of the wallet at the time the call is made. Note that if you consume states or +keys in this wallet, you must inform the wallet service so it can update its internal state.

    +
    +linearHeads +open val linearHeads: Map<SecureHash, StateAndRef<LinearState>>

    Returns a snapshot of the heads of LinearStates

    +
    +updates +open val updates: <ERROR CLASS><Update>

    Get a synchronous Observable of updates. When observations are pushed to the Observer, the Wallet will already incorporate +the update.

    +
    +

    Functions

    + + + + + + + +
    +notifyAll +open fun notifyAll(txns: Iterable<WireTransaction>): Wallet

    Possibly update the wallet by marking as spent states that these transactions consume, and adding any relevant +new states that they create. You should only insert transactions that have been successfully verified here

    +
    +

    Inherited Functions

    + + + + + + + + + + + + + + + + + + + + + + + +
    +linearHeadsOfType_ +open fun <T : LinearState> linearHeadsOfType_(stateType: Class<T>): Map<SecureHash, StateAndRef<T>>

    Returns the linearHeads only when the type of the state would be considered an instanceof the given type.

    +
    +notify +open fun notify(tx: WireTransaction): Wallet

    Same as notifyAll but with a single transaction.

    +
    +statesForRefs +open fun statesForRefs(refs: List<StateRef>): Map<StateRef, TransactionState<*>?>
    +toToken +open fun toToken(context: SerializeAsTokenContext): SerializationToken
    +whenConsumed +open fun whenConsumed(ref: StateRef): <ERROR CLASS><Update>

    Provide a Future for when a StateRef is consumed, which can be very useful in building tests.

    +
    +

    Companion Object Properties

    + + + + + + + +
    +clashingThreads +val Wallet.clashingThreads: Set<SecureHash>
    +

    Extension Functions

    + + + + + + + +
    +linearHeadsOfType +fun <T : LinearState> WalletService.linearHeadsOfType(): <ERROR CLASS>
    +

    Inheritors

    + + + + + + + +
    +NodeWalletService +class NodeWalletService : InMemoryWalletService

    Currently, the node wallet service is just the in-memory wallet service until we have finished evaluating and +selecting a persistence layer (probably an ORM over a SQL DB).

    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-in-memory-wallet-service/linear-heads.html b/docs/build/html/api/com.r3corda.core.testing/-in-memory-wallet-service/linear-heads.html new file mode 100644 index 0000000000..133aebc2ed --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-in-memory-wallet-service/linear-heads.html @@ -0,0 +1,20 @@ + + +InMemoryWalletService.linearHeads - + + + +com.r3corda.core.testing / InMemoryWalletService / linearHeads
    +
    +

    linearHeads

    + +open val linearHeads: Map<SecureHash, StateAndRef<LinearState>>
    +Overrides WalletService.linearHeads
    +

    Returns a snapshot of the heads of LinearStates

    +

    Getter
    +

    Returns a snapshot of the heads of LinearStates

    +

    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-in-memory-wallet-service/notify-all.html b/docs/build/html/api/com.r3corda.core.testing/-in-memory-wallet-service/notify-all.html new file mode 100644 index 0000000000..fcd90b2fd4 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-in-memory-wallet-service/notify-all.html @@ -0,0 +1,22 @@ + + +InMemoryWalletService.notifyAll - + + + +com.r3corda.core.testing / InMemoryWalletService / notifyAll
    +
    +

    notifyAll

    + +open fun notifyAll(txns: Iterable<WireTransaction>): Wallet
    +Overrides WalletService.notifyAll
    +

    Possibly update the wallet by marking as spent states that these transactions consume, and adding any relevant +new states that they create. You should only insert transactions that have been successfully verified here

    +

    Returns the new wallet that resulted from applying the transactions (note: it may quickly become out of date).

    +

    TODO: Consider if theres a good way to enforce the must-be-verified requirement in the type system.

    +
    +
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-in-memory-wallet-service/updates.html b/docs/build/html/api/com.r3corda.core.testing/-in-memory-wallet-service/updates.html new file mode 100644 index 0000000000..7d63274c5d --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-in-memory-wallet-service/updates.html @@ -0,0 +1,22 @@ + + +InMemoryWalletService.updates - + + + +com.r3corda.core.testing / InMemoryWalletService / updates
    +
    +

    updates

    + +open val updates: <ERROR CLASS><Update>
    +Overrides WalletService.updates
    +

    Get a synchronous Observable of updates. When observations are pushed to the Observer, the Wallet will already incorporate +the update.

    +

    Getter
    +

    Get a synchronous Observable of updates. When observations are pushed to the Observer, the Wallet will already incorporate +the update.

    +

    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-a-l-i-c-e.html b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-a-l-i-c-e.html new file mode 100644 index 0000000000..c2d0155e5c --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-a-l-i-c-e.html @@ -0,0 +1,15 @@ + + +JavaTestHelpers.ALICE - + + + +com.r3corda.core.testing / JavaTestHelpers / ALICE
    +
    +

    ALICE

    + +val ALICE: Party
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-a-l-i-c-e_-k-e-y.html b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-a-l-i-c-e_-k-e-y.html new file mode 100644 index 0000000000..a39926500f --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-a-l-i-c-e_-k-e-y.html @@ -0,0 +1,15 @@ + + +JavaTestHelpers.ALICE_KEY - + + + +com.r3corda.core.testing / JavaTestHelpers / ALICE_KEY
    +
    +

    ALICE_KEY

    + +val ALICE_KEY: KeyPair
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-a-l-i-c-e_-p-u-b-k-e-y.html b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-a-l-i-c-e_-p-u-b-k-e-y.html new file mode 100644 index 0000000000..aa5850890e --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-a-l-i-c-e_-p-u-b-k-e-y.html @@ -0,0 +1,15 @@ + + +JavaTestHelpers.ALICE_PUBKEY - + + + +com.r3corda.core.testing / JavaTestHelpers / ALICE_PUBKEY
    +
    +

    ALICE_PUBKEY

    + +val ALICE_PUBKEY: PublicKey
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-a-l-l_-t-e-s-t_-k-e-y-s.html b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-a-l-l_-t-e-s-t_-k-e-y-s.html new file mode 100644 index 0000000000..a63bdd244c --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-a-l-l_-t-e-s-t_-k-e-y-s.html @@ -0,0 +1,15 @@ + + +JavaTestHelpers.ALL_TEST_KEYS - + + + +com.r3corda.core.testing / JavaTestHelpers / ALL_TEST_KEYS
    +
    +

    ALL_TEST_KEYS

    + +val ALL_TEST_KEYS: List<KeyPair>
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-b-o-b.html b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-b-o-b.html new file mode 100644 index 0000000000..e64f4aabfd --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-b-o-b.html @@ -0,0 +1,15 @@ + + +JavaTestHelpers.BOB - + + + +com.r3corda.core.testing / JavaTestHelpers / BOB
    +
    +

    BOB

    + +val BOB: Party
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-b-o-b_-k-e-y.html b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-b-o-b_-k-e-y.html new file mode 100644 index 0000000000..6eafd4a817 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-b-o-b_-k-e-y.html @@ -0,0 +1,15 @@ + + +JavaTestHelpers.BOB_KEY - + + + +com.r3corda.core.testing / JavaTestHelpers / BOB_KEY
    +
    +

    BOB_KEY

    + +val BOB_KEY: KeyPair
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-b-o-b_-p-u-b-k-e-y.html b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-b-o-b_-p-u-b-k-e-y.html new file mode 100644 index 0000000000..f89f65e395 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-b-o-b_-p-u-b-k-e-y.html @@ -0,0 +1,15 @@ + + +JavaTestHelpers.BOB_PUBKEY - + + + +com.r3corda.core.testing / JavaTestHelpers / BOB_PUBKEY
    +
    +

    BOB_PUBKEY

    + +val BOB_PUBKEY: PublicKey
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-d-u-m-m-y_-n-o-t-a-r-y.html b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-d-u-m-m-y_-n-o-t-a-r-y.html new file mode 100644 index 0000000000..cd78b02f82 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-d-u-m-m-y_-n-o-t-a-r-y.html @@ -0,0 +1,15 @@ + + +JavaTestHelpers.DUMMY_NOTARY - + + + +com.r3corda.core.testing / JavaTestHelpers / DUMMY_NOTARY
    +
    +

    DUMMY_NOTARY

    + +val DUMMY_NOTARY: Party
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-d-u-m-m-y_-n-o-t-a-r-y_-k-e-y.html b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-d-u-m-m-y_-n-o-t-a-r-y_-k-e-y.html new file mode 100644 index 0000000000..b714f40380 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-d-u-m-m-y_-n-o-t-a-r-y_-k-e-y.html @@ -0,0 +1,15 @@ + + +JavaTestHelpers.DUMMY_NOTARY_KEY - + + + +com.r3corda.core.testing / JavaTestHelpers / DUMMY_NOTARY_KEY
    +
    +

    DUMMY_NOTARY_KEY

    + +val DUMMY_NOTARY_KEY: KeyPair
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-d-u-m-m-y_-p-u-b-k-e-y_1.html b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-d-u-m-m-y_-p-u-b-k-e-y_1.html new file mode 100644 index 0000000000..c4c112f4a4 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-d-u-m-m-y_-p-u-b-k-e-y_1.html @@ -0,0 +1,15 @@ + + +JavaTestHelpers.DUMMY_PUBKEY_1 - + + + +com.r3corda.core.testing / JavaTestHelpers / DUMMY_PUBKEY_1
    +
    +

    DUMMY_PUBKEY_1

    + +val DUMMY_PUBKEY_1: PublicKey
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-d-u-m-m-y_-p-u-b-k-e-y_2.html b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-d-u-m-m-y_-p-u-b-k-e-y_2.html new file mode 100644 index 0000000000..ff32aea46e --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-d-u-m-m-y_-p-u-b-k-e-y_2.html @@ -0,0 +1,15 @@ + + +JavaTestHelpers.DUMMY_PUBKEY_2 - + + + +com.r3corda.core.testing / JavaTestHelpers / DUMMY_PUBKEY_2
    +
    +

    DUMMY_PUBKEY_2

    + +val DUMMY_PUBKEY_2: PublicKey
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-m-e-g-a_-c-o-r-p.html b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-m-e-g-a_-c-o-r-p.html new file mode 100644 index 0000000000..7eed093912 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-m-e-g-a_-c-o-r-p.html @@ -0,0 +1,15 @@ + + +JavaTestHelpers.MEGA_CORP - + + + +com.r3corda.core.testing / JavaTestHelpers / MEGA_CORP
    +
    +

    MEGA_CORP

    + +val MEGA_CORP: Party
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-m-e-g-a_-c-o-r-p_-k-e-y.html b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-m-e-g-a_-c-o-r-p_-k-e-y.html new file mode 100644 index 0000000000..e334d6a277 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-m-e-g-a_-c-o-r-p_-k-e-y.html @@ -0,0 +1,15 @@ + + +JavaTestHelpers.MEGA_CORP_KEY - + + + +com.r3corda.core.testing / JavaTestHelpers / MEGA_CORP_KEY
    +
    +

    MEGA_CORP_KEY

    + +val MEGA_CORP_KEY: KeyPair
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-m-e-g-a_-c-o-r-p_-p-u-b-k-e-y.html b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-m-e-g-a_-c-o-r-p_-p-u-b-k-e-y.html new file mode 100644 index 0000000000..c072691f19 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-m-e-g-a_-c-o-r-p_-p-u-b-k-e-y.html @@ -0,0 +1,15 @@ + + +JavaTestHelpers.MEGA_CORP_PUBKEY - + + + +com.r3corda.core.testing / JavaTestHelpers / MEGA_CORP_PUBKEY
    +
    +

    MEGA_CORP_PUBKEY

    + +val MEGA_CORP_PUBKEY: PublicKey
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-m-i-n-i_-c-o-r-p.html b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-m-i-n-i_-c-o-r-p.html new file mode 100644 index 0000000000..1f562d4661 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-m-i-n-i_-c-o-r-p.html @@ -0,0 +1,15 @@ + + +JavaTestHelpers.MINI_CORP - + + + +com.r3corda.core.testing / JavaTestHelpers / MINI_CORP
    +
    +

    MINI_CORP

    + +val MINI_CORP: Party
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-m-i-n-i_-c-o-r-p_-k-e-y.html b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-m-i-n-i_-c-o-r-p_-k-e-y.html new file mode 100644 index 0000000000..5abe528f65 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-m-i-n-i_-c-o-r-p_-k-e-y.html @@ -0,0 +1,15 @@ + + +JavaTestHelpers.MINI_CORP_KEY - + + + +com.r3corda.core.testing / JavaTestHelpers / MINI_CORP_KEY
    +
    +

    MINI_CORP_KEY

    + +val MINI_CORP_KEY: KeyPair
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-m-i-n-i_-c-o-r-p_-p-u-b-k-e-y.html b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-m-i-n-i_-c-o-r-p_-p-u-b-k-e-y.html new file mode 100644 index 0000000000..fb9bc69405 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-m-i-n-i_-c-o-r-p_-p-u-b-k-e-y.html @@ -0,0 +1,15 @@ + + +JavaTestHelpers.MINI_CORP_PUBKEY - + + + +com.r3corda.core.testing / JavaTestHelpers / MINI_CORP_PUBKEY
    +
    +

    MINI_CORP_PUBKEY

    + +val MINI_CORP_PUBKEY: PublicKey
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-m-o-c-k_-i-d-e-n-t-i-t-y_-s-e-r-v-i-c-e.html b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-m-o-c-k_-i-d-e-n-t-i-t-y_-s-e-r-v-i-c-e.html new file mode 100644 index 0000000000..11bc0aba4f --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-m-o-c-k_-i-d-e-n-t-i-t-y_-s-e-r-v-i-c-e.html @@ -0,0 +1,15 @@ + + +JavaTestHelpers.MOCK_IDENTITY_SERVICE - + + + +com.r3corda.core.testing / JavaTestHelpers / MOCK_IDENTITY_SERVICE
    +
    +

    MOCK_IDENTITY_SERVICE

    + +val MOCK_IDENTITY_SERVICE: MockIdentityService
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-o-r-a-c-l-e_-k-e-y.html b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-o-r-a-c-l-e_-k-e-y.html new file mode 100644 index 0000000000..cf59822e1e --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-o-r-a-c-l-e_-k-e-y.html @@ -0,0 +1,15 @@ + + +JavaTestHelpers.ORACLE_KEY - + + + +com.r3corda.core.testing / JavaTestHelpers / ORACLE_KEY
    +
    +

    ORACLE_KEY

    + +val ORACLE_KEY: KeyPair
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-o-r-a-c-l-e_-p-u-b-k-e-y.html b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-o-r-a-c-l-e_-p-u-b-k-e-y.html new file mode 100644 index 0000000000..4ccccd3a91 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-o-r-a-c-l-e_-p-u-b-k-e-y.html @@ -0,0 +1,15 @@ + + +JavaTestHelpers.ORACLE_PUBKEY - + + + +com.r3corda.core.testing / JavaTestHelpers / ORACLE_PUBKEY
    +
    +

    ORACLE_PUBKEY

    + +val ORACLE_PUBKEY: PublicKey
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-t-e-s-t_-t-x_-t-i-m-e.html b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-t-e-s-t_-t-x_-t-i-m-e.html new file mode 100644 index 0000000000..34ec515a93 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/-t-e-s-t_-t-x_-t-i-m-e.html @@ -0,0 +1,15 @@ + + +JavaTestHelpers.TEST_TX_TIME - + + + +com.r3corda.core.testing / JavaTestHelpers / TEST_TX_TIME
    +
    +

    TEST_TX_TIME

    + +val TEST_TX_TIME: Instant
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/generate-state-ref.html b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/generate-state-ref.html new file mode 100644 index 0000000000..f904645a70 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/generate-state-ref.html @@ -0,0 +1,15 @@ + + +JavaTestHelpers.generateStateRef - + + + +com.r3corda.core.testing / JavaTestHelpers / generateStateRef
    +
    +

    generateStateRef

    + +fun generateStateRef(): StateRef
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/index.html b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/index.html new file mode 100644 index 0000000000..c6a9402f8c --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/index.html @@ -0,0 +1,179 @@ + + +JavaTestHelpers - + + + +com.r3corda.core.testing / JavaTestHelpers
    +
    +

    JavaTestHelpers

    +object JavaTestHelpers
    +

    JAVA INTEROP. Please keep the following points in mind when extending the Kotlin DSL

    +
    • Annotate functions with Kotlin defaults with @JvmOverloads. This produces the relevant overloads for Java.

      +
    • Void closures in arguments are inconvenient in Java, use overloading to define non-closure variants as well.

      +
    • Top-level funs should be defined in a JavaTestHelpers object and annotated with @JvmStatic first and should be +referred to from the global fun. This allows static importing of JavaTestHelpers in Java tests, which mimicks +top-level funs.

      +
    • Top-level vals are trickier. DO NOT USE@JvmField INSIDEJavaTestHelpers. Its surprisingly easy to +introduce a static init cycle because of the way Kotlin compiles top-level things, which can cause +non-deterministic behaviour, including your field not being initialized at all Instead opt for a proper Kotlin +val either with a custom @JvmStatic get() or a lazy delegate if the initialiser has side-effects See examples below.

      +
    • Infix functions work as regular ones from Java, but symbols with spaces in them dont Define a camelCase variant +as well.

      +
    • varargs are exposed as array types in Java. Define overloads for common cases.

      +
    • The Int.DOLLARS syntax doesnt work from Java. To remedy add a @JvmStatic DOLLARS(Int) function to +JavaTestHelpers

      +

    +
    +
    +
    +

    Properties

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +ALICE +val ALICE: Party
    +ALICE_KEY +val ALICE_KEY: KeyPair
    +ALICE_PUBKEY +val ALICE_PUBKEY: PublicKey
    +ALL_TEST_KEYS +val ALL_TEST_KEYS: List<KeyPair>
    +BOB +val BOB: Party
    +BOB_KEY +val BOB_KEY: KeyPair
    +BOB_PUBKEY +val BOB_PUBKEY: PublicKey
    +DUMMY_NOTARY +val DUMMY_NOTARY: Party
    +DUMMY_NOTARY_KEY +val DUMMY_NOTARY_KEY: KeyPair
    +DUMMY_PUBKEY_1 +val DUMMY_PUBKEY_1: PublicKey
    +DUMMY_PUBKEY_2 +val DUMMY_PUBKEY_2: PublicKey
    +MEGA_CORP +val MEGA_CORP: Party
    +MEGA_CORP_KEY +val MEGA_CORP_KEY: KeyPair
    +MEGA_CORP_PUBKEY +val MEGA_CORP_PUBKEY: PublicKey
    +MINI_CORP +val MINI_CORP: Party
    +MINI_CORP_KEY +val MINI_CORP_KEY: KeyPair
    +MINI_CORP_PUBKEY +val MINI_CORP_PUBKEY: PublicKey
    +MOCK_IDENTITY_SERVICE +val MOCK_IDENTITY_SERVICE: MockIdentityService
    +ORACLE_KEY +val ORACLE_KEY: KeyPair
    +ORACLE_PUBKEY +val ORACLE_PUBKEY: PublicKey
    +TEST_TX_TIME +val TEST_TX_TIME: Instant
    +

    Functions

    + + + + + + + + + + + +
    +generateStateRef +fun generateStateRef(): StateRef
    +transaction +fun transaction(body: TransactionForTest.() -> LastLineShouldTestForAcceptOrFailure): LastLineShouldTestForAcceptOrFailure
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/transaction.html b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/transaction.html new file mode 100644 index 0000000000..8fadb002ff --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-java-test-helpers/transaction.html @@ -0,0 +1,15 @@ + + +JavaTestHelpers.transaction - + + + +com.r3corda.core.testing / JavaTestHelpers / transaction
    +
    +

    transaction

    + +fun transaction(body: TransactionForTest.() -> LastLineShouldTestForAcceptOrFailure): LastLineShouldTestForAcceptOrFailure
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-labeled-output/-init-.html b/docs/build/html/api/com.r3corda.core.testing/-labeled-output/-init-.html index 6e54a5879c..1ef40c4b02 100644 --- a/docs/build/html/api/com.r3corda.core.testing/-labeled-output/-init-.html +++ b/docs/build/html/api/com.r3corda.core.testing/-labeled-output/-init-.html @@ -7,7 +7,7 @@ com.r3corda.core.testing / LabeledOutput / <init>

    <init>

    -LabeledOutput(label: String?, state: ContractState)
    +LabeledOutput(label: String?, state: TransactionState<*>)


    diff --git a/docs/build/html/api/com.r3corda.core.testing/-labeled-output/index.html b/docs/build/html/api/com.r3corda.core.testing/-labeled-output/index.html index 3715cfe423..69d1ffcbfb 100644 --- a/docs/build/html/api/com.r3corda.core.testing/-labeled-output/index.html +++ b/docs/build/html/api/com.r3corda.core.testing/-labeled-output/index.html @@ -17,7 +17,7 @@ <init> -LabeledOutput(label: String?, state: ContractState) +LabeledOutput(label: String?, state: TransactionState<*>) @@ -34,7 +34,7 @@ state -val state: ContractState +val state: TransactionState<*> diff --git a/docs/build/html/api/com.r3corda.core.testing/-labeled-output/state.html b/docs/build/html/api/com.r3corda.core.testing/-labeled-output/state.html index 6ecb3e794d..d78dddd71c 100644 --- a/docs/build/html/api/com.r3corda.core.testing/-labeled-output/state.html +++ b/docs/build/html/api/com.r3corda.core.testing/-labeled-output/state.html @@ -8,7 +8,7 @@

    state

    -val state: ContractState
    +val state: TransactionState<*>


    diff --git a/docs/build/html/api/com.r3corda.core.testing/-last-line-should-test-for-accept-or-failure.html b/docs/build/html/api/com.r3corda.core.testing/-last-line-should-test-for-accept-or-failure.html new file mode 100644 index 0000000000..190733ee28 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-last-line-should-test-for-accept-or-failure.html @@ -0,0 +1,18 @@ + + +LastLineShouldTestForAcceptOrFailure - + + + +com.r3corda.core.testing / LastLineShouldTestForAcceptOrFailure
    +
    +

    LastLineShouldTestForAcceptOrFailure

    +sealed class LastLineShouldTestForAcceptOrFailure
    +

    If you jumped here from a compiler error make sure the last line of your test tests for a transaction accept or fail +This is a dummy type that can only be instantiated by functions in this module. This way we can ensure that all tests +will have as the last line either an accept or a failure test. The name is deliberately long to help make sense of +the triggered diagnostic

    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-test-utils/index.html b/docs/build/html/api/com.r3corda.core.testing/-test-utils/index.html index 1d6e7b34a7..24d7a5b21e 100644 --- a/docs/build/html/api/com.r3corda.core.testing/-test-utils/index.html +++ b/docs/build/html/api/com.r3corda.core.testing/-test-utils/index.html @@ -17,19 +17,19 @@ keypair -val keypair: KeyPair +val keypair: <ERROR CLASS> keypair2 -val keypair2: KeyPair +val keypair2: <ERROR CLASS> keypair3 -val keypair3: KeyPair +val keypair3: <ERROR CLASS> diff --git a/docs/build/html/api/com.r3corda.core.testing/-test-utils/keypair.html b/docs/build/html/api/com.r3corda.core.testing/-test-utils/keypair.html index 83f4b7eed6..1b988a93a3 100644 --- a/docs/build/html/api/com.r3corda.core.testing/-test-utils/keypair.html +++ b/docs/build/html/api/com.r3corda.core.testing/-test-utils/keypair.html @@ -8,7 +8,7 @@

    keypair

    -val keypair: KeyPair
    +val keypair: <ERROR CLASS>


    diff --git a/docs/build/html/api/com.r3corda.core.testing/-test-utils/keypair2.html b/docs/build/html/api/com.r3corda.core.testing/-test-utils/keypair2.html index 7a9cd15792..86883a0259 100644 --- a/docs/build/html/api/com.r3corda.core.testing/-test-utils/keypair2.html +++ b/docs/build/html/api/com.r3corda.core.testing/-test-utils/keypair2.html @@ -8,7 +8,7 @@

    keypair2

    -val keypair2: KeyPair
    +val keypair2: <ERROR CLASS>


    diff --git a/docs/build/html/api/com.r3corda.core.testing/-test-utils/keypair3.html b/docs/build/html/api/com.r3corda.core.testing/-test-utils/keypair3.html index eb34a4c02e..ade61abeae 100644 --- a/docs/build/html/api/com.r3corda.core.testing/-test-utils/keypair3.html +++ b/docs/build/html/api/com.r3corda.core.testing/-test-utils/keypair3.html @@ -8,7 +8,7 @@

    keypair3

    -val keypair3: KeyPair
    +val keypair3: <ERROR CLASS>


    diff --git a/docs/build/html/api/com.r3corda.core.testing/-transaction-for-test/accepts.html b/docs/build/html/api/com.r3corda.core.testing/-transaction-for-test/accepts.html index aaba5b7166..bc32cf90d4 100644 --- a/docs/build/html/api/com.r3corda.core.testing/-transaction-for-test/accepts.html +++ b/docs/build/html/api/com.r3corda.core.testing/-transaction-for-test/accepts.html @@ -8,7 +8,7 @@

    accepts

    -fun accepts(time: Instant = TEST_TX_TIME): Unit
    +fun accepts(time: Instant = TEST_TX_TIME): LastLineShouldTestForAcceptOrFailure


    diff --git a/docs/build/html/api/com.r3corda.core.testing/-transaction-for-test/chain.html b/docs/build/html/api/com.r3corda.core.testing/-transaction-for-test/chain.html index 24b81e828d..96d8cbae1c 100644 --- a/docs/build/html/api/com.r3corda.core.testing/-transaction-for-test/chain.html +++ b/docs/build/html/api/com.r3corda.core.testing/-transaction-for-test/chain.html @@ -7,8 +7,8 @@ com.r3corda.core.testing / TransactionForTest / chain

    chain

    - -fun chain(vararg outputLabels: String, body: TransactionForTest.() -> Unit): TransactionForTest
    + +fun chain(vararg outputLabels: String, body: TransactionForTest.() -> LastLineShouldTestForAcceptOrFailure): TransactionForTest


    diff --git a/docs/build/html/api/com.r3corda.core.testing/-transaction-for-test/fails requirement.html b/docs/build/html/api/com.r3corda.core.testing/-transaction-for-test/fails requirement.html index 7ab883167e..ab6c436172 100644 --- a/docs/build/html/api/com.r3corda.core.testing/-transaction-for-test/fails requirement.html +++ b/docs/build/html/api/com.r3corda.core.testing/-transaction-for-test/fails requirement.html @@ -8,7 +8,7 @@

    fails requirement

    -infix fun fails requirement(msg: String): Unit
    +infix fun fails requirement(msg: String): LastLineShouldTestForAcceptOrFailure

    Used to confirm that the test, when (implicitly) run against the .verify() method, fails with the text of the message



    diff --git a/docs/build/html/api/com.r3corda.core.testing/-transaction-for-test/fails-requirement.html b/docs/build/html/api/com.r3corda.core.testing/-transaction-for-test/fails-requirement.html new file mode 100644 index 0000000000..c2efa380a2 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.testing/-transaction-for-test/fails-requirement.html @@ -0,0 +1,15 @@ + + +TransactionForTest.failsRequirement - + + + +com.r3corda.core.testing / TransactionForTest / failsRequirement
    +
    +

    failsRequirement

    + +fun failsRequirement(msg: String): LastLineShouldTestForAcceptOrFailure
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.testing/-transaction-for-test/index.html b/docs/build/html/api/com.r3corda.core.testing/-transaction-for-test/index.html index 58907c5576..d02d4a13ee 100644 --- a/docs/build/html/api/com.r3corda.core.testing/-transaction-for-test/index.html +++ b/docs/build/html/api/com.r3corda.core.testing/-transaction-for-test/index.html @@ -42,6 +42,18 @@ val outStates: ArrayList<LabeledOutput> + + +signers + +val signers: LinkedHashSet<PublicKey> + + + +type + +val type: General +

    Functions

    @@ -51,13 +63,13 @@ accepts -fun accepts(time: Instant = TEST_TX_TIME): Unit +fun accepts(time: Instant = TEST_TX_TIME): LastLineShouldTestForAcceptOrFailure chain -fun chain(vararg outputLabels: String, body: TransactionForTest.() -> Unit): TransactionForTest +fun chain(vararg outputLabels: String, body: TransactionForTest.() -> LastLineShouldTestForAcceptOrFailure): TransactionForTest @@ -69,14 +81,14 @@ fails requirement -infix fun fails requirement(msg: String): Unit

    Used to confirm that the test, when (implicitly) run against the .verify() method, fails with the text of the message

    +infix fun fails requirement(msg: String): LastLineShouldTestForAcceptOrFailure

    Used to confirm that the test, when (implicitly) run against the .verify() method, fails with the text of the message

    -fails_requirement +failsRequirement -fun fails_requirement(msg: String): Unit +fun failsRequirement(msg: String): LastLineShouldTestForAcceptOrFailure @@ -88,13 +100,14 @@ input -fun input(s: () -> ContractState): <ERROR CLASS> +fun input(s: () -> ContractState): Unit
    +fun input(s: ContractState): Unit rejects -fun rejects(withMessage: String? = null, time: Instant = TEST_TX_TIME): Unit +fun rejects(withMessage: String? = null, time: Instant = TEST_TX_TIME): LastLineShouldTestForAcceptOrFailure @@ -112,7 +125,7 @@ tweak -fun tweak(body: TransactionForTest.() -> Unit): TransactionForTest +fun tweak(body: TransactionForTest.() -> LastLineShouldTestForAcceptOrFailure): LastLineShouldTestForAcceptOrFailure @@ -121,9 +134,16 @@ +addCommand + +fun addCommand(cmd: Command): Unit + + + arg -fun arg(vararg key: PublicKey, c: () -> CommandData): Unit +fun arg(vararg keys: PublicKey, c: () -> CommandData): Unit
    +fun arg(key: PublicKey, c: CommandData): Unit @@ -141,7 +161,8 @@ output -open fun output(label: String? = null, s: () -> ContractState): <ERROR CLASS> +open fun output(label: String? = null, s: () -> ContractState): <ERROR CLASS>
    +open fun output(label: String? = null, s: ContractState): <ERROR CLASS> @@ -154,7 +175,7 @@ transaction -fun transaction(body: TransactionForTest.() -> Unit): Unit +fun transaction(body: TransactionForTest.() -> LastLineShouldTestForAcceptOrFailure): Unit diff --git a/docs/build/html/api/com.r3corda.core.testing/-transaction-for-test/input.html b/docs/build/html/api/com.r3corda.core.testing/-transaction-for-test/input.html index 6a0bbf71aa..a65e8c8e4a 100644 --- a/docs/build/html/api/com.r3corda.core.testing/-transaction-for-test/input.html +++ b/docs/build/html/api/com.r3corda.core.testing/-transaction-for-test/input.html @@ -8,7 +8,9 @@

    input

    -fun input(s: () -> ContractState): <ERROR CLASS>
    +fun input(s: () -> ContractState): Unit
    + +fun input(s: ContractState): Unit


    diff --git a/docs/build/html/api/com.r3corda.core.testing/-transaction-for-test/rejects.html b/docs/build/html/api/com.r3corda.core.testing/-transaction-for-test/rejects.html index d7869bc5dc..d935254cde 100644 --- a/docs/build/html/api/com.r3corda.core.testing/-transaction-for-test/rejects.html +++ b/docs/build/html/api/com.r3corda.core.testing/-transaction-for-test/rejects.html @@ -8,7 +8,7 @@

    rejects

    -fun rejects(withMessage: String? = null, time: Instant = TEST_TX_TIME): Unit
    +fun rejects(withMessage: String? = null, time: Instant = TEST_TX_TIME): LastLineShouldTestForAcceptOrFailure


    diff --git a/docs/build/html/api/com.r3corda.core.testing/-transaction-for-test/tweak.html b/docs/build/html/api/com.r3corda.core.testing/-transaction-for-test/tweak.html index df2ba5305d..ffe3501f75 100644 --- a/docs/build/html/api/com.r3corda.core.testing/-transaction-for-test/tweak.html +++ b/docs/build/html/api/com.r3corda.core.testing/-transaction-for-test/tweak.html @@ -7,8 +7,8 @@ com.r3corda.core.testing / TransactionForTest / tweak

    tweak

    - -fun tweak(body: TransactionForTest.() -> Unit): TransactionForTest
    + +fun tweak(body: TransactionForTest.() -> LastLineShouldTestForAcceptOrFailure): LastLineShouldTestForAcceptOrFailure


    diff --git a/docs/build/html/api/com.r3corda.core.testing/-transaction-group-d-s-l/-roots/index.html b/docs/build/html/api/com.r3corda.core.testing/-transaction-group-d-s-l/-roots/index.html index 77ea845266..34f1d0a3fb 100644 --- a/docs/build/html/api/com.r3corda.core.testing/-transaction-group-d-s-l/-roots/index.html +++ b/docs/build/html/api/com.r3corda.core.testing/-transaction-group-d-s-l/-roots/index.html @@ -28,14 +28,15 @@ roots -fun roots(body: Roots<T>.() -> Unit): Unit +fun roots(body: Roots<T>.() -> Unit): Unit

    Note: Dont delete, this is intended to trigger compiler diagnostic when the DSL primitive is used in the wrong place

    + transaction -fun transaction(vararg outputStates: LabeledOutput): Unit
    -fun transaction(body: WireTransactionDSL<T>.() -> Unit): Unit +fun transaction(vararg outputStates: LabeledOutput): Roots<T>fun transaction(body: WireTransactionDSL<T>.() -> Unit): Unit

    Note: Dont delete, this is intended to trigger compiler diagnostic when the DSL primitive is used in the wrong place

    + diff --git a/docs/build/html/api/com.r3corda.core.testing/-transaction-group-d-s-l/-roots/roots.html b/docs/build/html/api/com.r3corda.core.testing/-transaction-group-d-s-l/-roots/roots.html index d6100d78ad..8e634c8a58 100644 --- a/docs/build/html/api/com.r3corda.core.testing/-transaction-group-d-s-l/-roots/roots.html +++ b/docs/build/html/api/com.r3corda.core.testing/-transaction-group-d-s-l/-roots/roots.html @@ -11,6 +11,7 @@ fun roots(body: Roots<T>.() -> Unit): Unit
    Deprecated: Does not nest

    +

    Note: Dont delete, this is intended to trigger compiler diagnostic when the DSL primitive is used in the wrong place



    diff --git a/docs/build/html/api/com.r3corda.core.testing/-transaction-group-d-s-l/-roots/transaction.html b/docs/build/html/api/com.r3corda.core.testing/-transaction-group-d-s-l/-roots/transaction.html index 6aa05d2270..2f3cf367a1 100644 --- a/docs/build/html/api/com.r3corda.core.testing/-transaction-group-d-s-l/-roots/transaction.html +++ b/docs/build/html/api/com.r3corda.core.testing/-transaction-group-d-s-l/-roots/transaction.html @@ -8,11 +8,14 @@

    transaction

    -fun transaction(vararg outputStates: LabeledOutput): Unit
    +fun transaction(vararg outputStates: LabeledOutput): Roots<T>
    +
    +
    fun transaction(body: WireTransactionDSL<T>.() -> Unit): Unit
    Deprecated: Use the vararg form of transaction inside roots

    +

    Note: Dont delete, this is intended to trigger compiler diagnostic when the DSL primitive is used in the wrong place



    diff --git a/docs/build/html/api/com.r3corda.core.testing/-transaction-group-d-s-l/-wire-transaction-d-s-l/index.html b/docs/build/html/api/com.r3corda.core.testing/-transaction-group-d-s-l/-wire-transaction-d-s-l/index.html index 69beac9a64..31263df945 100644 --- a/docs/build/html/api/com.r3corda.core.testing/-transaction-group-d-s-l/-wire-transaction-d-s-l/index.html +++ b/docs/build/html/api/com.r3corda.core.testing/-transaction-group-d-s-l/-wire-transaction-d-s-l/index.html @@ -42,6 +42,18 @@ val outStates: ArrayList<LabeledOutput> + + +signers + +val signers: LinkedHashSet<PublicKey> + + + +type + +val type: General +

    Functions

    @@ -66,9 +78,16 @@ +addCommand + +fun addCommand(cmd: Command): Unit + + + arg -fun arg(vararg key: PublicKey, c: () -> CommandData): Unit +fun arg(vararg keys: PublicKey, c: () -> CommandData): Unit
    +fun arg(key: PublicKey, c: CommandData): Unit @@ -86,7 +105,8 @@ output -open fun output(label: String? = null, s: () -> ContractState): <ERROR CLASS> +open fun output(label: String? = null, s: () -> ContractState): <ERROR CLASS>
    +open fun output(label: String? = null, s: ContractState): <ERROR CLASS> @@ -99,7 +119,7 @@ transaction -fun transaction(body: TransactionForTest.() -> Unit): Unit +fun transaction(body: TransactionForTest.() -> LastLineShouldTestForAcceptOrFailure): Unit diff --git a/docs/build/html/api/com.r3corda.core.testing/-transaction-group-d-s-l/index.html b/docs/build/html/api/com.r3corda.core.testing/-transaction-group-d-s-l/index.html index f31843d0b5..3f4504c81e 100644 --- a/docs/build/html/api/com.r3corda.core.testing/-transaction-group-d-s-l/index.html +++ b/docs/build/html/api/com.r3corda.core.testing/-transaction-group-d-s-l/index.html @@ -56,7 +56,7 @@ output -val String.output: T +val String.output: TransactionState<T> @@ -85,7 +85,7 @@ labelForState -fun labelForState(state: T): String? +fun labelForState(output: TransactionState<*>): String? @@ -128,7 +128,8 @@ transactionGroup -fun transactionGroup(body: TransactionGroupDSL<T>.() -> Unit): Unit +fun transactionGroup(body: TransactionGroupDSL<T>.() -> Unit): Unit

    Note: Dont delete, this is intended to trigger compiler diagnostic when the DSL primitive is used in the wrong place

    + diff --git a/docs/build/html/api/com.r3corda.core.testing/-transaction-group-d-s-l/label-for-state.html b/docs/build/html/api/com.r3corda.core.testing/-transaction-group-d-s-l/label-for-state.html index a3a0b174e5..b888166bea 100644 --- a/docs/build/html/api/com.r3corda.core.testing/-transaction-group-d-s-l/label-for-state.html +++ b/docs/build/html/api/com.r3corda.core.testing/-transaction-group-d-s-l/label-for-state.html @@ -7,8 +7,8 @@ com.r3corda.core.testing / TransactionGroupDSL / labelForState

    labelForState

    - -fun labelForState(state: T): String?
    + +fun labelForState(output: TransactionState<*>): String?


    diff --git a/docs/build/html/api/com.r3corda.core.testing/-transaction-group-d-s-l/output.html b/docs/build/html/api/com.r3corda.core.testing/-transaction-group-d-s-l/output.html index cd2f2399b6..6b60514e36 100644 --- a/docs/build/html/api/com.r3corda.core.testing/-transaction-group-d-s-l/output.html +++ b/docs/build/html/api/com.r3corda.core.testing/-transaction-group-d-s-l/output.html @@ -8,7 +8,7 @@

    output

    -val String.output: T
    +val String.output: TransactionState<T>


    diff --git a/docs/build/html/api/com.r3corda.core.testing/-transaction-group-d-s-l/transaction-group.html b/docs/build/html/api/com.r3corda.core.testing/-transaction-group-d-s-l/transaction-group.html index 6a4836a971..3b1b92814d 100644 --- a/docs/build/html/api/com.r3corda.core.testing/-transaction-group-d-s-l/transaction-group.html +++ b/docs/build/html/api/com.r3corda.core.testing/-transaction-group-d-s-l/transaction-group.html @@ -11,6 +11,7 @@ fun transactionGroup(body: TransactionGroupDSL<T>.() -> Unit): Unit
    Deprecated: Does not nest

    +

    Note: Dont delete, this is intended to trigger compiler diagnostic when the DSL primitive is used in the wrong place



    diff --git a/docs/build/html/api/com.r3corda.core.testing/index.html b/docs/build/html/api/com.r3corda.core.testing/index.html index ff20a008e5..15757b2eff 100644 --- a/docs/build/html/api/com.r3corda.core.testing/index.html +++ b/docs/build/html/api/com.r3corda.core.testing/index.html @@ -18,12 +18,50 @@ +AlwaysSucceedContract + +class AlwaysSucceedContract : Contract + + + +DummyLinearState + +class DummyLinearState : LinearState + + + +InMemoryWalletService + +open class InMemoryWalletService : SingletonSerializeAsToken, WalletService

    This class implements a simple, in memory wallet that tracks states that are owned by us, and also has a convenience +method to auto-generate some self-issued cash states that can be used for test trading. A real wallet would persist +states relevant to us into a database and once such a wallet is implemented, this scaffolding can be removed.

    + + + + +JavaTestHelpers + +object JavaTestHelpers

    JAVA INTEROP. Please keep the following points in mind when extending the Kotlin DSL

    + + + + LabeledOutput class LabeledOutput +LastLineShouldTestForAcceptOrFailure + +sealed class LastLineShouldTestForAcceptOrFailure

    If you jumped here from a compiler error make sure the last line of your test tests for a transaction accept or fail +This is a dummy type that can only be instantiated by functions in this module. This way we can ensure that all tests +will have as the last line either an accept or a failure test. The name is deliberately long to help make sense of +the triggered diagnostic

    + + + + TestUtils object TestUtils @@ -67,7 +105,7 @@ ALL_TEST_KEYS -val ALL_TEST_KEYS: <ERROR CLASS> +val ALL_TEST_KEYS: List<KeyPair> @@ -103,13 +141,13 @@ DUMMY_PUBKEY_1 -val DUMMY_PUBKEY_1: DummyPublicKey +val DUMMY_PUBKEY_1: PublicKey DUMMY_PUBKEY_2 -val DUMMY_PUBKEY_2: DummyPublicKey +val DUMMY_PUBKEY_2: PublicKey @@ -192,7 +230,7 @@ label -infix fun ContractState.label(label: String): LabeledOutput +infix fun TransactionState<*>.label(label: String): LabeledOutput @@ -205,7 +243,7 @@ transaction -fun transaction(body: TransactionForTest.() -> Unit): <ERROR CLASS> +fun transaction(body: TransactionForTest.() -> LastLineShouldTestForAcceptOrFailure): LastLineShouldTestForAcceptOrFailure diff --git a/docs/build/html/api/com.r3corda.core.testing/label.html b/docs/build/html/api/com.r3corda.core.testing/label.html index e9a112a252..192ab36b79 100644 --- a/docs/build/html/api/com.r3corda.core.testing/label.html +++ b/docs/build/html/api/com.r3corda.core.testing/label.html @@ -7,8 +7,8 @@ com.r3corda.core.testing / label

    label

    - -infix fun ContractState.label(label: String): LabeledOutput
    + +infix fun TransactionState<*>.label(label: String): LabeledOutput


    diff --git a/docs/build/html/api/com.r3corda.core.testing/transaction.html b/docs/build/html/api/com.r3corda.core.testing/transaction.html index 0832008d7f..664582b199 100644 --- a/docs/build/html/api/com.r3corda.core.testing/transaction.html +++ b/docs/build/html/api/com.r3corda.core.testing/transaction.html @@ -7,8 +7,8 @@ com.r3corda.core.testing / transaction

    transaction

    - -fun transaction(body: TransactionForTest.() -> Unit): <ERROR CLASS>
    + +fun transaction(body: TransactionForTest.() -> LastLineShouldTestForAcceptOrFailure): LastLineShouldTestForAcceptOrFailure


    diff --git a/docs/build/html/api/com.r3corda.core.utilities/-non-empty-set-serializer/index.html b/docs/build/html/api/com.r3corda.core.utilities/-non-empty-set-serializer/index.html new file mode 100644 index 0000000000..817bfd50d4 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.utilities/-non-empty-set-serializer/index.html @@ -0,0 +1,33 @@ + + +NonEmptySetSerializer - + + + +com.r3corda.core.utilities / NonEmptySetSerializer
    +
    +

    NonEmptySetSerializer

    +object NonEmptySetSerializer
    +

    Custom serializer which understands it has to read in an item before +trying to construct the set.

    +
    +
    +

    Functions

    + + + + + + + + + + + +
    +read +fun read(kryo: <ERROR CLASS>, input: <ERROR CLASS>, type: Class<NonEmptySet<Any>>): NonEmptySet<Any>
    +write +fun write(kryo: <ERROR CLASS>, output: <ERROR CLASS>, obj: NonEmptySet<Any>): Unit
    + + diff --git a/docs/build/html/api/com.r3corda.core.utilities/-non-empty-set-serializer/read.html b/docs/build/html/api/com.r3corda.core.utilities/-non-empty-set-serializer/read.html new file mode 100644 index 0000000000..7fdaca5f02 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.utilities/-non-empty-set-serializer/read.html @@ -0,0 +1,15 @@ + + +NonEmptySetSerializer.read - + + + +com.r3corda.core.utilities / NonEmptySetSerializer / read
    +
    +

    read

    + +fun read(kryo: <ERROR CLASS>, input: <ERROR CLASS>, type: Class<NonEmptySet<Any>>): NonEmptySet<Any>
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.utilities/-non-empty-set-serializer/write.html b/docs/build/html/api/com.r3corda.core.utilities/-non-empty-set-serializer/write.html new file mode 100644 index 0000000000..ffee64de51 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.utilities/-non-empty-set-serializer/write.html @@ -0,0 +1,15 @@ + + +NonEmptySetSerializer.write - + + + +com.r3corda.core.utilities / NonEmptySetSerializer / write
    +
    +

    write

    + +fun write(kryo: <ERROR CLASS>, output: <ERROR CLASS>, obj: NonEmptySet<Any>): Unit
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.utilities/-non-empty-set/-init-.html b/docs/build/html/api/com.r3corda.core.utilities/-non-empty-set/-init-.html index 1639987355..3bd4e78196 100644 --- a/docs/build/html/api/com.r3corda.core.utilities/-non-empty-set/-init-.html +++ b/docs/build/html/api/com.r3corda.core.utilities/-non-empty-set/-init-.html @@ -7,9 +7,10 @@ com.r3corda.core.utilities / NonEmptySet / <init>

    <init>

    -NonEmptySet(initial: T, set: MutableSet<T> = mutableSetOf())
    +NonEmptySet(initial: T)

    A set which is constrained to ensure it can never be empty. An initial value must be provided at -construction, and attempting to remove the last element will cause an IllegalStateException.

    +construction, and attempting to remove the last element will cause an IllegalStateException. +The underlying set is exposed for Kryo to access, but should not be accessed directly.



    diff --git a/docs/build/html/api/com.r3corda.core.utilities/-non-empty-set/index.html b/docs/build/html/api/com.r3corda.core.utilities/-non-empty-set/index.html index 96e0d1a8a6..deda8d9a77 100644 --- a/docs/build/html/api/com.r3corda.core.utilities/-non-empty-set/index.html +++ b/docs/build/html/api/com.r3corda.core.utilities/-non-empty-set/index.html @@ -9,7 +9,8 @@

    NonEmptySet

    class NonEmptySet<T> : MutableSet<T>

    A set which is constrained to ensure it can never be empty. An initial value must be provided at -construction, and attempting to remove the last element will cause an IllegalStateException.

    +construction, and attempting to remove the last element will cause an IllegalStateException. +The underlying set is exposed for Kryo to access, but should not be accessed directly.



    Types

    @@ -30,8 +31,9 @@ construction, and attempting to remove the last element will cause an IllegalSta <init> -NonEmptySet(initial: T, set: MutableSet<T> = mutableSetOf())

    A set which is constrained to ensure it can never be empty. An initial value must be provided at -construction, and attempting to remove the last element will cause an IllegalStateException.

    +NonEmptySet(initial: T)

    A set which is constrained to ensure it can never be empty. An initial value must be provided at +construction, and attempting to remove the last element will cause an IllegalStateException. +The underlying set is exposed for Kryo to access, but should not be accessed directly.

    @@ -130,5 +132,19 @@ construction, and attempting to remove the last element will cause an IllegalSta +

    Extension Functions

    + + + + + + + +
    +noneOrSingle +fun <T> Iterable<T>.noneOrSingle(predicate: (T) -> Boolean): T?

    Returns the single element matching the given predicate, or null if element was not found, +or throws if more than one element was found.

    +fun <T> Iterable<T>.noneOrSingle(): T?

    Returns single element, or null if element was not found, or throws if more than one element was found.

    +
    diff --git a/docs/build/html/api/com.r3corda.core.utilities/-progress-tracker/-step/index.html b/docs/build/html/api/com.r3corda.core.utilities/-progress-tracker/-step/index.html index 1fae5cc2a1..3ab5534161 100644 --- a/docs/build/html/api/com.r3corda.core.utilities/-progress-tracker/-step/index.html +++ b/docs/build/html/api/com.r3corda.core.utilities/-progress-tracker/-step/index.html @@ -56,15 +56,15 @@ -ANNOUNCING +ANNOUNCING object ANNOUNCING : Step -ANNOUNCING +APPROVING -object ANNOUNCING : Step +object APPROVING : Step @@ -104,33 +104,9 @@ -FETCHING +LOADING -object FETCHING : Step - - - -FIXING - -object FIXING : Step - - - -ITERATING_DEALS - -object ITERATING_DEALS : Step - - - -ITERATING_FIXINGS - -object ITERATING_FIXINGS : Step - - - -LOCAL - -object LOCAL : Step +class LOADING : Step @@ -146,6 +122,12 @@ +NOTARY + +object NOTARY : Step + + + NOTIFYING object NOTIFYING : Step @@ -194,6 +176,12 @@ +REJECTING + +object REJECTING : Step + + + REQUESTING object REQUESTING : Step @@ -207,12 +195,6 @@ -SELF_ISSUING - -object SELF_ISSUING : Step - - - SENDING_SIGS object SENDING_SIGS : Step @@ -255,9 +237,9 @@ -STARTING_BUY +SIGNING -object STARTING_BUY : Step +object SIGNING : Step @@ -273,12 +255,6 @@ -TRADING - -object TRADING : Step - - - UNSTARTED object UNSTARTED : Step @@ -315,9 +291,9 @@ -WAITING_FOR_SELLER_TO_CONNECT +VERIFYING -object WAITING_FOR_SELLER_TO_CONNECT : Step +object VERIFYING : Step diff --git a/docs/build/html/api/com.r3corda.core.utilities/-time-window/-init-.html b/docs/build/html/api/com.r3corda.core.utilities/-time-window/-init-.html new file mode 100644 index 0000000000..05f9b25b92 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.utilities/-time-window/-init-.html @@ -0,0 +1,15 @@ + + +TimeWindow.<init> - + + + +com.r3corda.core.utilities / TimeWindow / <init>
    +
    +

    <init>

    +TimeWindow(start: Instant, duration: Duration)
    +

    A class representing a window in time from a particular instant, lasting a specified duration.

    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.utilities/-time-window/duration.html b/docs/build/html/api/com.r3corda.core.utilities/-time-window/duration.html new file mode 100644 index 0000000000..9b007335e3 --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.utilities/-time-window/duration.html @@ -0,0 +1,15 @@ + + +TimeWindow.duration - + + + +com.r3corda.core.utilities / TimeWindow / duration
    +
    +

    duration

    + +val duration: Duration
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.utilities/-time-window/end.html b/docs/build/html/api/com.r3corda.core.utilities/-time-window/end.html new file mode 100644 index 0000000000..f38321389b --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.utilities/-time-window/end.html @@ -0,0 +1,15 @@ + + +TimeWindow.end - + + + +com.r3corda.core.utilities / TimeWindow / end
    +
    +

    end

    + +val end: Instant
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.utilities/-time-window/index.html b/docs/build/html/api/com.r3corda.core.utilities/-time-window/index.html new file mode 100644 index 0000000000..d8f11c21fa --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.utilities/-time-window/index.html @@ -0,0 +1,50 @@ + + +TimeWindow - + + + +com.r3corda.core.utilities / TimeWindow
    +
    +

    TimeWindow

    +data class TimeWindow
    +

    A class representing a window in time from a particular instant, lasting a specified duration.

    +
    +
    +

    Constructors

    + + + + + + + +
    +<init> +TimeWindow(start: Instant, duration: Duration)

    A class representing a window in time from a particular instant, lasting a specified duration.

    +
    +

    Properties

    + + + + + + + + + + + + + + + +
    +duration +val duration: Duration
    +end +val end: Instant
    +start +val start: Instant
    + + diff --git a/docs/build/html/api/com.r3corda.core.utilities/-time-window/start.html b/docs/build/html/api/com.r3corda.core.utilities/-time-window/start.html new file mode 100644 index 0000000000..a30d34895b --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.utilities/-time-window/start.html @@ -0,0 +1,15 @@ + + +TimeWindow.start - + + + +com.r3corda.core.utilities / TimeWindow / start
    +
    +

    start

    + +val start: Instant
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core.utilities/index.html b/docs/build/html/api/com.r3corda.core.utilities/index.html index ed1e868ade..8ad6fcfaf7 100644 --- a/docs/build/html/api/com.r3corda.core.utilities/index.html +++ b/docs/build/html/api/com.r3corda.core.utilities/index.html @@ -29,7 +29,16 @@ NonEmptySet class NonEmptySet<T> : MutableSet<T>

    A set which is constrained to ensure it can never be empty. An initial value must be provided at -construction, and attempting to remove the last element will cause an IllegalStateException.

    +construction, and attempting to remove the last element will cause an IllegalStateException. +The underlying set is exposed for Kryo to access, but should not be accessed directly.

    + + + + +NonEmptySetSerializer + +object NonEmptySetSerializer

    Custom serializer which understands it has to read in an item before +trying to construct the set.

    @@ -51,6 +60,13 @@ white box unit tests to ensure that code is accessing a data store as much as yo +TimeWindow + +data class TimeWindow

    A class representing a window in time from a particular instant, lasting a specified duration.

    + + + + UntrustworthyData class UntrustworthyData<T>

    A small utility to approximate taint tracking: if a method gives you back one of these, it means the data came from @@ -77,6 +93,15 @@ first. The wrapper helps you to avoid forgetting this vital step. Things you mig +suggestInterestRateAnnouncementTimeWindow + +fun suggestInterestRateAnnouncementTimeWindow(index: String, source: String, date: LocalDate): TimeWindow

    This whole file exists as short cuts to get demos working. In reality wed have static data and/or rules engine +defining things like this. It currently resides in the core module because it needs to be visible to the IRS +contract.

    + + + + trace fun <ERROR CLASS>.trace(msg: () -> String): Unit diff --git a/docs/build/html/api/com.r3corda.core.utilities/suggest-interest-rate-announcement-time-window.html b/docs/build/html/api/com.r3corda.core.utilities/suggest-interest-rate-announcement-time-window.html new file mode 100644 index 0000000000..9937a1844e --- /dev/null +++ b/docs/build/html/api/com.r3corda.core.utilities/suggest-interest-rate-announcement-time-window.html @@ -0,0 +1,18 @@ + + +suggestInterestRateAnnouncementTimeWindow - + + + +com.r3corda.core.utilities / suggestInterestRateAnnouncementTimeWindow
    +
    +

    suggestInterestRateAnnouncementTimeWindow

    + +fun suggestInterestRateAnnouncementTimeWindow(index: String, source: String, date: LocalDate): TimeWindow
    +

    This whole file exists as short cuts to get demos working. In reality wed have static data and/or rules engine +defining things like this. It currently resides in the core module because it needs to be visible to the IRS +contract.

    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core/-retryable-exception/index.html b/docs/build/html/api/com.r3corda.core/-retryable-exception/index.html index 8d3a1e7929..4040b705cc 100644 --- a/docs/build/html/api/com.r3corda.core/-retryable-exception/index.html +++ b/docs/build/html/api/com.r3corda.core/-retryable-exception/index.html @@ -28,5 +28,16 @@ again.

    +

    Inheritors

    + + + + + + + +
    +UnknownFix +class UnknownFix : RetryableException
    diff --git a/docs/build/html/api/com.r3corda.core/-thread-box/-init-.html b/docs/build/html/api/com.r3corda.core/-thread-box/-init-.html index 0774d4d124..c394dda3fc 100644 --- a/docs/build/html/api/com.r3corda.core/-thread-box/-init-.html +++ b/docs/build/html/api/com.r3corda.core/-thread-box/-init-.html @@ -7,7 +7,7 @@ com.r3corda.core / ThreadBox / <init>

    <init>

    -ThreadBox(content: T, lock: Lock = ReentrantLock())
    +ThreadBox(content: T, lock: ReentrantLock = ReentrantLock())

    A threadbox is a simple utility that makes it harder to forget to take a lock before accessing some shared state. Simply define a private class to hold the data that must be grouped under the same lock, and then pass the only instance to the ThreadBox constructor. You can now use the locked method with a lambda to take the lock in a diff --git a/docs/build/html/api/com.r3corda.core/-thread-box/already-locked.html b/docs/build/html/api/com.r3corda.core/-thread-box/already-locked.html new file mode 100644 index 0000000000..eda07b192a --- /dev/null +++ b/docs/build/html/api/com.r3corda.core/-thread-box/already-locked.html @@ -0,0 +1,15 @@ + + +ThreadBox.alreadyLocked - + + + +com.r3corda.core / ThreadBox / alreadyLocked
    +
    +

    alreadyLocked

    + +inline fun <R> alreadyLocked(body: T.() -> R): R
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.core/-thread-box/index.html b/docs/build/html/api/com.r3corda.core/-thread-box/index.html index 27c0ac587a..285e300da9 100644 --- a/docs/build/html/api/com.r3corda.core/-thread-box/index.html +++ b/docs/build/html/api/com.r3corda.core/-thread-box/index.html @@ -30,7 +30,7 @@ private val state = ThreadBox(MutableState())

    <init> -ThreadBox(content: T, lock: Lock = ReentrantLock())

    A threadbox is a simple utility that makes it harder to forget to take a lock before accessing some shared state. +ThreadBox(content: T, lock: ReentrantLock = ReentrantLock())

    A threadbox is a simple utility that makes it harder to forget to take a lock before accessing some shared state. Simply define a private class to hold the data that must be grouped under the same lock, and then pass the only instance to the ThreadBox constructor. You can now use the locked method with a lambda to take the lock in a way that ensures itll be released if theres an exception.

    @@ -51,7 +51,7 @@ way that ensures itll be released if theres an exception.

    lock -val lock: Lock +val lock: ReentrantLock @@ -60,6 +60,12 @@ way that ensures itll be released if theres an exception.

    +alreadyLocked + +fun <R> alreadyLocked(body: T.() -> R): R + + + locked fun <R> locked(body: T.() -> R): R diff --git a/docs/build/html/api/com.r3corda.core/-thread-box/lock.html b/docs/build/html/api/com.r3corda.core/-thread-box/lock.html index ea2f2d3183..4bf17dbd2a 100644 --- a/docs/build/html/api/com.r3corda.core/-thread-box/lock.html +++ b/docs/build/html/api/com.r3corda.core/-thread-box/lock.html @@ -8,7 +8,7 @@

    lock

    -val lock: Lock
    +val lock: ReentrantLock


    diff --git a/docs/build/html/api/com.r3corda.demos.protocols/-auto-offer-protocol/-auto-offer-message/-init-.html b/docs/build/html/api/com.r3corda.demos.protocols/-auto-offer-protocol/-auto-offer-message/-init-.html index b32761396e..bc918c5633 100644 --- a/docs/build/html/api/com.r3corda.demos.protocols/-auto-offer-protocol/-auto-offer-message/-init-.html +++ b/docs/build/html/api/com.r3corda.demos.protocols/-auto-offer-protocol/-auto-offer-message/-init-.html @@ -7,7 +7,7 @@ com.r3corda.demos.protocols / AutoOfferProtocol / AutoOfferMessage / <init>

    <init>

    -AutoOfferMessage(otherSide: SingleMessageRecipient, otherSessionID: Long, dealBeingOffered: DealState)
    +AutoOfferMessage(otherSide: Party, notary: Party, otherSessionID: Long, dealBeingOffered: DealState)


    diff --git a/docs/build/html/api/com.r3corda.demos.protocols/-auto-offer-protocol/-auto-offer-message/index.html b/docs/build/html/api/com.r3corda.demos.protocols/-auto-offer-protocol/-auto-offer-message/index.html index 58e910e398..155b64f0b8 100644 --- a/docs/build/html/api/com.r3corda.demos.protocols/-auto-offer-protocol/-auto-offer-message/index.html +++ b/docs/build/html/api/com.r3corda.demos.protocols/-auto-offer-protocol/-auto-offer-message/index.html @@ -17,7 +17,7 @@ <init> -AutoOfferMessage(otherSide: SingleMessageRecipient, otherSessionID: Long, dealBeingOffered: DealState) +AutoOfferMessage(otherSide: Party, notary: Party, otherSessionID: Long, dealBeingOffered: DealState) @@ -32,6 +32,12 @@ +notary + +val notary: Party + + + otherSessionID val otherSessionID: Long @@ -40,7 +46,7 @@ otherSide -val otherSide: SingleMessageRecipient +val otherSide: Party diff --git a/docs/build/html/api/com.r3corda.demos.protocols/-auto-offer-protocol/-auto-offer-message/notary.html b/docs/build/html/api/com.r3corda.demos.protocols/-auto-offer-protocol/-auto-offer-message/notary.html new file mode 100644 index 0000000000..5bdd0c04c9 --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos.protocols/-auto-offer-protocol/-auto-offer-message/notary.html @@ -0,0 +1,15 @@ + + +AutoOfferProtocol.AutoOfferMessage.notary - + + + +com.r3corda.demos.protocols / AutoOfferProtocol / AutoOfferMessage / notary
    +
    +

    notary

    + +val notary: Party
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos.protocols/-auto-offer-protocol/-auto-offer-message/other-side.html b/docs/build/html/api/com.r3corda.demos.protocols/-auto-offer-protocol/-auto-offer-message/other-side.html index 1cf7c3c027..558b9a3b0a 100644 --- a/docs/build/html/api/com.r3corda.demos.protocols/-auto-offer-protocol/-auto-offer-message/other-side.html +++ b/docs/build/html/api/com.r3corda.demos.protocols/-auto-offer-protocol/-auto-offer-message/other-side.html @@ -8,7 +8,7 @@

    otherSide

    -val otherSide: SingleMessageRecipient
    +val otherSide: Party


    diff --git a/docs/build/html/api/com.r3corda.demos.protocols/-auto-offer-protocol/-requester/index.html b/docs/build/html/api/com.r3corda.demos.protocols/-auto-offer-protocol/-requester/index.html index b117c9a5df..928eb01c72 100644 --- a/docs/build/html/api/com.r3corda.demos.protocols/-auto-offer-protocol/-requester/index.html +++ b/docs/build/html/api/com.r3corda.demos.protocols/-auto-offer-protocol/-requester/index.html @@ -7,7 +7,7 @@ com.r3corda.demos.protocols / AutoOfferProtocol / Requester

    Requester

    -class Requester<T> : ProtocolLogic<SignedTransaction>
    +class Requester : ProtocolLogic<SignedTransaction>


    Types

    @@ -86,7 +86,9 @@ progress.

    serviceHub -val serviceHub: ServiceHub

    Provides access to big, heavy classes that may be reconstructed from time to time, e.g. across restarts

    +val serviceHub: ServiceHub

    Provides access to big, heavy classes that may be reconstructed from time to time, e.g. across restarts. It is +only available once the protocol has started, which means it cannnot be accessed in the constructor. Either +access this lazily or from inside call.

    @@ -123,13 +125,13 @@ progress.

    send -fun send(topic: String, destination: MessageRecipients, sessionID: Long, obj: Any): Unit +fun send(topic: String, destination: Party, sessionID: Long, payload: Any): Unit sendAndReceive -fun <T : Any> sendAndReceive(topic: String, destination: MessageRecipients, sessionIDForSend: Long, sessionIDForReceive: Long, obj: Any): UntrustworthyData<T> +fun <T : Any> sendAndReceive(topic: String, destination: Party, sessionIDForSend: Long, sessionIDForReceive: Long, payload: Any): UntrustworthyData<T> diff --git a/docs/build/html/api/com.r3corda.demos.protocols/-auto-offer-protocol/index.html b/docs/build/html/api/com.r3corda.demos.protocols/-auto-offer-protocol/index.html index 3a2b47999b..3c35b6f502 100644 --- a/docs/build/html/api/com.r3corda.demos.protocols/-auto-offer-protocol/index.html +++ b/docs/build/html/api/com.r3corda.demos.protocols/-auto-offer-protocol/index.html @@ -35,7 +35,7 @@ or the protocol would have to reach out to external systems (or users) to verify Requester -class Requester<T> : ProtocolLogic<SignedTransaction> +class Requester : ProtocolLogic<SignedTransaction> diff --git a/docs/build/html/api/com.r3corda.demos.protocols/-exit-server-protocol/-broadcast/index.html b/docs/build/html/api/com.r3corda.demos.protocols/-exit-server-protocol/-broadcast/index.html index 1d0b820801..124e892f4d 100644 --- a/docs/build/html/api/com.r3corda.demos.protocols/-exit-server-protocol/-broadcast/index.html +++ b/docs/build/html/api/com.r3corda.demos.protocols/-exit-server-protocol/-broadcast/index.html @@ -67,7 +67,9 @@ progress.

    serviceHub -val serviceHub: ServiceHub

    Provides access to big, heavy classes that may be reconstructed from time to time, e.g. across restarts

    +val serviceHub: ServiceHub

    Provides access to big, heavy classes that may be reconstructed from time to time, e.g. across restarts. It is +only available once the protocol has started, which means it cannnot be accessed in the constructor. Either +access this lazily or from inside call.

    @@ -98,13 +100,13 @@ progress.

    send -fun send(topic: String, destination: MessageRecipients, sessionID: Long, obj: Any): Unit +fun send(topic: String, destination: Party, sessionID: Long, payload: Any): Unit sendAndReceive -fun <T : Any> sendAndReceive(topic: String, destination: MessageRecipients, sessionIDForSend: Long, sessionIDForReceive: Long, obj: Any): UntrustworthyData<T> +fun <T : Any> sendAndReceive(topic: String, destination: Party, sessionIDForSend: Long, sessionIDForReceive: Long, payload: Any): UntrustworthyData<T> diff --git a/docs/build/html/api/com.r3corda.demos.protocols/-update-business-day-protocol/-broadcast/call.html b/docs/build/html/api/com.r3corda.demos.protocols/-update-business-day-protocol/-broadcast/call.html index e74d782932..5cdcdcc64d 100644 --- a/docs/build/html/api/com.r3corda.demos.protocols/-update-business-day-protocol/-broadcast/call.html +++ b/docs/build/html/api/com.r3corda.demos.protocols/-update-business-day-protocol/-broadcast/call.html @@ -8,7 +8,7 @@

    call

    -fun call(): Boolean
    +fun call(): Unit
    Overrides ProtocolLogic.call

    This is where you fill out your business logic.


    diff --git a/docs/build/html/api/com.r3corda.demos.protocols/-update-business-day-protocol/-broadcast/index.html b/docs/build/html/api/com.r3corda.demos.protocols/-update-business-day-protocol/-broadcast/index.html index 69e51151ba..daecc63e70 100644 --- a/docs/build/html/api/com.r3corda.demos.protocols/-update-business-day-protocol/-broadcast/index.html +++ b/docs/build/html/api/com.r3corda.demos.protocols/-update-business-day-protocol/-broadcast/index.html @@ -7,7 +7,7 @@ com.r3corda.demos.protocols / UpdateBusinessDayProtocol / Broadcast

    Broadcast

    -class Broadcast : ProtocolLogic<Boolean>
    +class Broadcast : ProtocolLogic<Unit>


    Types

    @@ -15,12 +15,6 @@ -LOCAL - -object LOCAL : Step - - - NOTIFYING object NOTIFYING : Step @@ -80,7 +74,9 @@ progress.

    serviceHub -val serviceHub: ServiceHub

    Provides access to big, heavy classes that may be reconstructed from time to time, e.g. across restarts

    +val serviceHub: ServiceHub

    Provides access to big, heavy classes that may be reconstructed from time to time, e.g. across restarts. It is +only available once the protocol has started, which means it cannnot be accessed in the constructor. Either +access this lazily or from inside call.

    @@ -92,7 +88,7 @@ progress.

    call -fun call(): Boolean

    This is where you fill out your business logic.

    +fun call(): Unit

    This is where you fill out your business logic.

    @@ -111,13 +107,13 @@ progress.

    send -fun send(topic: String, destination: MessageRecipients, sessionID: Long, obj: Any): Unit +fun send(topic: String, destination: Party, sessionID: Long, payload: Any): Unit sendAndReceive -fun <T : Any> sendAndReceive(topic: String, destination: MessageRecipients, sessionIDForSend: Long, sessionIDForReceive: Long, obj: Any): UntrustworthyData<T> +fun <T : Any> sendAndReceive(topic: String, destination: Party, sessionIDForSend: Long, sessionIDForReceive: Long, payload: Any): UntrustworthyData<T> diff --git a/docs/build/html/api/com.r3corda.demos.protocols/-update-business-day-protocol/-update-business-day-message/-init-.html b/docs/build/html/api/com.r3corda.demos.protocols/-update-business-day-protocol/-update-business-day-message/-init-.html index 3574d1fd14..98068af277 100644 --- a/docs/build/html/api/com.r3corda.demos.protocols/-update-business-day-protocol/-update-business-day-message/-init-.html +++ b/docs/build/html/api/com.r3corda.demos.protocols/-update-business-day-protocol/-update-business-day-message/-init-.html @@ -7,7 +7,7 @@ com.r3corda.demos.protocols / UpdateBusinessDayProtocol / UpdateBusinessDayMessage / <init>

    <init>

    -UpdateBusinessDayMessage(date: LocalDate, sessionID: Long)
    +UpdateBusinessDayMessage(date: LocalDate)


    diff --git a/docs/build/html/api/com.r3corda.demos.protocols/-update-business-day-protocol/-update-business-day-message/index.html b/docs/build/html/api/com.r3corda.demos.protocols/-update-business-day-protocol/-update-business-day-message/index.html index e91da6a7cf..f02aafc24d 100644 --- a/docs/build/html/api/com.r3corda.demos.protocols/-update-business-day-protocol/-update-business-day-message/index.html +++ b/docs/build/html/api/com.r3corda.demos.protocols/-update-business-day-protocol/-update-business-day-message/index.html @@ -17,7 +17,7 @@ <init> -UpdateBusinessDayMessage(date: LocalDate, sessionID: Long) +UpdateBusinessDayMessage(date: LocalDate) @@ -30,12 +30,6 @@ val date: LocalDate - - -sessionID - -val sessionID: Long - diff --git a/docs/build/html/api/com.r3corda.demos.protocols/-update-business-day-protocol/index.html b/docs/build/html/api/com.r3corda.demos.protocols/-update-business-day-protocol/index.html index 55c3e68fe8..a040a9c03e 100644 --- a/docs/build/html/api/com.r3corda.demos.protocols/-update-business-day-protocol/index.html +++ b/docs/build/html/api/com.r3corda.demos.protocols/-update-business-day-protocol/index.html @@ -8,8 +8,7 @@

    UpdateBusinessDayProtocol

    object UpdateBusinessDayProtocol
    -

    This is a very temporary, demo-oriented way of initiating processing of temporal events and is not -intended as the way things will necessarily be done longer term

    +

    This is a less temporary, demo-oriented way of initiating processing of temporal events



    Types

    @@ -19,7 +18,7 @@ intended as the way things will necessarily be done longer term

    Broadcast -class Broadcast : ProtocolLogic<Boolean> +class Broadcast : ProtocolLogic<Unit> @@ -33,12 +32,6 @@ intended as the way things will necessarily be done longer term

    data class UpdateBusinessDayMessage - - -Updater - -class Updater : ProtocolLogic<Boolean> -

    Properties

    diff --git a/docs/build/html/api/com.r3corda.demos.protocols/index.html b/docs/build/html/api/com.r3corda.demos.protocols/index.html index 5bf4d880a2..1efe6028b2 100644 --- a/docs/build/html/api/com.r3corda.demos.protocols/index.html +++ b/docs/build/html/api/com.r3corda.demos.protocols/index.html @@ -28,8 +28,7 @@ API call from a single party without bi-directional access to the database of of UpdateBusinessDayProtocol -object UpdateBusinessDayProtocol

    This is a very temporary, demo-oriented way of initiating processing of temporal events and is not -intended as the way things will necessarily be done longer term

    +object UpdateBusinessDayProtocol

    This is a less temporary, demo-oriented way of initiating processing of temporal events

    diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params-spec/api-address-arg.html b/docs/build/html/api/com.r3corda.demos/-cli-params-spec/api-address-arg.html new file mode 100644 index 0000000000..d94168971e --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params-spec/api-address-arg.html @@ -0,0 +1,15 @@ + + +CliParamsSpec.apiAddressArg - + + + +com.r3corda.demos / CliParamsSpec / apiAddressArg
    +
    +

    apiAddressArg

    + +val apiAddressArg: <ERROR CLASS>
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params-spec/base-directory-arg.html b/docs/build/html/api/com.r3corda.demos/-cli-params-spec/base-directory-arg.html new file mode 100644 index 0000000000..72615e9d97 --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params-spec/base-directory-arg.html @@ -0,0 +1,15 @@ + + +CliParamsSpec.baseDirectoryArg - + + + +com.r3corda.demos / CliParamsSpec / baseDirectoryArg
    +
    +

    baseDirectoryArg

    + +val baseDirectoryArg: <ERROR CLASS>
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params-spec/fake-trade-with-addr.html b/docs/build/html/api/com.r3corda.demos/-cli-params-spec/fake-trade-with-addr.html new file mode 100644 index 0000000000..a3e0eedd5f --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params-spec/fake-trade-with-addr.html @@ -0,0 +1,15 @@ + + +CliParamsSpec.fakeTradeWithAddr - + + + +com.r3corda.demos / CliParamsSpec / fakeTradeWithAddr
    +
    +

    fakeTradeWithAddr

    + +val fakeTradeWithAddr: <ERROR CLASS>
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params-spec/fake-trade-with-identity-file.html b/docs/build/html/api/com.r3corda.demos/-cli-params-spec/fake-trade-with-identity-file.html new file mode 100644 index 0000000000..3db3f5703e --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params-spec/fake-trade-with-identity-file.html @@ -0,0 +1,15 @@ + + +CliParamsSpec.fakeTradeWithIdentityFile - + + + +com.r3corda.demos / CliParamsSpec / fakeTradeWithIdentityFile
    +
    +

    fakeTradeWithIdentityFile

    + +val fakeTradeWithIdentityFile: <ERROR CLASS>
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params-spec/index.html b/docs/build/html/api/com.r3corda.demos/-cli-params-spec/index.html new file mode 100644 index 0000000000..2f0d533c2f --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params-spec/index.html @@ -0,0 +1,79 @@ + + +CliParamsSpec - + + + +com.r3corda.demos / CliParamsSpec
    +
    +

    CliParamsSpec

    +object CliParamsSpec
    +
    +
    +

    Properties

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +apiAddressArg +val apiAddressArg: <ERROR CLASS>
    +baseDirectoryArg +val baseDirectoryArg: <ERROR CLASS>
    +fakeTradeWithAddr +val fakeTradeWithAddr: <ERROR CLASS>
    +fakeTradeWithIdentityFile +val fakeTradeWithIdentityFile: <ERROR CLASS>
    +networkAddressArg +val networkAddressArg: <ERROR CLASS>
    +networkMapIdentityFile +val networkMapIdentityFile: <ERROR CLASS>
    +networkMapNetAddr +val networkMapNetAddr: <ERROR CLASS>
    +nonOptions +val nonOptions: <ERROR CLASS>
    +parser +val parser: <ERROR CLASS>
    +roleArg +val roleArg: <ERROR CLASS>
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params-spec/network-address-arg.html b/docs/build/html/api/com.r3corda.demos/-cli-params-spec/network-address-arg.html new file mode 100644 index 0000000000..b9aea4ed85 --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params-spec/network-address-arg.html @@ -0,0 +1,15 @@ + + +CliParamsSpec.networkAddressArg - + + + +com.r3corda.demos / CliParamsSpec / networkAddressArg
    +
    +

    networkAddressArg

    + +val networkAddressArg: <ERROR CLASS>
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params-spec/network-map-identity-file.html b/docs/build/html/api/com.r3corda.demos/-cli-params-spec/network-map-identity-file.html new file mode 100644 index 0000000000..1d0b30e893 --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params-spec/network-map-identity-file.html @@ -0,0 +1,15 @@ + + +CliParamsSpec.networkMapIdentityFile - + + + +com.r3corda.demos / CliParamsSpec / networkMapIdentityFile
    +
    +

    networkMapIdentityFile

    + +val networkMapIdentityFile: <ERROR CLASS>
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params-spec/network-map-net-addr.html b/docs/build/html/api/com.r3corda.demos/-cli-params-spec/network-map-net-addr.html new file mode 100644 index 0000000000..ce42e5428b --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params-spec/network-map-net-addr.html @@ -0,0 +1,15 @@ + + +CliParamsSpec.networkMapNetAddr - + + + +com.r3corda.demos / CliParamsSpec / networkMapNetAddr
    +
    +

    networkMapNetAddr

    + +val networkMapNetAddr: <ERROR CLASS>
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params-spec/non-options.html b/docs/build/html/api/com.r3corda.demos/-cli-params-spec/non-options.html new file mode 100644 index 0000000000..2c38ab17e2 --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params-spec/non-options.html @@ -0,0 +1,15 @@ + + +CliParamsSpec.nonOptions - + + + +com.r3corda.demos / CliParamsSpec / nonOptions
    +
    +

    nonOptions

    + +val nonOptions: <ERROR CLASS>
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params-spec/parser.html b/docs/build/html/api/com.r3corda.demos/-cli-params-spec/parser.html new file mode 100644 index 0000000000..c73d11aff3 --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params-spec/parser.html @@ -0,0 +1,15 @@ + + +CliParamsSpec.parser - + + + +com.r3corda.demos / CliParamsSpec / parser
    +
    +

    parser

    + +val parser: <ERROR CLASS>
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params-spec/role-arg.html b/docs/build/html/api/com.r3corda.demos/-cli-params-spec/role-arg.html new file mode 100644 index 0000000000..488228857c --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params-spec/role-arg.html @@ -0,0 +1,15 @@ + + +CliParamsSpec.roleArg - + + + +com.r3corda.demos / CliParamsSpec / roleArg
    +
    +

    roleArg

    + +val roleArg: <ERROR CLASS>
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params/-date-change/-init-.html b/docs/build/html/api/com.r3corda.demos/-cli-params/-date-change/-init-.html new file mode 100644 index 0000000000..19d800d152 --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params/-date-change/-init-.html @@ -0,0 +1,15 @@ + + +CliParams.DateChange.<init> - + + + +com.r3corda.demos / CliParams / DateChange / <init>
    +
    +

    <init>

    +DateChange(apiAddress: <ERROR CLASS>, dateString: String)
    +

    Corresponds to role Date

    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params/-date-change/api-address.html b/docs/build/html/api/com.r3corda.demos/-cli-params/-date-change/api-address.html new file mode 100644 index 0000000000..d8c5c51dd4 --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params/-date-change/api-address.html @@ -0,0 +1,15 @@ + + +CliParams.DateChange.apiAddress - + + + +com.r3corda.demos / CliParams / DateChange / apiAddress
    +
    +

    apiAddress

    + +val apiAddress: <ERROR CLASS>
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params/-date-change/date-string.html b/docs/build/html/api/com.r3corda.demos/-cli-params/-date-change/date-string.html new file mode 100644 index 0000000000..5c1834ddb8 --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params/-date-change/date-string.html @@ -0,0 +1,15 @@ + + +CliParams.DateChange.dateString - + + + +com.r3corda.demos / CliParams / DateChange / dateString
    +
    +

    dateString

    + +val dateString: String
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params/-date-change/index.html b/docs/build/html/api/com.r3corda.demos/-cli-params/-date-change/index.html new file mode 100644 index 0000000000..38ff2d7315 --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params/-date-change/index.html @@ -0,0 +1,44 @@ + + +CliParams.DateChange - + + + +com.r3corda.demos / CliParams / DateChange
    +
    +

    DateChange

    +class DateChange : CliParams
    +

    Corresponds to role Date

    +
    +
    +

    Constructors

    + + + + + + + +
    +<init> +DateChange(apiAddress: <ERROR CLASS>, dateString: String)

    Corresponds to role Date

    +
    +

    Properties

    + + + + + + + + + + + +
    +apiAddress +val apiAddress: <ERROR CLASS>
    +dateString +val dateString: String
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/-init-.html b/docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/-init-.html new file mode 100644 index 0000000000..198ea5dfb3 --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/-init-.html @@ -0,0 +1,15 @@ + + +CliParams.RunNode.<init> - + + + +com.r3corda.demos / CliParams / RunNode / <init>
    +
    +

    <init>

    +RunNode(node: IRSDemoNode, dir: Path, networkAddress: <ERROR CLASS>, apiAddress: <ERROR CLASS>, mapAddress: String, identityFile: Path, tradeWithAddrs: List<String>, tradeWithIdentities: List<Path>, uploadRates: Boolean, defaultLegalName: String, autoSetup: Boolean)
    +

    Corresponds to roles NodeA and NodeB

    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/api-address.html b/docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/api-address.html new file mode 100644 index 0000000000..207d1be562 --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/api-address.html @@ -0,0 +1,15 @@ + + +CliParams.RunNode.apiAddress - + + + +com.r3corda.demos / CliParams / RunNode / apiAddress
    +
    +

    apiAddress

    + +val apiAddress: <ERROR CLASS>
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/auto-setup.html b/docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/auto-setup.html new file mode 100644 index 0000000000..dab910fb3b --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/auto-setup.html @@ -0,0 +1,15 @@ + + +CliParams.RunNode.autoSetup - + + + +com.r3corda.demos / CliParams / RunNode / autoSetup
    +
    +

    autoSetup

    + +val autoSetup: Boolean
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/default-legal-name.html b/docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/default-legal-name.html new file mode 100644 index 0000000000..ef500bd37d --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/default-legal-name.html @@ -0,0 +1,15 @@ + + +CliParams.RunNode.defaultLegalName - + + + +com.r3corda.demos / CliParams / RunNode / defaultLegalName
    +
    +

    defaultLegalName

    + +val defaultLegalName: String
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/dir.html b/docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/dir.html new file mode 100644 index 0000000000..a0a5a6bdd5 --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/dir.html @@ -0,0 +1,15 @@ + + +CliParams.RunNode.dir - + + + +com.r3corda.demos / CliParams / RunNode / dir
    +
    +

    dir

    + +val dir: Path
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/identity-file.html b/docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/identity-file.html new file mode 100644 index 0000000000..68a403a966 --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/identity-file.html @@ -0,0 +1,15 @@ + + +CliParams.RunNode.identityFile - + + + +com.r3corda.demos / CliParams / RunNode / identityFile
    +
    +

    identityFile

    + +val identityFile: Path
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/index.html b/docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/index.html new file mode 100644 index 0000000000..566e96ad02 --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/index.html @@ -0,0 +1,98 @@ + + +CliParams.RunNode - + + + +com.r3corda.demos / CliParams / RunNode
    +
    +

    RunNode

    +class RunNode : CliParams
    +

    Corresponds to roles NodeA and NodeB

    +
    +
    +

    Constructors

    + + + + + + + +
    +<init> +RunNode(node: IRSDemoNode, dir: Path, networkAddress: <ERROR CLASS>, apiAddress: <ERROR CLASS>, mapAddress: String, identityFile: Path, tradeWithAddrs: List<String>, tradeWithIdentities: List<Path>, uploadRates: Boolean, defaultLegalName: String, autoSetup: Boolean)

    Corresponds to roles NodeA and NodeB

    +
    +

    Properties

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +apiAddress +val apiAddress: <ERROR CLASS>
    +autoSetup +val autoSetup: Boolean
    +defaultLegalName +val defaultLegalName: String
    +dir +val dir: Path
    +identityFile +val identityFile: Path
    +mapAddress +val mapAddress: String
    +networkAddress +val networkAddress: <ERROR CLASS>
    +node +val node: IRSDemoNode
    +tradeWithAddrs +val tradeWithAddrs: List<String>
    +tradeWithIdentities +val tradeWithIdentities: List<Path>
    +uploadRates +val uploadRates: Boolean
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/map-address.html b/docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/map-address.html new file mode 100644 index 0000000000..355322d9d5 --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/map-address.html @@ -0,0 +1,15 @@ + + +CliParams.RunNode.mapAddress - + + + +com.r3corda.demos / CliParams / RunNode / mapAddress
    +
    +

    mapAddress

    + +val mapAddress: String
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/network-address.html b/docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/network-address.html new file mode 100644 index 0000000000..dae97d4f86 --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/network-address.html @@ -0,0 +1,15 @@ + + +CliParams.RunNode.networkAddress - + + + +com.r3corda.demos / CliParams / RunNode / networkAddress
    +
    +

    networkAddress

    + +val networkAddress: <ERROR CLASS>
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/node.html b/docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/node.html new file mode 100644 index 0000000000..c5e15b8642 --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/node.html @@ -0,0 +1,15 @@ + + +CliParams.RunNode.node - + + + +com.r3corda.demos / CliParams / RunNode / node
    +
    +

    node

    + +val node: IRSDemoNode
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/trade-with-addrs.html b/docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/trade-with-addrs.html new file mode 100644 index 0000000000..452d1005d5 --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/trade-with-addrs.html @@ -0,0 +1,15 @@ + + +CliParams.RunNode.tradeWithAddrs - + + + +com.r3corda.demos / CliParams / RunNode / tradeWithAddrs
    +
    +

    tradeWithAddrs

    + +val tradeWithAddrs: List<String>
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/trade-with-identities.html b/docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/trade-with-identities.html new file mode 100644 index 0000000000..b9a531ffca --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/trade-with-identities.html @@ -0,0 +1,15 @@ + + +CliParams.RunNode.tradeWithIdentities - + + + +com.r3corda.demos / CliParams / RunNode / tradeWithIdentities
    +
    +

    tradeWithIdentities

    + +val tradeWithIdentities: List<Path>
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/upload-rates.html b/docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/upload-rates.html new file mode 100644 index 0000000000..6f178642e9 --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params/-run-node/upload-rates.html @@ -0,0 +1,15 @@ + + +CliParams.RunNode.uploadRates - + + + +com.r3corda.demos / CliParams / RunNode / uploadRates
    +
    +

    uploadRates

    + +val uploadRates: Boolean
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params/-setup-node/-init-.html b/docs/build/html/api/com.r3corda.demos/-cli-params/-setup-node/-init-.html new file mode 100644 index 0000000000..f678ac85fb --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params/-setup-node/-init-.html @@ -0,0 +1,15 @@ + + +CliParams.SetupNode.<init> - + + + +com.r3corda.demos / CliParams / SetupNode / <init>
    +
    +

    <init>

    +SetupNode(node: IRSDemoNode, dir: Path, defaultLegalName: String)
    +

    Corresponds to roles SetupNodeA and SetupNodeB

    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params/-setup-node/default-legal-name.html b/docs/build/html/api/com.r3corda.demos/-cli-params/-setup-node/default-legal-name.html new file mode 100644 index 0000000000..dbc059fe4f --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params/-setup-node/default-legal-name.html @@ -0,0 +1,15 @@ + + +CliParams.SetupNode.defaultLegalName - + + + +com.r3corda.demos / CliParams / SetupNode / defaultLegalName
    +
    +

    defaultLegalName

    + +val defaultLegalName: String
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params/-setup-node/dir.html b/docs/build/html/api/com.r3corda.demos/-cli-params/-setup-node/dir.html new file mode 100644 index 0000000000..0177c35d78 --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params/-setup-node/dir.html @@ -0,0 +1,15 @@ + + +CliParams.SetupNode.dir - + + + +com.r3corda.demos / CliParams / SetupNode / dir
    +
    +

    dir

    + +val dir: Path
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params/-setup-node/index.html b/docs/build/html/api/com.r3corda.demos/-cli-params/-setup-node/index.html new file mode 100644 index 0000000000..c512dc861d --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params/-setup-node/index.html @@ -0,0 +1,50 @@ + + +CliParams.SetupNode - + + + +com.r3corda.demos / CliParams / SetupNode
    +
    +

    SetupNode

    +class SetupNode : CliParams
    +

    Corresponds to roles SetupNodeA and SetupNodeB

    +
    +
    +

    Constructors

    + + + + + + + +
    +<init> +SetupNode(node: IRSDemoNode, dir: Path, defaultLegalName: String)

    Corresponds to roles SetupNodeA and SetupNodeB

    +
    +

    Properties

    + + + + + + + + + + + + + + + +
    +defaultLegalName +val defaultLegalName: String
    +dir +val dir: Path
    +node +val node: IRSDemoNode
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params/-setup-node/node.html b/docs/build/html/api/com.r3corda.demos/-cli-params/-setup-node/node.html new file mode 100644 index 0000000000..06ce7765ce --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params/-setup-node/node.html @@ -0,0 +1,15 @@ + + +CliParams.SetupNode.node - + + + +com.r3corda.demos / CliParams / SetupNode / node
    +
    +

    node

    + +val node: IRSDemoNode
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params/-trade/-init-.html b/docs/build/html/api/com.r3corda.demos/-cli-params/-trade/-init-.html new file mode 100644 index 0000000000..796082aa17 --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params/-trade/-init-.html @@ -0,0 +1,15 @@ + + +CliParams.Trade.<init> - + + + +com.r3corda.demos / CliParams / Trade / <init>
    +
    +

    <init>

    +Trade(apiAddress: <ERROR CLASS>, tradeId: String)
    +

    Corresponds to role Trade

    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params/-trade/api-address.html b/docs/build/html/api/com.r3corda.demos/-cli-params/-trade/api-address.html new file mode 100644 index 0000000000..bebf995bd1 --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params/-trade/api-address.html @@ -0,0 +1,15 @@ + + +CliParams.Trade.apiAddress - + + + +com.r3corda.demos / CliParams / Trade / apiAddress
    +
    +

    apiAddress

    + +val apiAddress: <ERROR CLASS>
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params/-trade/index.html b/docs/build/html/api/com.r3corda.demos/-cli-params/-trade/index.html new file mode 100644 index 0000000000..2f9cb06bf4 --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params/-trade/index.html @@ -0,0 +1,44 @@ + + +CliParams.Trade - + + + +com.r3corda.demos / CliParams / Trade
    +
    +

    Trade

    +class Trade : CliParams
    +

    Corresponds to role Trade

    +
    +
    +

    Constructors

    + + + + + + + +
    +<init> +Trade(apiAddress: <ERROR CLASS>, tradeId: String)

    Corresponds to role Trade

    +
    +

    Properties

    + + + + + + + + + + + +
    +apiAddress +val apiAddress: <ERROR CLASS>
    +tradeId +val tradeId: String
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params/-trade/trade-id.html b/docs/build/html/api/com.r3corda.demos/-cli-params/-trade/trade-id.html new file mode 100644 index 0000000000..4c7da1e4b4 --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params/-trade/trade-id.html @@ -0,0 +1,15 @@ + + +CliParams.Trade.tradeId - + + + +com.r3corda.demos / CliParams / Trade / tradeId
    +
    +

    tradeId

    + +val tradeId: String
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params/default-base-directory.html b/docs/build/html/api/com.r3corda.demos/-cli-params/default-base-directory.html new file mode 100644 index 0000000000..020af40ee5 --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params/default-base-directory.html @@ -0,0 +1,15 @@ + + +CliParams.defaultBaseDirectory - + + + +com.r3corda.demos / CliParams / defaultBaseDirectory
    +
    +

    defaultBaseDirectory

    + +val defaultBaseDirectory: String
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params/index.html b/docs/build/html/api/com.r3corda.demos/-cli-params/index.html new file mode 100644 index 0000000000..09566ecbea --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params/index.html @@ -0,0 +1,109 @@ + + +CliParams - + + + +com.r3corda.demos / CliParams
    +
    +

    CliParams

    +sealed class CliParams
    +

    Parsed command line parameters.

    +
    +
    +

    Types

    + + + + + + + + + + + + + + + + + + + +
    +DateChange +class DateChange : CliParams

    Corresponds to role Date

    +
    +RunNode +class RunNode : CliParams

    Corresponds to roles NodeA and NodeB

    +
    +SetupNode +class SetupNode : CliParams

    Corresponds to roles SetupNodeA and SetupNodeB

    +
    +Trade +class Trade : CliParams

    Corresponds to role Trade

    +
    +

    Companion Object Properties

    + + + + + + + +
    +defaultBaseDirectory +val defaultBaseDirectory: String
    +

    Companion Object Functions

    + + + + + + + + + + + +
    +legalName +fun legalName(node: IRSDemoNode): String
    +parse +fun parse(options: <ERROR CLASS>): CliParams
    +

    Inheritors

    + + + + + + + + + + + + + + + + + + + +
    +DateChange +class DateChange : CliParams

    Corresponds to role Date

    +
    +RunNode +class RunNode : CliParams

    Corresponds to roles NodeA and NodeB

    +
    +SetupNode +class SetupNode : CliParams

    Corresponds to roles SetupNodeA and SetupNodeB

    +
    +Trade +class Trade : CliParams

    Corresponds to role Trade

    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params/legal-name.html b/docs/build/html/api/com.r3corda.demos/-cli-params/legal-name.html new file mode 100644 index 0000000000..96ac0f5273 --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params/legal-name.html @@ -0,0 +1,15 @@ + + +CliParams.legalName - + + + +com.r3corda.demos / CliParams / legalName
    +
    +

    legalName

    + +fun legalName(node: IRSDemoNode): String
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-cli-params/parse.html b/docs/build/html/api/com.r3corda.demos/-cli-params/parse.html new file mode 100644 index 0000000000..dfc7ecdb75 --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-cli-params/parse.html @@ -0,0 +1,15 @@ + + +CliParams.parse - + + + +com.r3corda.demos / CliParams / parse
    +
    +

    parse

    + +fun parse(options: <ERROR CLASS>): CliParams
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-d-e-f-a-u-l-t_-b-a-s-e_-d-i-r-e-c-t-o-r-y.html b/docs/build/html/api/com.r3corda.demos/-d-e-f-a-u-l-t_-b-a-s-e_-d-i-r-e-c-t-o-r-y.html new file mode 100644 index 0000000000..b4c2d4a5e0 --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-d-e-f-a-u-l-t_-b-a-s-e_-d-i-r-e-c-t-o-r-y.html @@ -0,0 +1,15 @@ + + +DEFAULT_BASE_DIRECTORY - + + + +com.r3corda.demos / DEFAULT_BASE_DIRECTORY
    +
    +

    DEFAULT_BASE_DIRECTORY

    + +val DEFAULT_BASE_DIRECTORY: String
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-i-r-s-demo-node/-node-a.html b/docs/build/html/api/com.r3corda.demos/-i-r-s-demo-node/-node-a.html new file mode 100644 index 0000000000..76fb767ede --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-i-r-s-demo-node/-node-a.html @@ -0,0 +1,25 @@ + + +IRSDemoNode.NodeA - + + + +com.r3corda.demos / IRSDemoNode / NodeA
    +
    +

    NodeA

    +NodeA
    +
    +
    +

    Inherited Properties

    + + + + + + + +
    +other +val other: IRSDemoNode
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-i-r-s-demo-node/-node-b.html b/docs/build/html/api/com.r3corda.demos/-i-r-s-demo-node/-node-b.html new file mode 100644 index 0000000000..f0e3845da4 --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-i-r-s-demo-node/-node-b.html @@ -0,0 +1,25 @@ + + +IRSDemoNode.NodeB - + + + +com.r3corda.demos / IRSDemoNode / NodeB
    +
    +

    NodeB

    +NodeB
    +
    +
    +

    Inherited Properties

    + + + + + + + +
    +other +val other: IRSDemoNode
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-i-r-s-demo-node/index.html b/docs/build/html/api/com.r3corda.demos/-i-r-s-demo-node/index.html new file mode 100644 index 0000000000..af7812a100 --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-i-r-s-demo-node/index.html @@ -0,0 +1,42 @@ + + +IRSDemoNode - + + + +com.r3corda.demos / IRSDemoNode
    +
    +

    IRSDemoNode

    +enum class IRSDemoNode
    +
    +
    +

    Enum Values

    + + + + + + + + + + + +
    +NodeA +
    +NodeB +
    +

    Properties

    + + + + + + + +
    +other +val other: IRSDemoNode
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-i-r-s-demo-node/other.html b/docs/build/html/api/com.r3corda.demos/-i-r-s-demo-node/other.html new file mode 100644 index 0000000000..c918904272 --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/-i-r-s-demo-node/other.html @@ -0,0 +1,15 @@ + + +IRSDemoNode.other - + + + +com.r3corda.demos / IRSDemoNode / other
    +
    +

    other

    + +val other: IRSDemoNode
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos/-i-r-s-demo-role/index.html b/docs/build/html/api/com.r3corda.demos/-i-r-s-demo-role/index.html index a0f781db98..ae2ec21cf5 100644 --- a/docs/build/html/api/com.r3corda.demos/-i-r-s-demo-role/index.html +++ b/docs/build/html/api/com.r3corda.demos/-i-r-s-demo-role/index.html @@ -8,6 +8,13 @@

    IRSDemoRole

    enum class IRSDemoRole
    +

    Roles. There are 4 modes this demo can be run:

    +
    • SetupNodeA/SetupNodeB: Creates and sets up the necessary directories for nodes

      +
    • NodeA/NodeB: Starts the nodes themselves

      +
    • Trade: Uploads an example trade

      +
    • DateChange: Changes the demos date

      +

    +


    Enum Values

    diff --git a/docs/build/html/api/com.r3corda.demos/index.html b/docs/build/html/api/com.r3corda.demos/index.html index 14e5f3bc28..f6911c3ed6 100644 --- a/docs/build/html/api/com.r3corda.demos/index.html +++ b/docs/build/html/api/com.r3corda.demos/index.html @@ -12,6 +12,19 @@ +CliParams + +sealed class CliParams

    Parsed command line parameters.

    + + + + +CliParamsSpec + +object CliParamsSpec + + + DemoClock class DemoClock : MutableClock, SerializeAsToken

    A Clock that can have the date advanced for use in demos

    @@ -19,9 +32,16 @@ +IRSDemoNode + +enum class IRSDemoNode + + + IRSDemoRole -enum class IRSDemoRole +enum class IRSDemoRole

    Roles. There are 4 modes this demo can be run:

    + @@ -29,18 +49,6 @@ enum class Role - - -TraderDemoProtocolBuyer - -class TraderDemoProtocolBuyer : ProtocolLogic<Unit> - - - -TraderDemoProtocolSeller - -class TraderDemoProtocolSeller : ProtocolLogic<Unit> -

    Properties

    @@ -48,15 +56,15 @@ -DEMO_TOPIC +DEFAULT_BASE_DIRECTORY -val DEMO_TOPIC: String +val DEFAULT_BASE_DIRECTORY: String -DIRNAME +DEMO_TOPIC -val DIRNAME: String +val DEMO_TOPIC: String @@ -74,27 +82,15 @@ service.

    -parseOptions +runIRSDemo -fun parseOptions(args: Array<String>, parser: <ERROR CLASS>): <ERROR CLASS> +fun runIRSDemo(args: Array<String>): Int -runBuyer +runTraderDemo -fun runBuyer(node: Node): Unit - - - -runSeller - -fun runSeller(myNetAddr: <ERROR CLASS>, node: Node, theirNetAddr: <ERROR CLASS>): Unit - - - -setupDirectory - -fun setupDirectory(mode: Role): Path +fun runTraderDemo(args: Array<String>): Int diff --git a/docs/build/html/api/com.r3corda.demos/run-i-r-s-demo.html b/docs/build/html/api/com.r3corda.demos/run-i-r-s-demo.html new file mode 100644 index 0000000000..c0009b260c --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/run-i-r-s-demo.html @@ -0,0 +1,15 @@ + + +runIRSDemo - + + + +com.r3corda.demos / runIRSDemo
    +
    +

    runIRSDemo

    + +fun runIRSDemo(args: Array<String>): Int
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.demos/run-trader-demo.html b/docs/build/html/api/com.r3corda.demos/run-trader-demo.html new file mode 100644 index 0000000000..25c694b6e5 --- /dev/null +++ b/docs/build/html/api/com.r3corda.demos/run-trader-demo.html @@ -0,0 +1,15 @@ + + +runTraderDemo - + + + +com.r3corda.demos / runTraderDemo
    +
    +

    runTraderDemo

    + +fun runTraderDemo(args: Array<String>): Int
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.node.api/-a-p-i-server/fetch-states.html b/docs/build/html/api/com.r3corda.node.api/-a-p-i-server/fetch-states.html index 666254854a..99fa888306 100644 --- a/docs/build/html/api/com.r3corda.node.api/-a-p-i-server/fetch-states.html +++ b/docs/build/html/api/com.r3corda.node.api/-a-p-i-server/fetch-states.html @@ -8,7 +8,7 @@

    fetchStates

    -abstract fun fetchStates(states: List<StateRef>): Map<StateRef, ContractState?>
    +abstract fun fetchStates(states: List<StateRef>): Map<StateRef, TransactionState<ContractState>?>


    diff --git a/docs/build/html/api/com.r3corda.node.api/-a-p-i-server/fetch-transactions.html b/docs/build/html/api/com.r3corda.node.api/-a-p-i-server/fetch-transactions.html index cd68eed4fa..f4b7999730 100644 --- a/docs/build/html/api/com.r3corda.node.api/-a-p-i-server/fetch-transactions.html +++ b/docs/build/html/api/com.r3corda.node.api/-a-p-i-server/fetch-transactions.html @@ -13,8 +13,8 @@

    Parameters

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

    Return
    +null values indicate missing transactions from the requested list.



    diff --git a/docs/build/html/api/com.r3corda.node.api/-a-p-i-server/index.html b/docs/build/html/api/com.r3corda.node.api/-a-p-i-server/index.html index 67fa5431c0..0ee69e7c6b 100644 --- a/docs/build/html/api/com.r3corda.node.api/-a-p-i-server/index.html +++ b/docs/build/html/api/com.r3corda.node.api/-a-p-i-server/index.html @@ -46,7 +46,7 @@ successful, otherwise exception is thrown.

    fetchStates -abstract fun fetchStates(states: List<StateRef>): Map<StateRef, ContractState?> +abstract fun fetchStates(states: List<StateRef>): Map<StateRef, TransactionState<ContractState>?> @@ -92,6 +92,13 @@ to avoid calling fetchLedgerTransactions() many times.

    abstract fun serverTime(): LocalDateTime

    Report current UTC time as understood by the platform.

    + + +status + +abstract fun status(): <ERROR CLASS>

    Report whether this node is started up or not

    + +

    Inheritors

    diff --git a/docs/build/html/api/com.r3corda.node.api/-a-p-i-server/query-states.html b/docs/build/html/api/com.r3corda.node.api/-a-p-i-server/query-states.html index 9f97e27528..c0041e792f 100644 --- a/docs/build/html/api/com.r3corda.node.api/-a-p-i-server/query-states.html +++ b/docs/build/html/api/com.r3corda.node.api/-a-p-i-server/query-states.html @@ -15,8 +15,8 @@ to avoid calling fetchLedgerTransactions() many times.

    Parameters

    query - Some "where clause" like expression.
    -Return
    -Zero or more matching States.
    +

    Return
    +Zero or more matching States.



    diff --git a/docs/build/html/api/com.r3corda.node.api/-a-p-i-server/status.html b/docs/build/html/api/com.r3corda.node.api/-a-p-i-server/status.html new file mode 100644 index 0000000000..67b36d865d --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.api/-a-p-i-server/status.html @@ -0,0 +1,16 @@ + + +APIServer.status - + + + +com.r3corda.node.api / APIServer / status
    +
    +

    status

    + +abstract fun status(): <ERROR CLASS>
    +

    Report whether this node is started up or not

    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.node.internal.testing/-i-r-s-simulation/-init-.html b/docs/build/html/api/com.r3corda.node.internal.testing/-i-r-s-simulation/-init-.html index bd07e8a5f1..f7b77c79d6 100644 --- a/docs/build/html/api/com.r3corda.node.internal.testing/-i-r-s-simulation/-init-.html +++ b/docs/build/html/api/com.r3corda.node.internal.testing/-i-r-s-simulation/-init-.html @@ -7,7 +7,7 @@ com.r3corda.node.internal.testing / IRSSimulation / <init>

    <init>

    -IRSSimulation(runAsync: Boolean, latencyInjector: LatencyCalculator?)
    +IRSSimulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, latencyInjector: LatencyCalculator?)

    A simulation in which banks execute interest rate swaps with each other, including the fixing events.



    diff --git a/docs/build/html/api/com.r3corda.node.internal.testing/-i-r-s-simulation/index.html b/docs/build/html/api/com.r3corda.node.internal.testing/-i-r-s-simulation/index.html index 37ec2eb368..fc5808a6f4 100644 --- a/docs/build/html/api/com.r3corda.node.internal.testing/-i-r-s-simulation/index.html +++ b/docs/build/html/api/com.r3corda.node.internal.testing/-i-r-s-simulation/index.html @@ -18,7 +18,7 @@ <init> -IRSSimulation(runAsync: Boolean, latencyInjector: LatencyCalculator?)

    A simulation in which banks execute interest rate swaps with each other, including the fixing events.

    +IRSSimulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, latencyInjector: LatencyCalculator?)

    A simulation in which banks execute interest rate swaps with each other, including the fixing events.

    @@ -63,9 +63,15 @@ -currentDay +clocks -var currentDay: LocalDate

    The current simulated date. By default this never changes. If you want it to change, you should do so from +val clocks: <ERROR CLASS> + + + +currentDateAndTime + +var currentDateAndTime: LocalDateTime

    The current simulated date. By default this never changes. If you want it to change, you should do so from within your overridden iterate call. Changes in the current day surface in the dateChanges observable.

    @@ -73,7 +79,7 @@ within your overridden iterate call. C dateChanges -val dateChanges: <ERROR CLASS><LocalDate> +val dateChanges: <ERROR CLASS><LocalDateTime> @@ -115,6 +121,12 @@ in the UI somewhere.

    +networkSendManuallyPumped + +val networkSendManuallyPumped: Boolean + + + notary val notary: SimulatedNode @@ -170,15 +182,15 @@ network bringup has been simulated.

    -linkConsensus +showConsensusFor -fun linkConsensus(nodes: Collection<SimulatedNode>, protocol: ProtocolLogic<*>): Unit +fun showConsensusFor(nodes: List<SimulatedNode>): Unit -linkProtocolProgress +showProgressFor -fun linkProtocolProgress(node: SimulatedNode, protocol: ProtocolLogic<*>): Unit +fun showProgressFor(nodes: List<SimulatedNode>): Unit @@ -190,7 +202,7 @@ network bringup has been simulated.

    startTradingCircle -fun startTradingCircle(tradeBetween: (Int, Int) -> <ERROR CLASS><out <ERROR CLASS>>): Unit

    Given a function that returns a future, iterates that function with arguments like (0, 1), (1, 2), (2, 3) etc +fun startTradingCircle(tradeBetween: (Int, Int) -> <ERROR CLASS><out <ERROR CLASS>>): Unit

    Given a function that returns a future, iterates that function with arguments like (0, 1), (1, 2), (2, 3) etc each time the returned future completes.

    diff --git a/docs/build/html/api/com.r3corda.node.internal.testing/-i-r-s-simulation/iterate.html b/docs/build/html/api/com.r3corda.node.internal.testing/-i-r-s-simulation/iterate.html index 4475f334a6..2d2be5183f 100644 --- a/docs/build/html/api/com.r3corda.node.internal.testing/-i-r-s-simulation/iterate.html +++ b/docs/build/html/api/com.r3corda.node.internal.testing/-i-r-s-simulation/iterate.html @@ -17,8 +17,8 @@ interesting happening, or control the precise speed at which things operate (bey is a useful way to do things.



    -Return
    -the message that was processed, or null if no node accepted a message in this round.
    +

    Return
    +the message that was processed, or null if no node accepted a message in this round.



    diff --git a/docs/build/html/api/com.r3corda.node.internal.testing/-mock-network/-init-.html b/docs/build/html/api/com.r3corda.node.internal.testing/-mock-network/-init-.html index 7e0cab9adb..b31eff5de1 100644 --- a/docs/build/html/api/com.r3corda.node.internal.testing/-mock-network/-init-.html +++ b/docs/build/html/api/com.r3corda.node.internal.testing/-mock-network/-init-.html @@ -7,7 +7,7 @@ com.r3corda.node.internal.testing / MockNetwork / <init>

    <init>

    -MockNetwork(threadPerNode: Boolean = false, defaultFactory: Factory = MockNetwork.DefaultFactory)
    +MockNetwork(networkSendManuallyPumped: Boolean = false, threadPerNode: Boolean = false, defaultFactory: Factory = MockNetwork.DefaultFactory)

    A mock node brings up a suite of in-memory services in a fast manner suitable for unit testing. Components that do IO are either swapped out for mocks, or pointed to a Jimfs in memory filesystem.

    Mock network nodes require manual pumping by default: they will not run asynchronous. This means that diff --git a/docs/build/html/api/com.r3corda.node.internal.testing/-mock-network/-mock-node/index.html b/docs/build/html/api/com.r3corda.node.internal.testing/-mock-network/-mock-node/index.html index 5bd4b8f5f4..015fd14f10 100644 --- a/docs/build/html/api/com.r3corda.node.internal.testing/-mock-network/-mock-node/index.html +++ b/docs/build/html/api/com.r3corda.node.internal.testing/-mock-network/-mock-node/index.html @@ -176,6 +176,12 @@ +scheduler + +lateinit var scheduler: SchedulerService + + + services val services: ServiceHubInternal @@ -203,7 +209,7 @@ storage -lateinit var storage: StorageService +lateinit var storage: TxWritableStorageService @@ -272,9 +278,15 @@ +createNodeDir + +fun createNodeDir(): Unit + + + initialiseStorageService -open fun initialiseStorageService(dir: Path): <ERROR CLASS><StorageService, CheckpointStorage> +open fun initialiseStorageService(dir: Path): <ERROR CLASS><TxWritableStorageService, CheckpointStorage> @@ -302,6 +314,13 @@ +setup + +open fun setup(): AbstractNode

    Run any tasks that are needed to ensure the node is in a correct state before running start()

    + + + + stop open fun stop(): Unit diff --git a/docs/build/html/api/com.r3corda.node.internal.testing/-mock-network/index.html b/docs/build/html/api/com.r3corda.node.internal.testing/-mock-network/index.html index 1f3f355485..b67c37ef47 100644 --- a/docs/build/html/api/com.r3corda.node.internal.testing/-mock-network/index.html +++ b/docs/build/html/api/com.r3corda.node.internal.testing/-mock-network/index.html @@ -50,7 +50,7 @@ method.

    <init> -MockNetwork(threadPerNode: Boolean = false, defaultFactory: Factory = MockNetwork.DefaultFactory)

    A mock node brings up a suite of in-memory services in a fast manner suitable for unit testing. +MockNetwork(networkSendManuallyPumped: Boolean = false, threadPerNode: Boolean = false, defaultFactory: Factory = MockNetwork.DefaultFactory)

    A mock node brings up a suite of in-memory services in a fast manner suitable for unit testing. Components that do IO are either swapped out for mocks, or pointed to a Jimfs in memory filesystem.

    diff --git a/docs/build/html/api/com.r3corda.node.internal.testing/-simulation/-init-.html b/docs/build/html/api/com.r3corda.node.internal.testing/-simulation/-init-.html index 9fb34180e1..e450f6b867 100644 --- a/docs/build/html/api/com.r3corda.node.internal.testing/-simulation/-init-.html +++ b/docs/build/html/api/com.r3corda.node.internal.testing/-simulation/-init-.html @@ -7,7 +7,7 @@ com.r3corda.node.internal.testing / Simulation / <init>

    <init>

    -Simulation(runAsync: Boolean, latencyInjector: LatencyCalculator?)
    +Simulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, latencyInjector: LatencyCalculator?)

    Base class for network simulations that are based on the unit test / mock environment.

    Sets up some nodes that can run protocols between each other, and exposes their progress trackers. Provides banks in a few cities around the world.

    diff --git a/docs/build/html/api/com.r3corda.node.internal.testing/-simulation/clocks.html b/docs/build/html/api/com.r3corda.node.internal.testing/-simulation/clocks.html new file mode 100644 index 0000000000..ba7bc1a4fc --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.internal.testing/-simulation/clocks.html @@ -0,0 +1,15 @@ + + +Simulation.clocks - + + + +com.r3corda.node.internal.testing / Simulation / clocks
    +
    +

    clocks

    + +val clocks: <ERROR CLASS>
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.node.internal.testing/-simulation/current-date-and-time.html b/docs/build/html/api/com.r3corda.node.internal.testing/-simulation/current-date-and-time.html new file mode 100644 index 0000000000..f8c7cae3b4 --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.internal.testing/-simulation/current-date-and-time.html @@ -0,0 +1,17 @@ + + +Simulation.currentDateAndTime - + + + +com.r3corda.node.internal.testing / Simulation / currentDateAndTime
    +
    +

    currentDateAndTime

    + +var currentDateAndTime: LocalDateTime
    +

    The current simulated date. By default this never changes. If you want it to change, you should do so from +within your overridden iterate call. Changes in the current day surface in the dateChanges observable.

    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.node.internal.testing/-simulation/date-changes.html b/docs/build/html/api/com.r3corda.node.internal.testing/-simulation/date-changes.html index 183466f7ac..58391e1b23 100644 --- a/docs/build/html/api/com.r3corda.node.internal.testing/-simulation/date-changes.html +++ b/docs/build/html/api/com.r3corda.node.internal.testing/-simulation/date-changes.html @@ -8,7 +8,7 @@

    dateChanges

    -val dateChanges: <ERROR CLASS><LocalDate>
    +val dateChanges: <ERROR CLASS><LocalDateTime>


    diff --git a/docs/build/html/api/com.r3corda.node.internal.testing/-simulation/index.html b/docs/build/html/api/com.r3corda.node.internal.testing/-simulation/index.html index 013fab1853..52675fe3fc 100644 --- a/docs/build/html/api/com.r3corda.node.internal.testing/-simulation/index.html +++ b/docs/build/html/api/com.r3corda.node.internal.testing/-simulation/index.html @@ -63,7 +63,7 @@ in a few cities around the world.

    <init> -Simulation(runAsync: Boolean, latencyInjector: LatencyCalculator?)

    Base class for network simulations that are based on the unit test / mock environment.

    +Simulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, latencyInjector: LatencyCalculator?)

    Base class for network simulations that are based on the unit test / mock environment.

    @@ -97,9 +97,15 @@ in a few cities around the world.

    -currentDay +clocks -var currentDay: LocalDate

    The current simulated date. By default this never changes. If you want it to change, you should do so from +val clocks: <ERROR CLASS> + + + +currentDateAndTime + +var currentDateAndTime: LocalDateTime

    The current simulated date. By default this never changes. If you want it to change, you should do so from within your overridden iterate call. Changes in the current day surface in the dateChanges observable.

    @@ -107,7 +113,7 @@ within your overridden iterate call. Changes in the c dateChanges -val dateChanges: <ERROR CLASS><LocalDate> +val dateChanges: <ERROR CLASS><LocalDateTime> @@ -149,6 +155,12 @@ in the UI somewhere.

    +networkSendManuallyPumped + +val networkSendManuallyPumped: Boolean + + + notary val notary: SimulatedNode @@ -191,15 +203,15 @@ in the UI somewhere.

    -linkConsensus +showConsensusFor -fun linkConsensus(nodes: Collection<SimulatedNode>, protocol: ProtocolLogic<*>): Unit +fun showConsensusFor(nodes: List<SimulatedNode>): Unit -linkProtocolProgress +showProgressFor -fun linkProtocolProgress(node: SimulatedNode, protocol: ProtocolLogic<*>): Unit +fun showProgressFor(nodes: List<SimulatedNode>): Unit @@ -219,7 +231,7 @@ network bringup has been simulated.

    startTradingCircle -fun startTradingCircle(tradeBetween: (Int, Int) -> <ERROR CLASS><out <ERROR CLASS>>): Unit

    Given a function that returns a future, iterates that function with arguments like (0, 1), (1, 2), (2, 3) etc +fun startTradingCircle(tradeBetween: (Int, Int) -> <ERROR CLASS><out <ERROR CLASS>>): Unit

    Given a function that returns a future, iterates that function with arguments like (0, 1), (1, 2), (2, 3) etc each time the returned future completes.

    diff --git a/docs/build/html/api/com.r3corda.node.internal.testing/-simulation/iterate.html b/docs/build/html/api/com.r3corda.node.internal.testing/-simulation/iterate.html index 5be053eaee..6595b0b202 100644 --- a/docs/build/html/api/com.r3corda.node.internal.testing/-simulation/iterate.html +++ b/docs/build/html/api/com.r3corda.node.internal.testing/-simulation/iterate.html @@ -16,8 +16,8 @@ interesting happening, or control the precise speed at which things operate (bey is a useful way to do things.



    -Return
    -the message that was processed, or null if no node accepted a message in this round.
    +

    Return
    +the message that was processed, or null if no node accepted a message in this round.



    diff --git a/docs/build/html/api/com.r3corda.node.internal.testing/-simulation/network-send-manually-pumped.html b/docs/build/html/api/com.r3corda.node.internal.testing/-simulation/network-send-manually-pumped.html new file mode 100644 index 0000000000..167e7945c3 --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.internal.testing/-simulation/network-send-manually-pumped.html @@ -0,0 +1,15 @@ + + +Simulation.networkSendManuallyPumped - + + + +com.r3corda.node.internal.testing / Simulation / networkSendManuallyPumped
    +
    +

    networkSendManuallyPumped

    + +val networkSendManuallyPumped: Boolean
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.node.internal.testing/-simulation/show-consensus-for.html b/docs/build/html/api/com.r3corda.node.internal.testing/-simulation/show-consensus-for.html new file mode 100644 index 0000000000..eb090e7bf1 --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.internal.testing/-simulation/show-consensus-for.html @@ -0,0 +1,15 @@ + + +Simulation.showConsensusFor - + + + +com.r3corda.node.internal.testing / Simulation / showConsensusFor
    +
    +

    showConsensusFor

    + +protected fun showConsensusFor(nodes: List<SimulatedNode>): Unit
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.node.internal.testing/-simulation/show-progress-for.html b/docs/build/html/api/com.r3corda.node.internal.testing/-simulation/show-progress-for.html new file mode 100644 index 0000000000..6c8ab4506a --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.internal.testing/-simulation/show-progress-for.html @@ -0,0 +1,15 @@ + + +Simulation.showProgressFor - + + + +com.r3corda.node.internal.testing / Simulation / showProgressFor
    +
    +

    showProgressFor

    + +protected fun showProgressFor(nodes: List<SimulatedNode>): Unit
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.node.internal.testing/-simulation/start-trading-circle.html b/docs/build/html/api/com.r3corda.node.internal.testing/-simulation/start-trading-circle.html index ce81ff4cac..223b6e5e3f 100644 --- a/docs/build/html/api/com.r3corda.node.internal.testing/-simulation/start-trading-circle.html +++ b/docs/build/html/api/com.r3corda.node.internal.testing/-simulation/start-trading-circle.html @@ -7,8 +7,8 @@ com.r3corda.node.internal.testing / Simulation / startTradingCircle

    startTradingCircle

    - -fun startTradingCircle(tradeBetween: (Int, Int) -> <ERROR CLASS><out <ERROR CLASS>>): Unit
    + +fun startTradingCircle(tradeBetween: (Int, Int) -> <ERROR CLASS><out <ERROR CLASS>>): Unit

    Given a function that returns a future, iterates that function with arguments like (0, 1), (1, 2), (2, 3) etc each time the returned future completes.


    diff --git a/docs/build/html/api/com.r3corda.node.internal.testing/-test-clock/advance-by.html b/docs/build/html/api/com.r3corda.node.internal.testing/-test-clock/advance-by.html index 67d4e2f6f8..194076736f 100644 --- a/docs/build/html/api/com.r3corda.node.internal.testing/-test-clock/advance-by.html +++ b/docs/build/html/api/com.r3corda.node.internal.testing/-test-clock/advance-by.html @@ -8,7 +8,8 @@

    advanceBy

    -fun advanceBy(duration: Duration): Boolean
    +fun advanceBy(duration: Duration): Unit
    +

    Advance this Clock by the specified Duration for testing purposes.



    diff --git a/docs/build/html/api/com.r3corda.node.internal.testing/-test-clock/index.html b/docs/build/html/api/com.r3corda.node.internal.testing/-test-clock/index.html index 74363a5e22..10720346a0 100644 --- a/docs/build/html/api/com.r3corda.node.internal.testing/-test-clock/index.html +++ b/docs/build/html/api/com.r3corda.node.internal.testing/-test-clock/index.html @@ -7,7 +7,7 @@ com.r3corda.node.internal.testing / TestClock

    TestClock

    -class TestClock : MutableClock
    +class TestClock : MutableClock, SerializeAsToken

    A Clock that can have the time advanced for use in testing



    @@ -49,7 +49,8 @@ advanceBy -fun advanceBy(duration: Duration): Boolean +fun advanceBy(duration: Duration): Unit

    Advance this Clock by the specified Duration for testing purposes.

    + @@ -65,9 +66,22 @@ +setTo + +fun setTo(newInstant: Instant): Unit

    Move this Clock to the specified Instant for testing purposes.

    + + + + +toToken + +fun toToken(context: SerializeAsTokenContext): SerializationToken + + + withZone -fun withZone(zone: ZoneId): Clock +fun withZone(zone: ZoneId): Clock diff --git a/docs/build/html/api/com.r3corda.node.internal.testing/-test-clock/set-to.html b/docs/build/html/api/com.r3corda.node.internal.testing/-test-clock/set-to.html new file mode 100644 index 0000000000..a32ac32d5e --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.internal.testing/-test-clock/set-to.html @@ -0,0 +1,19 @@ + + +TestClock.setTo - + + + +com.r3corda.node.internal.testing / TestClock / setTo
    +
    +

    setTo

    + +fun setTo(newInstant: Instant): Unit
    +

    Move this Clock to the specified Instant for testing purposes.

    +

    This will only be approximate due to the time ticking away, but will be some time shortly after the requested Instant.

    +
    +
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.node.internal.testing/-test-clock/to-token.html b/docs/build/html/api/com.r3corda.node.internal.testing/-test-clock/to-token.html new file mode 100644 index 0000000000..a77b6817cd --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.internal.testing/-test-clock/to-token.html @@ -0,0 +1,16 @@ + + +TestClock.toToken - + + + +com.r3corda.node.internal.testing / TestClock / toToken
    +
    +

    toToken

    + +fun toToken(context: SerializeAsTokenContext): SerializationToken
    +Overrides SerializeAsToken.toToken
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.node.internal.testing/-test-clock/with-zone.html b/docs/build/html/api/com.r3corda.node.internal.testing/-test-clock/with-zone.html index 1a62abe9f0..17eb640a5c 100644 --- a/docs/build/html/api/com.r3corda.node.internal.testing/-test-clock/with-zone.html +++ b/docs/build/html/api/com.r3corda.node.internal.testing/-test-clock/with-zone.html @@ -8,7 +8,9 @@

    withZone

    -fun withZone(zone: ZoneId): Clock
    +fun withZone(zone: ZoneId): Clock
    +Deprecated: Do not use this. Instead seek to use ZonedDateTime methods.
    +


    diff --git a/docs/build/html/api/com.r3corda.node.internal.testing/-trade-simulation/index.html b/docs/build/html/api/com.r3corda.node.internal.testing/-trade-simulation/index.html index a3ac6159bf..cf9e1baae5 100644 --- a/docs/build/html/api/com.r3corda.node.internal.testing/-trade-simulation/index.html +++ b/docs/build/html/api/com.r3corda.node.internal.testing/-trade-simulation/index.html @@ -54,9 +54,15 @@ then B and C trade with each other, then C and A etc).

    -currentDay +clocks -var currentDay: LocalDate

    The current simulated date. By default this never changes. If you want it to change, you should do so from +val clocks: <ERROR CLASS> + + + +currentDateAndTime + +var currentDateAndTime: LocalDateTime

    The current simulated date. By default this never changes. If you want it to change, you should do so from within your overridden iterate call. Changes in the current day surface in the dateChanges observable.

    @@ -64,7 +70,7 @@ within your overridden iterate call. C dateChanges -val dateChanges: <ERROR CLASS><LocalDate> +val dateChanges: <ERROR CLASS><LocalDateTime> @@ -106,6 +112,12 @@ in the UI somewhere.

    +networkSendManuallyPumped + +val networkSendManuallyPumped: Boolean + + + notary val notary: SimulatedNode @@ -161,15 +173,15 @@ network bringup has been simulated.

    -linkConsensus +showConsensusFor -fun linkConsensus(nodes: Collection<SimulatedNode>, protocol: ProtocolLogic<*>): Unit +fun showConsensusFor(nodes: List<SimulatedNode>): Unit -linkProtocolProgress +showProgressFor -fun linkProtocolProgress(node: SimulatedNode, protocol: ProtocolLogic<*>): Unit +fun showProgressFor(nodes: List<SimulatedNode>): Unit @@ -181,7 +193,7 @@ network bringup has been simulated.

    startTradingCircle -fun startTradingCircle(tradeBetween: (Int, Int) -> <ERROR CLASS><out <ERROR CLASS>>): Unit

    Given a function that returns a future, iterates that function with arguments like (0, 1), (1, 2), (2, 3) etc +fun startTradingCircle(tradeBetween: (Int, Int) -> <ERROR CLASS><out <ERROR CLASS>>): Unit

    Given a function that returns a future, iterates that function with arguments like (0, 1), (1, 2), (2, 3) etc each time the returned future completes.

    diff --git a/docs/build/html/api/com.r3corda.node.internal.testing/index.html b/docs/build/html/api/com.r3corda.node.internal.testing/index.html index 11f3b82dd1..5dbb825bd8 100644 --- a/docs/build/html/api/com.r3corda.node.internal.testing/index.html +++ b/docs/build/html/api/com.r3corda.node.internal.testing/index.html @@ -36,7 +36,7 @@ Components that do IO are either swapped out for mocks, or pointed to a TestClock -class TestClock : MutableClock

    A Clock that can have the time advanced for use in testing

    +class TestClock : MutableClock, SerializeAsToken

    A Clock that can have the time advanced for use in testing

    @@ -47,11 +47,16 @@ Components that do IO are either swapped out for mocks, or pointed to a + + +

    Extensions for External Classes

    + + +kotlin.collections.Iterable +
    -WalletFiller -object WalletFiller
    @@ -62,13 +67,19 @@ then B and C trade with each other, then C and A etc).

    issueInvalidState -fun issueInvalidState(node: AbstractNode, notary: Party = DUMMY_NOTARY): StateRef +fun issueInvalidState(node: AbstractNode, notary: Party = DUMMY_NOTARY): StateAndRef<*> + + + +issueMultiPartyState + +fun issueMultiPartyState(nodeA: AbstractNode, nodeB: AbstractNode): StateAndRef<MultiOwnerState> issueState -fun issueState(node: AbstractNode, notary: Party = DUMMY_NOTARY): StateRef +fun issueState(node: AbstractNode): StateAndRef<*> diff --git a/docs/build/html/api/com.r3corda.node.internal.testing/issue-invalid-state.html b/docs/build/html/api/com.r3corda.node.internal.testing/issue-invalid-state.html index 972f29cba4..2226b480e0 100644 --- a/docs/build/html/api/com.r3corda.node.internal.testing/issue-invalid-state.html +++ b/docs/build/html/api/com.r3corda.node.internal.testing/issue-invalid-state.html @@ -8,7 +8,7 @@

    issueInvalidState

    -fun issueInvalidState(node: AbstractNode, notary: Party = DUMMY_NOTARY): StateRef
    +fun issueInvalidState(node: AbstractNode, notary: Party = DUMMY_NOTARY): StateAndRef<*>


    diff --git a/docs/build/html/api/com.r3corda.node.internal.testing/issue-multi-party-state.html b/docs/build/html/api/com.r3corda.node.internal.testing/issue-multi-party-state.html new file mode 100644 index 0000000000..d804ff71e4 --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.internal.testing/issue-multi-party-state.html @@ -0,0 +1,15 @@ + + +issueMultiPartyState - + + + +com.r3corda.node.internal.testing / issueMultiPartyState
    +
    +

    issueMultiPartyState

    + +fun issueMultiPartyState(nodeA: AbstractNode, nodeB: AbstractNode): StateAndRef<MultiOwnerState>
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.node.internal.testing/issue-state.html b/docs/build/html/api/com.r3corda.node.internal.testing/issue-state.html index 7671595a78..4c38be0cae 100644 --- a/docs/build/html/api/com.r3corda.node.internal.testing/issue-state.html +++ b/docs/build/html/api/com.r3corda.node.internal.testing/issue-state.html @@ -7,8 +7,8 @@ com.r3corda.node.internal.testing / issueState

    issueState

    - -fun issueState(node: AbstractNode, notary: Party = DUMMY_NOTARY): StateRef
    + +fun issueState(node: AbstractNode): StateAndRef<*>


    diff --git a/docs/build/html/api/com.r3corda.node.internal.testing/kotlin.collections.-iterable/index.html b/docs/build/html/api/com.r3corda.node.internal.testing/kotlin.collections.-iterable/index.html new file mode 100644 index 0000000000..db9b7c5779 --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.internal.testing/kotlin.collections.-iterable/index.html @@ -0,0 +1,23 @@ + + +com.r3corda.node.internal.testing.kotlin.collections.Iterable - + + + +com.r3corda.node.internal.testing / kotlin.collections.Iterable
    +
    +

    Extensions for kotlin.collections.Iterable

    + + + + + + + +
    +setTo +fun Iterable<TestClock>.setTo(instant: Instant): <ERROR CLASS>

    A helper method to set several TestClocks to approximately the same time. The clocks may drift by the time it +takes for each TestClock to have its time set and any observers to execute.

    +
    + + diff --git a/docs/build/html/api/com.r3corda.node.internal.testing/kotlin.collections.-iterable/set-to.html b/docs/build/html/api/com.r3corda.node.internal.testing/kotlin.collections.-iterable/set-to.html new file mode 100644 index 0000000000..6a29e63fe4 --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.internal.testing/kotlin.collections.-iterable/set-to.html @@ -0,0 +1,17 @@ + + +setTo - + + + +com.r3corda.node.internal.testing / kotlin.collections.Iterable / setTo
    +
    +

    setTo

    + +fun Iterable<TestClock>.setTo(instant: Instant): <ERROR CLASS>
    +

    A helper method to set several TestClocks to approximately the same time. The clocks may drift by the time it +takes for each TestClock to have its time set and any observers to execute.

    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.node.internal/-a-p-i-server-impl/fetch-states.html b/docs/build/html/api/com.r3corda.node.internal/-a-p-i-server-impl/fetch-states.html index 780dc42f0d..d6d5319252 100644 --- a/docs/build/html/api/com.r3corda.node.internal/-a-p-i-server-impl/fetch-states.html +++ b/docs/build/html/api/com.r3corda.node.internal/-a-p-i-server-impl/fetch-states.html @@ -8,7 +8,7 @@

    fetchStates

    -fun fetchStates(states: List<StateRef>): Map<StateRef, ContractState?>
    +fun fetchStates(states: List<StateRef>): Map<StateRef, TransactionState<ContractState>?>
    Overrides APIServer.fetchStates


    diff --git a/docs/build/html/api/com.r3corda.node.internal/-a-p-i-server-impl/fetch-transactions.html b/docs/build/html/api/com.r3corda.node.internal/-a-p-i-server-impl/fetch-transactions.html index bd87ee46d3..aacea823fa 100644 --- a/docs/build/html/api/com.r3corda.node.internal/-a-p-i-server-impl/fetch-transactions.html +++ b/docs/build/html/api/com.r3corda.node.internal/-a-p-i-server-impl/fetch-transactions.html @@ -14,8 +14,8 @@ Overrides 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.
    +

    Return
    +null values indicate missing transactions from the requested list.



    diff --git a/docs/build/html/api/com.r3corda.node.internal/-a-p-i-server-impl/index.html b/docs/build/html/api/com.r3corda.node.internal/-a-p-i-server-impl/index.html index 6ae60245ef..c1c3eab456 100644 --- a/docs/build/html/api/com.r3corda.node.internal/-a-p-i-server-impl/index.html +++ b/docs/build/html/api/com.r3corda.node.internal/-a-p-i-server-impl/index.html @@ -63,7 +63,7 @@ successful, otherwise exception is thrown.

    fetchStates -fun fetchStates(states: List<StateRef>): Map<StateRef, ContractState?> +fun fetchStates(states: List<StateRef>): Map<StateRef, TransactionState<ContractState>?> @@ -109,6 +109,13 @@ to avoid calling fetchLedgerTransactions() many times.

    fun serverTime(): LocalDateTime

    Report current UTC time as understood by the platform.

    + + +status + +fun status(): <ERROR CLASS>

    Report whether this node is started up or not

    + + diff --git a/docs/build/html/api/com.r3corda.node.internal/-a-p-i-server-impl/query-states.html b/docs/build/html/api/com.r3corda.node.internal/-a-p-i-server-impl/query-states.html index d2955835c7..6125cc0208 100644 --- a/docs/build/html/api/com.r3corda.node.internal/-a-p-i-server-impl/query-states.html +++ b/docs/build/html/api/com.r3corda.node.internal/-a-p-i-server-impl/query-states.html @@ -16,8 +16,8 @@ to avoid calling fetchLedgerTransactions() many times.

    Parameters

    query - Some "where clause" like expression.
    -Return
    -Zero or more matching States.
    +

    Return
    +Zero or more matching States.



    diff --git a/docs/build/html/api/com.r3corda.node.internal/-a-p-i-server-impl/status.html b/docs/build/html/api/com.r3corda.node.internal/-a-p-i-server-impl/status.html new file mode 100644 index 0000000000..0d79666efa --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.internal/-a-p-i-server-impl/status.html @@ -0,0 +1,17 @@ + + +APIServerImpl.status - + + + +com.r3corda.node.internal / APIServerImpl / status
    +
    +

    status

    + +fun status(): <ERROR CLASS>
    +Overrides APIServer.status
    +

    Report whether this node is started up or not

    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.node.internal/-abstract-node/create-node-dir.html b/docs/build/html/api/com.r3corda.node.internal/-abstract-node/create-node-dir.html new file mode 100644 index 0000000000..9b4a99bb51 --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.internal/-abstract-node/create-node-dir.html @@ -0,0 +1,15 @@ + + +AbstractNode.createNodeDir - + + + +com.r3corda.node.internal / AbstractNode / createNodeDir
    +
    +

    createNodeDir

    + +protected fun createNodeDir(): Unit
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.node.internal/-abstract-node/generate-key-pair.html b/docs/build/html/api/com.r3corda.node.internal/-abstract-node/generate-key-pair.html index 8a8b4fd79e..202dc93f49 100644 --- a/docs/build/html/api/com.r3corda.node.internal/-abstract-node/generate-key-pair.html +++ b/docs/build/html/api/com.r3corda.node.internal/-abstract-node/generate-key-pair.html @@ -8,7 +8,7 @@

    generateKeyPair

    -protected open fun generateKeyPair(): KeyPair
    +protected open fun generateKeyPair(): <ERROR CLASS>


    diff --git a/docs/build/html/api/com.r3corda.node.internal/-abstract-node/index.html b/docs/build/html/api/com.r3corda.node.internal/-abstract-node/index.html index 7199da99cb..ba6f518de8 100644 --- a/docs/build/html/api/com.r3corda.node.internal/-abstract-node/index.html +++ b/docs/build/html/api/com.r3corda.node.internal/-abstract-node/index.html @@ -145,6 +145,12 @@ I/O), or a mock implementation suitable for unit test environments.

    +scheduler + +lateinit var scheduler: SchedulerService + + + serverThread abstract val serverThread: AffinityExecutor @@ -178,7 +184,7 @@ I/O), or a mock implementation suitable for unit test environments.

    storage -lateinit var storage: StorageService +lateinit var storage: TxWritableStorageService @@ -199,6 +205,12 @@ I/O), or a mock implementation suitable for unit test environments.

    +createNodeDir + +fun createNodeDir(): Unit + + + findMyLocation open fun findMyLocation(): PhysicalLocation? @@ -207,13 +219,13 @@ I/O), or a mock implementation suitable for unit test environments.

    generateKeyPair -open fun generateKeyPair(): KeyPair +open fun generateKeyPair(): <ERROR CLASS> initialiseStorageService -open fun initialiseStorageService(dir: Path): <ERROR CLASS><StorageService, CheckpointStorage> +open fun initialiseStorageService(dir: Path): <ERROR CLASS><TxWritableStorageService, CheckpointStorage> @@ -260,6 +272,13 @@ I/O), or a mock implementation suitable for unit test environments.

    +setup + +open fun setup(): AbstractNode

    Run any tasks that are needed to ensure the node is in a correct state before running start()

    + + + + start open fun start(): AbstractNode diff --git a/docs/build/html/api/com.r3corda.node.internal/-abstract-node/initialise-storage-service.html b/docs/build/html/api/com.r3corda.node.internal/-abstract-node/initialise-storage-service.html index a5a05dc9f8..cc979b8276 100644 --- a/docs/build/html/api/com.r3corda.node.internal/-abstract-node/initialise-storage-service.html +++ b/docs/build/html/api/com.r3corda.node.internal/-abstract-node/initialise-storage-service.html @@ -8,7 +8,7 @@

    initialiseStorageService

    -protected open fun initialiseStorageService(dir: Path): <ERROR CLASS><StorageService, CheckpointStorage>
    +protected open fun initialiseStorageService(dir: Path): <ERROR CLASS><TxWritableStorageService, CheckpointStorage>


    diff --git a/docs/build/html/api/com.r3corda.node.internal/-abstract-node/scheduler.html b/docs/build/html/api/com.r3corda.node.internal/-abstract-node/scheduler.html new file mode 100644 index 0000000000..76e0cf73ff --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.internal/-abstract-node/scheduler.html @@ -0,0 +1,15 @@ + + +AbstractNode.scheduler - + + + +com.r3corda.node.internal / AbstractNode / scheduler
    +
    +

    scheduler

    + +lateinit var scheduler: SchedulerService
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.node.internal/-abstract-node/setup.html b/docs/build/html/api/com.r3corda.node.internal/-abstract-node/setup.html new file mode 100644 index 0000000000..51fa9b4bfb --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.internal/-abstract-node/setup.html @@ -0,0 +1,16 @@ + + +AbstractNode.setup - + + + +com.r3corda.node.internal / AbstractNode / setup
    +
    +

    setup

    + +open fun setup(): AbstractNode
    +

    Run any tasks that are needed to ensure the node is in a correct state before running start()

    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.node.internal/-abstract-node/storage.html b/docs/build/html/api/com.r3corda.node.internal/-abstract-node/storage.html index 9a1fb09728..cc51e1fc01 100644 --- a/docs/build/html/api/com.r3corda.node.internal/-abstract-node/storage.html +++ b/docs/build/html/api/com.r3corda.node.internal/-abstract-node/storage.html @@ -8,7 +8,7 @@

    storage

    -lateinit var storage: StorageService
    +lateinit var storage: TxWritableStorageService


    diff --git a/docs/build/html/api/com.r3corda.node.internal/-node/-init-.html b/docs/build/html/api/com.r3corda.node.internal/-node/-init-.html index 37981a39c8..328efc2d5a 100644 --- a/docs/build/html/api/com.r3corda.node.internal/-node/-init-.html +++ b/docs/build/html/api/com.r3corda.node.internal/-node/-init-.html @@ -7,7 +7,7 @@ com.r3corda.node.internal / Node / <init>

    <init>

    -Node(dir: Path, p2pAddr: <ERROR CLASS>, configuration: NodeConfiguration, networkMapAddress: NodeInfo?, advertisedServices: Set<ServiceType>, clock: Clock = NodeClock(), clientAPIs: List<Class<*>> = listOf())
    +Node(dir: Path, p2pAddr: <ERROR CLASS>, webServerAddr: <ERROR CLASS>, configuration: NodeConfiguration, networkMapAddress: NodeInfo?, advertisedServices: Set<ServiceType>, clock: Clock = NodeClock(), clientAPIs: List<Class<*>> = listOf())

    A Node manages a standalone server that takes part in the P2P network. It creates the services found in ServiceHub, loads important data off disk and starts listening for connections.

    Parameters

    diff --git a/docs/build/html/api/com.r3corda.node.internal/-node/index.html b/docs/build/html/api/com.r3corda.node.internal/-node/index.html index aec969fc20..92ab822155 100644 --- a/docs/build/html/api/com.r3corda.node.internal/-node/index.html +++ b/docs/build/html/api/com.r3corda.node.internal/-node/index.html @@ -45,7 +45,7 @@ Listed clientAPI classes are assumed to have to take a single APIServer construc <init> -Node(dir: Path, p2pAddr: <ERROR CLASS>, configuration: NodeConfiguration, networkMapAddress: NodeInfo?, advertisedServices: Set<ServiceType>, clock: Clock = NodeClock(), clientAPIs: List<Class<*>> = listOf())

    A Node manages a standalone server that takes part in the P2P network. It creates the services found in ServiceHub, +Node(dir: Path, p2pAddr: <ERROR CLASS>, webServerAddr: <ERROR CLASS>, configuration: NodeConfiguration, networkMapAddress: NodeInfo?, advertisedServices: Set<ServiceType>, clock: Clock = NodeClock(), clientAPIs: List<Class<*>> = listOf())

    A Node manages a standalone server that takes part in the P2P network. It creates the services found in ServiceHub, loads important data off disk and starts listening for connections.

    @@ -84,6 +84,12 @@ loads important data off disk and starts listening for connections.

    lateinit var webServer: <ERROR CLASS> + + +webServerAddr + +val webServerAddr: <ERROR CLASS> +

    Inherited Properties

    @@ -200,6 +206,12 @@ loads important data off disk and starts listening for connections.

    +scheduler + +lateinit var scheduler: SchedulerService + + + services val services: ServiceHubInternal @@ -227,7 +239,7 @@ loads important data off disk and starts listening for connections.

    storage -lateinit var storage: StorageService +lateinit var storage: TxWritableStorageService @@ -248,6 +260,13 @@ loads important data off disk and starts listening for connections.

    +setup + +fun setup(): Node

    Run any tasks that are needed to ensure the node is in a correct state before running start()

    + + + + start fun start(): Node @@ -277,6 +296,12 @@ loads important data off disk and starts listening for connections.

    +createNodeDir + +fun createNodeDir(): Unit + + + findMyLocation open fun findMyLocation(): PhysicalLocation? @@ -285,13 +310,13 @@ loads important data off disk and starts listening for connections.

    generateKeyPair -open fun generateKeyPair(): KeyPair +open fun generateKeyPair(): <ERROR CLASS> initialiseStorageService -open fun initialiseStorageService(dir: Path): <ERROR CLASS><StorageService, CheckpointStorage> +open fun initialiseStorageService(dir: Path): <ERROR CLASS><TxWritableStorageService, CheckpointStorage> diff --git a/docs/build/html/api/com.r3corda.node.internal/-node/setup.html b/docs/build/html/api/com.r3corda.node.internal/-node/setup.html new file mode 100644 index 0000000000..d558159ff9 --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.internal/-node/setup.html @@ -0,0 +1,17 @@ + + +Node.setup - + + + +com.r3corda.node.internal / Node / setup
    +
    +

    setup

    + +fun setup(): Node
    +Overrides AbstractNode.setup
    +

    Run any tasks that are needed to ensure the node is in a correct state before running start()

    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.node.internal/-node/web-server-addr.html b/docs/build/html/api/com.r3corda.node.internal/-node/web-server-addr.html new file mode 100644 index 0000000000..1bdd912829 --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.internal/-node/web-server-addr.html @@ -0,0 +1,15 @@ + + +Node.webServerAddr - + + + +com.r3corda.node.internal / Node / webServerAddr
    +
    +

    webServerAddr

    + +val webServerAddr: <ERROR CLASS>
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.node.services.api/-abstract-node-service/-init-.html b/docs/build/html/api/com.r3corda.node.services.api/-abstract-node-service/-init-.html index a4fbadae50..3e66ba201a 100644 --- a/docs/build/html/api/com.r3corda.node.services.api/-abstract-node-service/-init-.html +++ b/docs/build/html/api/com.r3corda.node.services.api/-abstract-node-service/-init-.html @@ -7,7 +7,7 @@ com.r3corda.node.services.api / AbstractNodeService / <init>

    <init>

    -AbstractNodeService(net: MessagingService)
    +AbstractNodeService(net: MessagingService, networkMapCache: NetworkMapCache)

    Abstract superclass for services that a node can host, which provides helper functions.



    diff --git a/docs/build/html/api/com.r3corda.node.services.api/-abstract-node-service/add-message-handler.html b/docs/build/html/api/com.r3corda.node.services.api/-abstract-node-service/add-message-handler.html index 2f5176e9be..5b1fa9b396 100644 --- a/docs/build/html/api/com.r3corda.node.services.api/-abstract-node-service/add-message-handler.html +++ b/docs/build/html/api/com.r3corda.node.services.api/-abstract-node-service/add-message-handler.html @@ -8,30 +8,32 @@

    addMessageHandler

    -protected inline fun <reified Q : AbstractRequestMessage, reified R : Any> addMessageHandler(topic: String, crossinline handler: (Q) -> R, crossinline exceptionConsumer: (Message, Exception) -> Unit): Unit
    +protected inline fun <reified Q : ServiceRequestMessage, reified R : Any> addMessageHandler(topic: String, crossinline handler: (Q) -> R, crossinline exceptionConsumer: (Message, Exception) -> Unit): Unit

    Register a handler for a message topic. In comparison to using net.addMessageHandler() this manages a lot of -common boilerplate code. Exceptions are caught and passed to the provided consumer.

    +common boilerplate code. Exceptions are caught and passed to the provided consumer. If you just want a simple +acknowledgement response with no content, use com.r3corda.core.messaging.Ack

    Parameters

    topic - the topic, without the default session ID postfix (".0)

    -handler - a function to handle the deserialised request and return a response
    +handler - a function to handle the deserialised request and return an optional response (if return type not Unit)

    exceptionConsumer - a function to which any thrown exception is passed.


    -protected inline fun <reified Q : AbstractRequestMessage, reified R : Any> addMessageHandler(topic: String, crossinline handler: (Q) -> R): Unit
    +protected inline fun <reified Q : ServiceRequestMessage, reified R : Any> addMessageHandler(topic: String, crossinline handler: (Q) -> R): Unit

    Register a handler for a message topic. In comparison to using net.addMessageHandler() this manages a lot of -common boilerplate code. Exceptions are propagated to the messaging layer.

    +common boilerplate code. Exceptions are propagated to the messaging layer. If you just want a simple +acknowledgement response with no content, use com.r3corda.core.messaging.Ack

    Parameters

    topic - the topic, without the default session ID postfix (".0)

    -handler - a function to handle the deserialised request and return a response
    +handler - a function to handle the deserialised request and return an optional response (if return type not Unit)


    diff --git a/docs/build/html/api/com.r3corda.node.services.api/-abstract-node-service/index.html b/docs/build/html/api/com.r3corda.node.services.api/-abstract-node-service/index.html index 1af1aaaf89..c643e4a666 100644 --- a/docs/build/html/api/com.r3corda.node.services.api/-abstract-node-service/index.html +++ b/docs/build/html/api/com.r3corda.node.services.api/-abstract-node-service/index.html @@ -7,7 +7,7 @@ com.r3corda.node.services.api / AbstractNodeService

    AbstractNodeService

    -abstract class AbstractNodeService
    +abstract class AbstractNodeService : SingletonSerializeAsToken

    Abstract superclass for services that a node can host, which provides helper functions.



    @@ -18,7 +18,7 @@ <init> -AbstractNodeService(net: MessagingService)

    Abstract superclass for services that a node can host, which provides helper functions.

    +AbstractNodeService(net: MessagingService, networkMapCache: NetworkMapCache)

    Abstract superclass for services that a node can host, which provides helper functions.

    @@ -32,6 +32,12 @@ val net: MessagingService + + +networkMapCache + +val networkMapCache: NetworkMapCache +

    Functions

    @@ -41,14 +47,27 @@ addMessageHandler -fun <Q : AbstractRequestMessage, R : Any> addMessageHandler(topic: String, handler: (Q) -> R, exceptionConsumer: (Message, Exception) -> Unit): Unit

    Register a handler for a message topic. In comparison to using net.addMessageHandler() this manages a lot of -common boilerplate code. Exceptions are caught and passed to the provided consumer.

    -fun <Q : AbstractRequestMessage, R : Any> addMessageHandler(topic: String, handler: (Q) -> R): Unit

    Register a handler for a message topic. In comparison to using net.addMessageHandler() this manages a lot of -common boilerplate code. Exceptions are propagated to the messaging layer.

    +fun <Q : ServiceRequestMessage, R : Any> addMessageHandler(topic: String, handler: (Q) -> R, exceptionConsumer: (Message, Exception) -> Unit): Unit

    Register a handler for a message topic. In comparison to using net.addMessageHandler() this manages a lot of +common boilerplate code. Exceptions are caught and passed to the provided consumer. If you just want a simple +acknowledgement response with no content, use com.r3corda.core.messaging.Ack

    +fun <Q : ServiceRequestMessage, R : Any> addMessageHandler(topic: String, handler: (Q) -> R): Unit

    Register a handler for a message topic. In comparison to using net.addMessageHandler() this manages a lot of +common boilerplate code. Exceptions are propagated to the messaging layer. If you just want a simple +acknowledgement response with no content, use com.r3corda.core.messaging.Ack

    +

    Inherited Functions

    + + + + + + + +
    +toToken +open fun toToken(context: SerializeAsTokenContext): SerializationToken

    Inheritors

    @@ -68,6 +87,14 @@ glue that sits between the network layer and the database layer.

    + + + + + + + + @@ -68,6 +91,20 @@
    +NotaryChangeService +class NotaryChangeService : AbstractNodeService

    A service that monitors the network for requests for changing the notary of a state, +and immediately runs the NotaryChangeProtocol if the auto-accept criteria are met.

    +
    NotaryService abstract class NotaryService : AbstractNodeService

    A Notary service acts as the final signer of a transaction ensuring two things:

    diff --git a/docs/build/html/api/com.r3corda.node.services.api/-abstract-node-service/network-map-cache.html b/docs/build/html/api/com.r3corda.node.services.api/-abstract-node-service/network-map-cache.html new file mode 100644 index 0000000000..aa82cd1246 --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.services.api/-abstract-node-service/network-map-cache.html @@ -0,0 +1,15 @@ + + +AbstractNodeService.networkMapCache - + + + +com.r3corda.node.services.api / AbstractNodeService / networkMapCache
    +
    +

    networkMapCache

    + +val networkMapCache: NetworkMapCache
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.node.services.api/-service-hub-internal/-init-.html b/docs/build/html/api/com.r3corda.node.services.api/-service-hub-internal/-init-.html new file mode 100644 index 0000000000..949e8c0dda --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.services.api/-service-hub-internal/-init-.html @@ -0,0 +1,14 @@ + + +ServiceHubInternal.<init> - + + + +com.r3corda.node.services.api / ServiceHubInternal / <init>
    +
    +

    <init>

    +ServiceHubInternal()
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.node.services.api/-service-hub-internal/index.html b/docs/build/html/api/com.r3corda.node.services.api/-service-hub-internal/index.html index d82d7660e8..87764128a3 100644 --- a/docs/build/html/api/com.r3corda.node.services.api/-service-hub-internal/index.html +++ b/docs/build/html/api/com.r3corda.node.services.api/-service-hub-internal/index.html @@ -7,9 +7,20 @@ com.r3corda.node.services.api / ServiceHubInternal

    ServiceHubInternal

    -interface ServiceHubInternal : ServiceHub
    +abstract class ServiceHubInternal : ServiceHub


    +

    Constructors

    + + + + + + + +
    +<init> +ServiceHubInternal()

    Properties

    @@ -19,6 +30,12 @@ + + + +
    abstract val monitoringService: MonitoringService
    +protocolLogicRefFactory +abstract val protocolLogicRefFactory: ProtocolLogicRefFactory

    Inherited Properties

    @@ -56,6 +73,12 @@
    +schedulerService +abstract val schedulerService: SchedulerService
    storageService abstract val storageService: StorageService
    +

    Functions

    + + + + + + + +
    +startProtocol +abstract fun <T> startProtocol(loggerName: String, logic: ProtocolLogic<T>): <ERROR CLASS><T>

    TODO: borrowing this method from service manager work in another branch. Its required to avoid circular dependency +between SMM and the scheduler. That particular problem should also be resolved by the service manager work +itself, at which point this method would not be needed (by the scheduler)

    +

    Inherited Functions

    @@ -75,14 +112,16 @@ @@ -97,5 +136,18 @@ transaction. If no exception is thrown, the transaction is valid.

    loadState -open fun loadState(stateRef: StateRef): ContractState

    Given a StateRef loads the referenced transaction and looks up the specified output ContractState

    +open fun loadState(stateRef: StateRef): TransactionState<*>

    Given a StateRef loads the referenced transaction and looks up the specified output ContractState

    recordTransactions -open fun recordTransactions(txs: List<SignedTransaction>): Unit

    Given a list of SignedTransactions, writes them to the local storage for validated transactions and then +abstract fun recordTransactions(txs: Iterable<SignedTransaction>): Unit

    Given a list of SignedTransactions, writes them to the local storage for validated transactions and then +sends them to the wallet for further processing.

    +open fun recordTransactions(vararg txs: SignedTransaction): <ERROR CLASS>

    Given some SignedTransactions, writes them to the local storage for validated transactions and then sends them to the wallet for further processing.

    +

    Extension Functions

    + + + + + + + +
    +fillWithSomeTestCash +fun ServiceHub.fillWithSomeTestCash(howMuch: Amount<Currency>, notary: Party = DUMMY_NOTARY, atLeastThisManyStates: Int = 3, atMostThisManyStates: Int = 10, rng: Random = Random(), ref: OpaqueBytes = OpaqueBytes(ByteArray(1, { 0 }))): Wallet

    Creates a random set of between (by default) 3 and 10 cash states that add up to the given amount and adds them +to the wallet. This is intended for unit tests.

    +
    diff --git a/docs/build/html/api/com.r3corda.node.services.api/-service-hub-internal/protocol-logic-ref-factory.html b/docs/build/html/api/com.r3corda.node.services.api/-service-hub-internal/protocol-logic-ref-factory.html new file mode 100644 index 0000000000..ac451032a4 --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.services.api/-service-hub-internal/protocol-logic-ref-factory.html @@ -0,0 +1,15 @@ + + +ServiceHubInternal.protocolLogicRefFactory - + + + +com.r3corda.node.services.api / ServiceHubInternal / protocolLogicRefFactory
    +
    +

    protocolLogicRefFactory

    + +abstract val protocolLogicRefFactory: ProtocolLogicRefFactory
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.node.services.api/-service-hub-internal/start-protocol.html b/docs/build/html/api/com.r3corda.node.services.api/-service-hub-internal/start-protocol.html new file mode 100644 index 0000000000..b91f456d66 --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.services.api/-service-hub-internal/start-protocol.html @@ -0,0 +1,18 @@ + + +ServiceHubInternal.startProtocol - + + + +com.r3corda.node.services.api / ServiceHubInternal / startProtocol
    +
    +

    startProtocol

    + +abstract fun <T> startProtocol(loggerName: String, logic: ProtocolLogic<T>): <ERROR CLASS><T>
    +

    TODO: borrowing this method from service manager work in another branch. Its required to avoid circular dependency +between SMM and the scheduler. That particular problem should also be resolved by the service manager work +itself, at which point this method would not be needed (by the scheduler)

    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.node.services.api/index.html b/docs/build/html/api/com.r3corda.node.services.api/index.html index fc4a4ac1dd..936dc89ec4 100644 --- a/docs/build/html/api/com.r3corda.node.services.api/index.html +++ b/docs/build/html/api/com.r3corda.node.services.api/index.html @@ -14,7 +14,7 @@ AbstractNodeService -abstract class AbstractNodeService

    Abstract superclass for services that a node can host, which provides helper functions.

    +abstract class AbstractNodeService : SingletonSerializeAsToken

    Abstract superclass for services that a node can host, which provides helper functions.

    @@ -56,7 +56,7 @@ This is not an interface because it is too lightweight to bother mocking out.

    ServiceHubInternal -interface ServiceHubInternal : ServiceHub +abstract class ServiceHubInternal : ServiceHub diff --git a/docs/build/html/api/com.r3corda.node.services.clientapi/-node-interest-rates/-oracle/-init-.html b/docs/build/html/api/com.r3corda.node.services.clientapi/-node-interest-rates/-oracle/-init-.html index 79771ec824..b63c80734f 100644 --- a/docs/build/html/api/com.r3corda.node.services.clientapi/-node-interest-rates/-oracle/-init-.html +++ b/docs/build/html/api/com.r3corda.node.services.clientapi/-node-interest-rates/-oracle/-init-.html @@ -7,7 +7,7 @@ com.r3corda.node.services.clientapi / NodeInterestRates / Oracle / <init>

    <init>

    -Oracle(identity: Party, signingKey: KeyPair)
    +Oracle(identity: Party, signingKey: KeyPair, clock: Clock)

    An implementation of an interest rate fix oracle which is given data in a simple string format.

    The oracle will try to interpolate the missing value of a tenor for the given fix name and date.


    diff --git a/docs/build/html/api/com.r3corda.node.services.clientapi/-node-interest-rates/-oracle/clock.html b/docs/build/html/api/com.r3corda.node.services.clientapi/-node-interest-rates/-oracle/clock.html new file mode 100644 index 0000000000..aebde2d534 --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.services.clientapi/-node-interest-rates/-oracle/clock.html @@ -0,0 +1,15 @@ + + +NodeInterestRates.Oracle.clock - + + + +com.r3corda.node.services.clientapi / NodeInterestRates / Oracle / clock
    +
    +

    clock

    + +val clock: Clock
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.node.services.clientapi/-node-interest-rates/-oracle/index.html b/docs/build/html/api/com.r3corda.node.services.clientapi/-node-interest-rates/-oracle/index.html index e44b0c9a5b..55f4f285e2 100644 --- a/docs/build/html/api/com.r3corda.node.services.clientapi/-node-interest-rates/-oracle/index.html +++ b/docs/build/html/api/com.r3corda.node.services.clientapi/-node-interest-rates/-oracle/index.html @@ -21,7 +21,7 @@ <init> -Oracle(identity: Party, signingKey: KeyPair)

    An implementation of an interest rate fix oracle which is given data in a simple string format.

    +Oracle(identity: Party, signingKey: KeyPair, clock: Clock)

    An implementation of an interest rate fix oracle which is given data in a simple string format.

    @@ -31,6 +31,12 @@ +clock + +val clock: Clock + + + identity val identity: Party @@ -50,7 +56,10 @@ query -fun query(queries: List<FixOf>): List<Fix> +fun query(queries: List<FixOf>, deadline: Instant): List<Fix>

    This method will now wait until the given deadline if the fix for the given FixOf is not immediately +available. To implement this, readWithDeadline will loop if the deadline is not reached and we throw +UnknownFix as it implements RetryableException which has special meaning to this function.

    + diff --git a/docs/build/html/api/com.r3corda.node.services.clientapi/-node-interest-rates/-oracle/query.html b/docs/build/html/api/com.r3corda.node.services.clientapi/-node-interest-rates/-oracle/query.html index 904322ccc3..93164e93b0 100644 --- a/docs/build/html/api/com.r3corda.node.services.clientapi/-node-interest-rates/-oracle/query.html +++ b/docs/build/html/api/com.r3corda.node.services.clientapi/-node-interest-rates/-oracle/query.html @@ -7,8 +7,11 @@ com.r3corda.node.services.clientapi / NodeInterestRates / Oracle / query

    query

    - -fun query(queries: List<FixOf>): List<Fix>
    + +fun query(queries: List<FixOf>, deadline: Instant): List<Fix>
    +

    This method will now wait until the given deadline if the fix for the given FixOf is not immediately +available. To implement this, readWithDeadline will loop if the deadline is not reached and we throw +UnknownFix as it implements RetryableException which has special meaning to this function.



    diff --git a/docs/build/html/api/com.r3corda.node.services.clientapi/-node-interest-rates/-service/index.html b/docs/build/html/api/com.r3corda.node.services.clientapi/-node-interest-rates/-service/index.html index 9bea4ae0d0..a05c3ad822 100644 --- a/docs/build/html/api/com.r3corda.node.services.clientapi/-node-interest-rates/-service/index.html +++ b/docs/build/html/api/com.r3corda.node.services.clientapi/-node-interest-rates/-service/index.html @@ -63,6 +63,12 @@ val net: MessagingService + + +networkMapCache + +val networkMapCache: NetworkMapCache +

    Functions

    @@ -85,10 +91,12 @@ back to the user in the response.

    addMessageHandler -fun <Q : AbstractRequestMessage, R : Any> addMessageHandler(topic: String, handler: (Q) -> R, exceptionConsumer: (Message, Exception) -> Unit): Unit

    Register a handler for a message topic. In comparison to using net.addMessageHandler() this manages a lot of -common boilerplate code. Exceptions are caught and passed to the provided consumer.

    -fun <Q : AbstractRequestMessage, R : Any> addMessageHandler(topic: String, handler: (Q) -> R): Unit

    Register a handler for a message topic. In comparison to using net.addMessageHandler() this manages a lot of -common boilerplate code. Exceptions are propagated to the messaging layer.

    +fun <Q : ServiceRequestMessage, R : Any> addMessageHandler(topic: String, handler: (Q) -> R, exceptionConsumer: (Message, Exception) -> Unit): Unit

    Register a handler for a message topic. In comparison to using net.addMessageHandler() this manages a lot of +common boilerplate code. Exceptions are caught and passed to the provided consumer. If you just want a simple +acknowledgement response with no content, use com.r3corda.core.messaging.Ack

    +fun <Q : ServiceRequestMessage, R : Any> addMessageHandler(topic: String, handler: (Q) -> R): Unit

    Register a handler for a message topic. In comparison to using net.addMessageHandler() this manages a lot of +common boilerplate code. Exceptions are propagated to the messaging layer. If you just want a simple +acknowledgement response with no content, use com.r3corda.core.messaging.Ack

    diff --git a/docs/build/html/api/com.r3corda.node.services.clientapi/-node-interest-rates/-unknown-fix/index.html b/docs/build/html/api/com.r3corda.node.services.clientapi/-node-interest-rates/-unknown-fix/index.html index d0d9c30710..dd0b21c140 100644 --- a/docs/build/html/api/com.r3corda.node.services.clientapi/-node-interest-rates/-unknown-fix/index.html +++ b/docs/build/html/api/com.r3corda.node.services.clientapi/-node-interest-rates/-unknown-fix/index.html @@ -7,7 +7,7 @@ com.r3corda.node.services.clientapi / NodeInterestRates / UnknownFix

    UnknownFix

    -class UnknownFix : Exception
    +class UnknownFix : RetryableException


    Constructors

    @@ -32,16 +32,5 @@ -

    Functions

    - - - - - - - -
    -toString -fun toString(): String
    diff --git a/docs/build/html/api/com.r3corda.node.services.clientapi/-node-interest-rates/index.html b/docs/build/html/api/com.r3corda.node.services.clientapi/-node-interest-rates/index.html index 0cf4832dcd..e0c26024ce 100644 --- a/docs/build/html/api/com.r3corda.node.services.clientapi/-node-interest-rates/index.html +++ b/docs/build/html/api/com.r3corda.node.services.clientapi/-node-interest-rates/index.html @@ -65,7 +65,7 @@ Interpolates missing values using the provided interpolation mechanism.

    UnknownFix -class UnknownFix : Exception +class UnknownFix : RetryableException diff --git a/docs/build/html/api/com.r3corda.node.services.events/-node-scheduler-service/-init-.html b/docs/build/html/api/com.r3corda.node.services.events/-node-scheduler-service/-init-.html new file mode 100644 index 0000000000..fd2d6c6066 --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.services.events/-node-scheduler-service/-init-.html @@ -0,0 +1,35 @@ + + +NodeSchedulerService.<init> - + + + +com.r3corda.node.services.events / NodeSchedulerService / <init>
    +
    +

    <init>

    +NodeSchedulerService(services: ServiceHubInternal, protocolLogicRefFactory: ProtocolLogicRefFactory = ProtocolLogicRefFactory(), schedulerTimerExecutor: Executor = Executors.newSingleThreadExecutor())
    +

    A first pass of a simple SchedulerService that works with MutableClocks for testing, demonstrations and simulations +that also encompasses the Wallet observer for processing transactions.

    +

    This will observe transactions as they are stored and schedule and unschedule activities based on the States consumed +or produced.

    +

    TODO: Needs extensive support from persistence and protocol frameworks to be truly reliable and atomic.

    +

    Currently does not provide any system state other than the ContractState so the expectation is that a transaction +is the outcome of the activity in order to schedule another activity. Once we have implemented more persistence +in the nodes, maybe we can consider multiple activities and whether the activities have been completed or not, +but that starts to sound a lot like off-ledger state.

    +
    +
    +

    Parameters

    + +services - Core node services.
    +
    + +protocolLogicRefFactory - Factory for restoring ProtocolLogic instances from references.
    +
    + +schedulerTimerExecutor - The executor the scheduler blocks on waiting for the clock to advance to the next +activity. Only replace this for unit testing purposes. This is not the executor the ProtocolLogic is launched on.
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.node.services.events/-node-scheduler-service/index.html b/docs/build/html/api/com.r3corda.node.services.events/-node-scheduler-service/index.html new file mode 100644 index 0000000000..bf47a14e04 --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.services.events/-node-scheduler-service/index.html @@ -0,0 +1,78 @@ + + +NodeSchedulerService - + + + +com.r3corda.node.services.events / NodeSchedulerService
    +
    +

    NodeSchedulerService

    +class NodeSchedulerService : SchedulerService, SingletonSerializeAsToken
    +

    A first pass of a simple SchedulerService that works with MutableClocks for testing, demonstrations and simulations +that also encompasses the Wallet observer for processing transactions.

    +

    This will observe transactions as they are stored and schedule and unschedule activities based on the States consumed +or produced.

    +

    TODO: Needs extensive support from persistence and protocol frameworks to be truly reliable and atomic.

    +

    Currently does not provide any system state other than the ContractState so the expectation is that a transaction +is the outcome of the activity in order to schedule another activity. Once we have implemented more persistence +in the nodes, maybe we can consider multiple activities and whether the activities have been completed or not, +but that starts to sound a lot like off-ledger state.

    +
    +
    +

    Parameters

    + +services - Core node services.
    +
    + +protocolLogicRefFactory - Factory for restoring ProtocolLogic instances from references.
    +
    + +schedulerTimerExecutor - The executor the scheduler blocks on waiting for the clock to advance to the next +activity. Only replace this for unit testing purposes. This is not the executor the ProtocolLogic is launched on.
    +
    +
    +

    Constructors

    + + + + + + + +
    +<init> +NodeSchedulerService(services: ServiceHubInternal, protocolLogicRefFactory: ProtocolLogicRefFactory = ProtocolLogicRefFactory(), schedulerTimerExecutor: Executor = Executors.newSingleThreadExecutor())

    A first pass of a simple SchedulerService that works with MutableClocks for testing, demonstrations and simulations +that also encompasses the Wallet observer for processing transactions.

    +
    +

    Functions

    + + + + + + + + + + + +
    +scheduleStateActivity +fun scheduleStateActivity(action: ScheduledStateRef): Unit

    Schedule a new activity for a TX output, probably because it was just produced.

    +
    +unscheduleStateActivity +fun unscheduleStateActivity(ref: StateRef): Unit

    Unschedule all activity for a TX output, probably because it was consumed.

    +
    +

    Inherited Functions

    + + + + + + + +
    +toToken +open fun toToken(context: SerializeAsTokenContext): SerializationToken
    + + diff --git a/docs/build/html/api/com.r3corda.node.services.events/-node-scheduler-service/schedule-state-activity.html b/docs/build/html/api/com.r3corda.node.services.events/-node-scheduler-service/schedule-state-activity.html new file mode 100644 index 0000000000..de952a17a0 --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.services.events/-node-scheduler-service/schedule-state-activity.html @@ -0,0 +1,21 @@ + + +NodeSchedulerService.scheduleStateActivity - + + + +com.r3corda.node.services.events / NodeSchedulerService / scheduleStateActivity
    +
    +

    scheduleStateActivity

    + +fun scheduleStateActivity(action: ScheduledStateRef): Unit
    +Overrides SchedulerService.scheduleStateActivity
    +

    Schedule a new activity for a TX output, probably because it was just produced.

    +

    Only one activity can be scheduled for a particular StateRef at any one time. Scheduling a ScheduledStateRef +replaces any previously scheduled ScheduledStateRef for any one StateRef.

    +
    +
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.node.services.events/-node-scheduler-service/unschedule-state-activity.html b/docs/build/html/api/com.r3corda.node.services.events/-node-scheduler-service/unschedule-state-activity.html new file mode 100644 index 0000000000..51c2dfd287 --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.services.events/-node-scheduler-service/unschedule-state-activity.html @@ -0,0 +1,17 @@ + + +NodeSchedulerService.unscheduleStateActivity - + + + +com.r3corda.node.services.events / NodeSchedulerService / unscheduleStateActivity
    +
    +

    unscheduleStateActivity

    + +fun unscheduleStateActivity(ref: StateRef): Unit
    +Overrides SchedulerService.unscheduleStateActivity
    +

    Unschedule all activity for a TX output, probably because it was consumed.

    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.node.services.events/-scheduled-activity-observer/-init-.html b/docs/build/html/api/com.r3corda.node.services.events/-scheduled-activity-observer/-init-.html new file mode 100644 index 0000000000..9b35e03e46 --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.services.events/-scheduled-activity-observer/-init-.html @@ -0,0 +1,16 @@ + + +ScheduledActivityObserver.<init> - + + + +com.r3corda.node.services.events / ScheduledActivityObserver / <init>
    +
    +

    <init>

    +ScheduledActivityObserver(services: ServiceHubInternal)
    +

    This observes the wallet and schedules and unschedules activities appropriately based on state production and +consumption.

    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.node.services.events/-scheduled-activity-observer/index.html b/docs/build/html/api/com.r3corda.node.services.events/-scheduled-activity-observer/index.html new file mode 100644 index 0000000000..158ba7c287 --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.services.events/-scheduled-activity-observer/index.html @@ -0,0 +1,40 @@ + + +ScheduledActivityObserver - + + + +com.r3corda.node.services.events / ScheduledActivityObserver
    +
    +

    ScheduledActivityObserver

    +class ScheduledActivityObserver
    +

    This observes the wallet and schedules and unschedules activities appropriately based on state production and +consumption.

    +
    +
    +

    Constructors

    + + + + + + + +
    +<init> +ScheduledActivityObserver(services: ServiceHubInternal)

    This observes the wallet and schedules and unschedules activities appropriately based on state production and +consumption.

    +
    +

    Properties

    + + + + + + + +
    +services +val services: ServiceHubInternal
    + + diff --git a/docs/build/html/api/com.r3corda.node.services.events/-scheduled-activity-observer/services.html b/docs/build/html/api/com.r3corda.node.services.events/-scheduled-activity-observer/services.html new file mode 100644 index 0000000000..4dd01b933f --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.services.events/-scheduled-activity-observer/services.html @@ -0,0 +1,15 @@ + + +ScheduledActivityObserver.services - + + + +com.r3corda.node.services.events / ScheduledActivityObserver / services
    +
    +

    services

    + +val services: ServiceHubInternal
    +
    +
    + + diff --git a/docs/build/html/api/com.r3corda.node.services.events/index.html b/docs/build/html/api/com.r3corda.node.services.events/index.html new file mode 100644 index 0000000000..fda2bfe737 --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.services.events/index.html @@ -0,0 +1,32 @@ + + +com.r3corda.node.services.events - + + + +com.r3corda.node.services.events
    +
    +

    Package com.r3corda.node.services.events

    +

    Types

    + + + + + + + + + + + +
    +NodeSchedulerService +class NodeSchedulerService : SchedulerService, SingletonSerializeAsToken

    A first pass of a simple SchedulerService that works with MutableClocks for testing, demonstrations and simulations +that also encompasses the Wallet observer for processing transactions.

    +
    +ScheduledActivityObserver +class ScheduledActivityObserver

    This observes the wallet and schedules and unschedules activities appropriately based on state production and +consumption.

    +
    + + diff --git a/docs/build/html/api/com.r3corda.node.services.keys/-e2-e-test-key-management-service/-init-.html b/docs/build/html/api/com.r3corda.node.services.keys/-e2-e-test-key-management-service/-init-.html index ea707c5e9b..2c48aa30d4 100644 --- a/docs/build/html/api/com.r3corda.node.services.keys/-e2-e-test-key-management-service/-init-.html +++ b/docs/build/html/api/com.r3corda.node.services.keys/-e2-e-test-key-management-service/-init-.html @@ -7,7 +7,7 @@ com.r3corda.node.services.keys / E2ETestKeyManagementService / <init>

    <init>

    -E2ETestKeyManagementService()
    +E2ETestKeyManagementService(initialKeys: Set<KeyPair>)

    A simple in-memory KMS that doesnt bother saving keys to disk. A real implementation would:

    • Probably be accessed via the network layer as an internal node service i.e. via a message queue, so it can run on a separate/firewalled service.

      diff --git a/docs/build/html/api/com.r3corda.node.services.keys/-e2-e-test-key-management-service/index.html b/docs/build/html/api/com.r3corda.node.services.keys/-e2-e-test-key-management-service/index.html index 1a8340dafa..93e6aa8d82 100644 --- a/docs/build/html/api/com.r3corda.node.services.keys/-e2-e-test-key-management-service/index.html +++ b/docs/build/html/api/com.r3corda.node.services.keys/-e2-e-test-key-management-service/index.html @@ -26,7 +26,7 @@ on a separate/firewalled service.

      <init> -E2ETestKeyManagementService()

      A simple in-memory KMS that doesnt bother saving keys to disk. A real implementation would:

      +E2ETestKeyManagementService(initialKeys: Set<KeyPair>)

      A simple in-memory KMS that doesnt bother saving keys to disk. A real implementation would:

      diff --git a/docs/build/html/api/com.r3corda.node.services.keys/-e2-e-test-key-management-service/keys.html b/docs/build/html/api/com.r3corda.node.services.keys/-e2-e-test-key-management-service/keys.html index 8e06733bf4..933a5136fc 100644 --- a/docs/build/html/api/com.r3corda.node.services.keys/-e2-e-test-key-management-service/keys.html +++ b/docs/build/html/api/com.r3corda.node.services.keys/-e2-e-test-key-management-service/keys.html @@ -11,9 +11,9 @@ val keys: Map<PublicKey, PrivateKey>
      Overrides KeyManagementService.keys

      Returns a snapshot of the current pubkey->privkey mapping.

      -Getter
      +

      Getter

      Returns a snapshot of the current pubkey->privkey mapping.

      -
      +



      diff --git a/docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/-in-memory-messaging/index.html b/docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/-in-memory-messaging/index.html index 2449904983..10f5e2569a 100644 --- a/docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/-in-memory-messaging/index.html +++ b/docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/-in-memory-messaging/index.html @@ -97,9 +97,9 @@ executor. The topic can be the empty string to match all messages.

      -pump +pumpReceive -fun pump(block: Boolean): MessageTransfer?

      Delivers a single message from the internal queue. If there are no messages waiting to be delivered and block +fun pumpReceive(block: Boolean): MessageTransfer?

      Delivers a single message from the internal queue. If there are no messages waiting to be delivered and block is true, waits until one has been provided on a different thread via send. If block is false, the return result indicates whether a message was delivered or not.

      diff --git a/docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/-in-memory-messaging/pump-receive.html b/docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/-in-memory-messaging/pump-receive.html new file mode 100644 index 0000000000..3aa0d40c12 --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/-in-memory-messaging/pump-receive.html @@ -0,0 +1,20 @@ + + +InMemoryMessagingNetwork.InMemoryMessaging.pumpReceive - + + + +com.r3corda.node.services.network / InMemoryMessagingNetwork / InMemoryMessaging / pumpReceive
      +
      +

      pumpReceive

      + +fun pumpReceive(block: Boolean): MessageTransfer?
      +

      Delivers a single message from the internal queue. If there are no messages waiting to be delivered and block +is true, waits until one has been provided on a different thread via send. If block is false, the return +result indicates whether a message was delivered or not.

      +

      Return
      +the message that was processed, if any in this round.

      +
      +
      + + diff --git a/docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/-init-.html b/docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/-init-.html index 9080279a32..1c07d02f7b 100644 --- a/docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/-init-.html +++ b/docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/-init-.html @@ -7,7 +7,7 @@ com.r3corda.node.services.network / InMemoryMessagingNetwork / <init>

      <init>

      -InMemoryMessagingNetwork()
      +InMemoryMessagingNetwork(sendManuallyPumped: Boolean)

      An in-memory network allows you to manufacture InMemoryMessagings for a set of participants. Each InMemoryMessaging maintains a queue of messages it has received, and a background thread that dispatches messages one by one to registered handlers. Alternatively, a messaging system may be manually pumped, in which diff --git a/docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/create-node.html b/docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/create-node.html index 31503d5272..5e1cd3199b 100644 --- a/docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/create-node.html +++ b/docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/create-node.html @@ -11,7 +11,7 @@ fun createNode(manuallyPumped: Boolean): <ERROR CLASS><Handle, MessagingServiceBuilder<InMemoryMessaging>>

      Creates a node and returns the new object that identifies its location on the network to senders, and the InMemoryMessaging that the recipient/in-memory node uses to receive messages and send messages itself.

      -

      If manuallyPumped is set to true, then you are expected to call the InMemoryMessaging.pump method on the InMemoryMessaging +

      If manuallyPumped is set to true, then you are expected to call the InMemoryMessaging.pump method on the InMemoryMessaging in order to cause the delivery of a single message, which will occur on the thread of the caller. If set to false then this class will set up a background thread to deliver messages asynchronously, if the handler specifies no executor.

      diff --git a/docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/index.html b/docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/index.html index d451ad1feb..63d05087ed 100644 --- a/docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/index.html +++ b/docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/index.html @@ -60,7 +60,7 @@ when all entities on the network are being simulated in-process.

      <init> -InMemoryMessagingNetwork()

      An in-memory network allows you to manufacture InMemoryMessagings for a set of participants. Each +InMemoryMessagingNetwork(sendManuallyPumped: Boolean)

      An in-memory network allows you to manufacture InMemoryMessagings for a set of participants. Each InMemoryMessaging maintains a queue of messages it has received, and a background thread that dispatches messages one by one to registered handlers. Alternatively, a messaging system may be manually pumped, in which case no thread is created and a caller is expected to force delivery one at a time (this is useful for unit @@ -74,13 +74,6 @@ testing).

      -allMessages - -val allMessages: <ERROR CLASS><MessageTransfer>

      A stream of (sender, message, recipients) triples

      - - - - endpoints val endpoints: List<InMemoryMessaging> @@ -98,6 +91,26 @@ testing).

      var latencyCalculator: LatencyCalculator?

      This can be set to an object which can inject artificial latency between sender/recipient pairs.

      + + +receivedMessages + +val receivedMessages: <ERROR CLASS><MessageTransfer>

      A stream of (sender, message, recipients) triples

      + + + + +sendManuallyPumped + +val sendManuallyPumped: Boolean + + + +sentMessages + +val sentMessages: <ERROR CLASS><MessageTransfer>

      A stream of (sender, message, recipients) triples

      + +

      Functions

      @@ -120,6 +133,18 @@ testing).

      +pumpSend + +fun pumpSend(block: Boolean): MessageTransfer? + + + +pumpSendInternal + +fun pumpSendInternal(transfer: MessageTransfer): Unit + + + stop fun stop(): Unit diff --git a/docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/pump-send-internal.html b/docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/pump-send-internal.html new file mode 100644 index 0000000000..242283b31f --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/pump-send-internal.html @@ -0,0 +1,15 @@ + + +InMemoryMessagingNetwork.pumpSendInternal - + + + +com.r3corda.node.services.network / InMemoryMessagingNetwork / pumpSendInternal
      +
      +

      pumpSendInternal

      + +fun pumpSendInternal(transfer: MessageTransfer): Unit
      +
      +
      + + diff --git a/docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/pump-send.html b/docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/pump-send.html new file mode 100644 index 0000000000..441973d30c --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/pump-send.html @@ -0,0 +1,15 @@ + + +InMemoryMessagingNetwork.pumpSend - + + + +com.r3corda.node.services.network / InMemoryMessagingNetwork / pumpSend
      +
      +

      pumpSend

      + +fun pumpSend(block: Boolean): MessageTransfer?
      +
      +
      + + diff --git a/docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/received-messages.html b/docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/received-messages.html new file mode 100644 index 0000000000..ae8c94184d --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/received-messages.html @@ -0,0 +1,16 @@ + + +InMemoryMessagingNetwork.receivedMessages - + + + +com.r3corda.node.services.network / InMemoryMessagingNetwork / receivedMessages
      +
      +

      receivedMessages

      + +val receivedMessages: <ERROR CLASS><MessageTransfer>
      +

      A stream of (sender, message, recipients) triples

      +
      +
      + + diff --git a/docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/send-manually-pumped.html b/docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/send-manually-pumped.html new file mode 100644 index 0000000000..de38c759b9 --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/send-manually-pumped.html @@ -0,0 +1,15 @@ + + +InMemoryMessagingNetwork.sendManuallyPumped - + + + +com.r3corda.node.services.network / InMemoryMessagingNetwork / sendManuallyPumped
      +
      +

      sendManuallyPumped

      + +val sendManuallyPumped: Boolean
      +
      +
      + + diff --git a/docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/sent-messages.html b/docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/sent-messages.html new file mode 100644 index 0000000000..ebeec4eb72 --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.services.network/-in-memory-messaging-network/sent-messages.html @@ -0,0 +1,16 @@ + + +InMemoryMessagingNetwork.sentMessages - + + + +com.r3corda.node.services.network / InMemoryMessagingNetwork / sentMessages
      +
      +

      sentMessages

      + +val sentMessages: <ERROR CLASS><MessageTransfer>
      +

      A stream of (sender, message, recipients) triples

      +
      +
      + + diff --git a/docs/build/html/api/com.r3corda.node.services.network/-in-memory-network-map-cache/network-map-nodes.html b/docs/build/html/api/com.r3corda.node.services.network/-in-memory-network-map-cache/network-map-nodes.html index c6e118a45f..21c1b4004a 100644 --- a/docs/build/html/api/com.r3corda.node.services.network/-in-memory-network-map-cache/network-map-nodes.html +++ b/docs/build/html/api/com.r3corda.node.services.network/-in-memory-network-map-cache/network-map-nodes.html @@ -11,9 +11,9 @@ open val networkMapNodes: List<NodeInfo>
      Overrides NetworkMapCache.networkMapNodes

      A list of nodes that advertise a network map service

      -Getter
      +

      Getter

      A list of nodes that advertise a network map service

      -
      +



      diff --git a/docs/build/html/api/com.r3corda.node.services.network/-in-memory-network-map-cache/notary-nodes.html b/docs/build/html/api/com.r3corda.node.services.network/-in-memory-network-map-cache/notary-nodes.html index bc2ce2c8e5..70690525bf 100644 --- a/docs/build/html/api/com.r3corda.node.services.network/-in-memory-network-map-cache/notary-nodes.html +++ b/docs/build/html/api/com.r3corda.node.services.network/-in-memory-network-map-cache/notary-nodes.html @@ -11,9 +11,9 @@ open val notaryNodes: List<NodeInfo>
      Overrides NetworkMapCache.notaryNodes

      A list of nodes that advertise a notary service

      -Getter
      +

      Getter

      A list of nodes that advertise a notary service

      -
      +



      diff --git a/docs/build/html/api/com.r3corda.node.services.network/-in-memory-network-map-cache/party-nodes.html b/docs/build/html/api/com.r3corda.node.services.network/-in-memory-network-map-cache/party-nodes.html index 7e39ee7068..6554afa1c7 100644 --- a/docs/build/html/api/com.r3corda.node.services.network/-in-memory-network-map-cache/party-nodes.html +++ b/docs/build/html/api/com.r3corda.node.services.network/-in-memory-network-map-cache/party-nodes.html @@ -11,9 +11,9 @@ open val partyNodes: List<NodeInfo>
      Overrides NetworkMapCache.partyNodes

      A list of all nodes the cache is aware of

      -Getter
      +

      Getter

      A list of all nodes the cache is aware of

      -
      +



      diff --git a/docs/build/html/api/com.r3corda.node.services.network/-in-memory-network-map-cache/rates-oracle-nodes.html b/docs/build/html/api/com.r3corda.node.services.network/-in-memory-network-map-cache/rates-oracle-nodes.html index 0646984d3b..a1508ff82f 100644 --- a/docs/build/html/api/com.r3corda.node.services.network/-in-memory-network-map-cache/rates-oracle-nodes.html +++ b/docs/build/html/api/com.r3corda.node.services.network/-in-memory-network-map-cache/rates-oracle-nodes.html @@ -11,9 +11,9 @@ open val ratesOracleNodes: List<NodeInfo>
      Overrides NetworkMapCache.ratesOracleNodes

      A list of nodes that advertise a rates oracle service

      -Getter
      +

      Getter

      A list of nodes that advertise a rates oracle service

      -
      +



      diff --git a/docs/build/html/api/com.r3corda.node.services.network/-in-memory-network-map-cache/regulators.html b/docs/build/html/api/com.r3corda.node.services.network/-in-memory-network-map-cache/regulators.html index 6fc21fa0be..69859b6a8f 100644 --- a/docs/build/html/api/com.r3corda.node.services.network/-in-memory-network-map-cache/regulators.html +++ b/docs/build/html/api/com.r3corda.node.services.network/-in-memory-network-map-cache/regulators.html @@ -13,11 +13,11 @@ Overrides val net: MessagingService + + +networkMapCache + +val networkMapCache: NetworkMapCache +

      Functions

      @@ -118,10 +124,12 @@ addMessageHandler -fun <Q : AbstractRequestMessage, R : Any> addMessageHandler(topic: String, handler: (Q) -> R, exceptionConsumer: (Message, Exception) -> Unit): Unit

      Register a handler for a message topic. In comparison to using net.addMessageHandler() this manages a lot of -common boilerplate code. Exceptions are caught and passed to the provided consumer.

      -fun <Q : AbstractRequestMessage, R : Any> addMessageHandler(topic: String, handler: (Q) -> R): Unit

      Register a handler for a message topic. In comparison to using net.addMessageHandler() this manages a lot of -common boilerplate code. Exceptions are propagated to the messaging layer.

      +fun <Q : ServiceRequestMessage, R : Any> addMessageHandler(topic: String, handler: (Q) -> R, exceptionConsumer: (Message, Exception) -> Unit): Unit

      Register a handler for a message topic. In comparison to using net.addMessageHandler() this manages a lot of +common boilerplate code. Exceptions are caught and passed to the provided consumer. If you just want a simple +acknowledgement response with no content, use com.r3corda.core.messaging.Ack

      +fun <Q : ServiceRequestMessage, R : Any> addMessageHandler(topic: String, handler: (Q) -> R): Unit

      Register a handler for a message topic. In comparison to using net.addMessageHandler() this manages a lot of +common boilerplate code. Exceptions are propagated to the messaging layer. If you just want a simple +acknowledgement response with no content, use com.r3corda.core.messaging.Ack

      diff --git a/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-fetch-map-request/index.html b/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-fetch-map-request/index.html index 95a08a61a2..c7a0dc1064 100644 --- a/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-fetch-map-request/index.html +++ b/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-fetch-map-request/index.html @@ -7,7 +7,7 @@ com.r3corda.node.services.network / NetworkMapService / FetchMapRequest

      FetchMapRequest

      -class FetchMapRequest : AbstractRequestMessage
      +class FetchMapRequest : NetworkMapRequestMessage


      Constructors

      @@ -32,6 +32,12 @@ +sessionID + +val sessionID: Long + + + subscribe val subscribe: Boolean @@ -43,15 +49,20 @@ -replyTo +replyTo val replyTo: MessageRecipients + + +

      Inherited Functions

      + + +getReplyTo +open fun getReplyTo(networkMapCache: NetworkMapCache): MessageRecipients
      -sessionID -val sessionID: Long?
      diff --git a/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-fetch-map-request/session-i-d.html b/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-fetch-map-request/session-i-d.html new file mode 100644 index 0000000000..54a0829282 --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-fetch-map-request/session-i-d.html @@ -0,0 +1,16 @@ + + +NetworkMapService.FetchMapRequest.sessionID - + + + +com.r3corda.node.services.network / NetworkMapService / FetchMapRequest / sessionID
      +
      +

      sessionID

      + +val sessionID: Long
      +Overrides ServiceRequestMessage.sessionID
      +
      +
      + + diff --git a/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-network-map-request-message/-init-.html b/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-network-map-request-message/-init-.html new file mode 100644 index 0000000000..4bdb9b47d8 --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-network-map-request-message/-init-.html @@ -0,0 +1,14 @@ + + +NetworkMapService.NetworkMapRequestMessage.<init> - + + + +com.r3corda.node.services.network / NetworkMapService / NetworkMapRequestMessage / <init>
      +
      +

      <init>

      +NetworkMapRequestMessage(replyTo: MessageRecipients)
      +
      +
      + + diff --git a/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-network-map-request-message/get-reply-to.html b/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-network-map-request-message/get-reply-to.html new file mode 100644 index 0000000000..411c03272e --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-network-map-request-message/get-reply-to.html @@ -0,0 +1,16 @@ + + +NetworkMapService.NetworkMapRequestMessage.getReplyTo - + + + +com.r3corda.node.services.network / NetworkMapService / NetworkMapRequestMessage / getReplyTo
      +
      +

      getReplyTo

      + +open fun getReplyTo(networkMapCache: NetworkMapCache): MessageRecipients
      +Overrides ServiceRequestMessage.getReplyTo
      +
      +
      + + diff --git a/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-network-map-request-message/index.html b/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-network-map-request-message/index.html new file mode 100644 index 0000000000..fa98395ee8 --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-network-map-request-message/index.html @@ -0,0 +1,87 @@ + + +NetworkMapService.NetworkMapRequestMessage - + + + +com.r3corda.node.services.network / NetworkMapService / NetworkMapRequestMessage
      +
      +

      NetworkMapRequestMessage

      +abstract class NetworkMapRequestMessage : ServiceRequestMessage
      +
      +
      +

      Constructors

      + + + + + + + +
      +<init> +NetworkMapRequestMessage(replyTo: MessageRecipients)
      +

      Properties

      + + + + + + + +
      +replyTo +val replyTo: MessageRecipients
      +

      Inherited Properties

      + + + + + + + +
      +sessionID +abstract val sessionID: Long
      +

      Functions

      + + + + + + + +
      +getReplyTo +open fun getReplyTo(networkMapCache: NetworkMapCache): MessageRecipients
      +

      Inheritors

      + + + + + + + + + + + + + + + + + + + +
      +FetchMapRequest +class FetchMapRequest : NetworkMapRequestMessage
      +QueryIdentityRequest +class QueryIdentityRequest : NetworkMapRequestMessage
      +RegistrationRequest +class RegistrationRequest : NetworkMapRequestMessage
      +SubscribeRequest +class SubscribeRequest : NetworkMapRequestMessage
      + + diff --git a/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-network-map-request-message/reply-to.html b/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-network-map-request-message/reply-to.html new file mode 100644 index 0000000000..8d20583bc8 --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-network-map-request-message/reply-to.html @@ -0,0 +1,15 @@ + + +NetworkMapService.NetworkMapRequestMessage.replyTo - + + + +com.r3corda.node.services.network / NetworkMapService / NetworkMapRequestMessage / replyTo
      +
      +

      replyTo

      + +val replyTo: MessageRecipients
      +
      +
      + + diff --git a/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-query-identity-request/index.html b/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-query-identity-request/index.html index 36df720f8b..f900946b0f 100644 --- a/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-query-identity-request/index.html +++ b/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-query-identity-request/index.html @@ -7,7 +7,7 @@ com.r3corda.node.services.network / NetworkMapService / QueryIdentityRequest

      QueryIdentityRequest

      -class QueryIdentityRequest : AbstractRequestMessage
      +class QueryIdentityRequest : NetworkMapRequestMessage


      Constructors

      @@ -30,6 +30,12 @@ val identity: Party + + +sessionID + +val sessionID: Long +

      Inherited Properties

      @@ -37,15 +43,20 @@ -replyTo +replyTo val replyTo: MessageRecipients + + +

      Inherited Functions

      + + +getReplyTo +open fun getReplyTo(networkMapCache: NetworkMapCache): MessageRecipients
      -sessionID -val sessionID: Long?
      diff --git a/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-query-identity-request/session-i-d.html b/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-query-identity-request/session-i-d.html new file mode 100644 index 0000000000..76256205ae --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-query-identity-request/session-i-d.html @@ -0,0 +1,16 @@ + + +NetworkMapService.QueryIdentityRequest.sessionID - + + + +com.r3corda.node.services.network / NetworkMapService / QueryIdentityRequest / sessionID
      +
      +

      sessionID

      + +val sessionID: Long
      +Overrides ServiceRequestMessage.sessionID
      +
      +
      + + diff --git a/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-registration-request/index.html b/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-registration-request/index.html index 5edbe99a3b..e4cfb86148 100644 --- a/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-registration-request/index.html +++ b/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-registration-request/index.html @@ -7,7 +7,7 @@ com.r3corda.node.services.network / NetworkMapService / RegistrationRequest

      RegistrationRequest

      -class RegistrationRequest : AbstractRequestMessage
      +class RegistrationRequest : NetworkMapRequestMessage


      Constructors

      @@ -26,6 +26,12 @@ +sessionID + +val sessionID: Long + + + wireReg val wireReg: WireNodeRegistration @@ -37,15 +43,20 @@ -replyTo +replyTo val replyTo: MessageRecipients + + +

      Inherited Functions

      + + +getReplyTo +open fun getReplyTo(networkMapCache: NetworkMapCache): MessageRecipients
      -sessionID -val sessionID: Long?
      diff --git a/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-registration-request/session-i-d.html b/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-registration-request/session-i-d.html new file mode 100644 index 0000000000..4590026b2c --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-registration-request/session-i-d.html @@ -0,0 +1,16 @@ + + +NetworkMapService.RegistrationRequest.sessionID - + + + +com.r3corda.node.services.network / NetworkMapService / RegistrationRequest / sessionID
      +
      +

      sessionID

      + +val sessionID: Long
      +Overrides ServiceRequestMessage.sessionID
      +
      +
      + + diff --git a/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-subscribe-request/index.html b/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-subscribe-request/index.html index 285562de31..7a60bdd25e 100644 --- a/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-subscribe-request/index.html +++ b/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-subscribe-request/index.html @@ -7,7 +7,7 @@ com.r3corda.node.services.network / NetworkMapService / SubscribeRequest

      SubscribeRequest

      -class SubscribeRequest : AbstractRequestMessage
      +class SubscribeRequest : NetworkMapRequestMessage


      Constructors

      @@ -26,6 +26,12 @@ +sessionID + +val sessionID: Long + + + subscribe val subscribe: Boolean @@ -37,15 +43,20 @@ -replyTo +replyTo val replyTo: MessageRecipients + + +

      Inherited Functions

      + + +getReplyTo +open fun getReplyTo(networkMapCache: NetworkMapCache): MessageRecipients
      -sessionID -val sessionID: Long?
      diff --git a/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-subscribe-request/session-i-d.html b/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-subscribe-request/session-i-d.html new file mode 100644 index 0000000000..b92dabcc49 --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/-subscribe-request/session-i-d.html @@ -0,0 +1,16 @@ + + +NetworkMapService.SubscribeRequest.sessionID - + + + +com.r3corda.node.services.network / NetworkMapService / SubscribeRequest / sessionID
      +
      +

      sessionID

      + +val sessionID: Long
      +Overrides ServiceRequestMessage.sessionID
      +
      +
      + + diff --git a/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/index.html b/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/index.html index 35a0077a22..3b56656b12 100644 --- a/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/index.html +++ b/docs/build/html/api/com.r3corda.node.services.network/-network-map-service/index.html @@ -21,7 +21,7 @@ replace each other based on a serial number present in the change.

      FetchMapRequest -class FetchMapRequest : AbstractRequestMessage +class FetchMapRequest : NetworkMapRequestMessage @@ -31,9 +31,15 @@ replace each other based on a serial number present in the change.

      +NetworkMapRequestMessage + +abstract class NetworkMapRequestMessage : ServiceRequestMessage + + + QueryIdentityRequest -class QueryIdentityRequest : AbstractRequestMessage +class QueryIdentityRequest : NetworkMapRequestMessage @@ -45,7 +51,7 @@ replace each other based on a serial number present in the change.

      RegistrationRequest -class RegistrationRequest : AbstractRequestMessage +class RegistrationRequest : NetworkMapRequestMessage @@ -57,7 +63,7 @@ replace each other based on a serial number present in the change.

      SubscribeRequest -class SubscribeRequest : AbstractRequestMessage +class SubscribeRequest : NetworkMapRequestMessage diff --git a/docs/build/html/api/com.r3corda.node.services.persistence/-data-vending-service/-init-.html b/docs/build/html/api/com.r3corda.node.services.persistence/-data-vending-service/-init-.html index 14768621ce..dbc2cfb1ba 100644 --- a/docs/build/html/api/com.r3corda.node.services.persistence/-data-vending-service/-init-.html +++ b/docs/build/html/api/com.r3corda.node.services.persistence/-data-vending-service/-init-.html @@ -7,7 +7,7 @@ com.r3corda.node.services.persistence / DataVendingService / <init>

      <init>

      -DataVendingService(net: MessagingService, storage: StorageService)
      +DataVendingService(net: MessagingService, storage: StorageService, networkMapCache: NetworkMapCache)

      This class sets up network message handlers for requests from peers for data keyed by hash. It is a piece of simple glue that sits between the network layer and the database layer.

      Note that in our data model, to be able to name a thing by hash automatically gives the power to request it. There diff --git a/docs/build/html/api/com.r3corda.node.services.persistence/-data-vending-service/index.html b/docs/build/html/api/com.r3corda.node.services.persistence/-data-vending-service/index.html index c2a6754647..c7a041f938 100644 --- a/docs/build/html/api/com.r3corda.node.services.persistence/-data-vending-service/index.html +++ b/docs/build/html/api/com.r3corda.node.services.persistence/-data-vending-service/index.html @@ -27,7 +27,7 @@ such the hash of a piece of data can be seen as a type of password allowing acce <init> -DataVendingService(net: MessagingService, storage: StorageService)

      This class sets up network message handlers for requests from peers for data keyed by hash. It is a piece of simple +DataVendingService(net: MessagingService, storage: StorageService, networkMapCache: NetworkMapCache)

      This class sets up network message handlers for requests from peers for data keyed by hash. It is a piece of simple glue that sits between the network layer and the database layer.

      @@ -42,6 +42,12 @@ glue that sits between the network layer and the database layer.

      val net: MessagingService + + +networkMapCache + +val networkMapCache: NetworkMapCache +

      Inherited Functions

      @@ -51,10 +57,12 @@ glue that sits between the network layer and the database layer.

      addMessageHandler -fun <Q : AbstractRequestMessage, R : Any> addMessageHandler(topic: String, handler: (Q) -> R, exceptionConsumer: (Message, Exception) -> Unit): Unit

      Register a handler for a message topic. In comparison to using net.addMessageHandler() this manages a lot of -common boilerplate code. Exceptions are caught and passed to the provided consumer.

      -fun <Q : AbstractRequestMessage, R : Any> addMessageHandler(topic: String, handler: (Q) -> R): Unit

      Register a handler for a message topic. In comparison to using net.addMessageHandler() this manages a lot of -common boilerplate code. Exceptions are propagated to the messaging layer.

      +fun <Q : ServiceRequestMessage, R : Any> addMessageHandler(topic: String, handler: (Q) -> R, exceptionConsumer: (Message, Exception) -> Unit): Unit

      Register a handler for a message topic. In comparison to using net.addMessageHandler() this manages a lot of +common boilerplate code. Exceptions are caught and passed to the provided consumer. If you just want a simple +acknowledgement response with no content, use com.r3corda.core.messaging.Ack

      +fun <Q : ServiceRequestMessage, R : Any> addMessageHandler(topic: String, handler: (Q) -> R): Unit

      Register a handler for a message topic. In comparison to using net.addMessageHandler() this manages a lot of +common boilerplate code. Exceptions are propagated to the messaging layer. If you just want a simple +acknowledgement response with no content, use com.r3corda.core.messaging.Ack

      diff --git a/docs/build/html/api/com.r3corda.node.services.persistence/-node-attachment-service/index.html b/docs/build/html/api/com.r3corda.node.services.persistence/-node-attachment-service/index.html index 238789d363..cd7b09ca62 100644 --- a/docs/build/html/api/com.r3corda.node.services.persistence/-node-attachment-service/index.html +++ b/docs/build/html/api/com.r3corda.node.services.persistence/-node-attachment-service/index.html @@ -95,10 +95,8 @@ operation due to the need to copy the bytes to disk and hash them along the way. openAttachment -fun openAttachment(id: SecureHash): Attachment?

      Returns a newly opened stream for the given locally stored attachment, or null if no such attachment is known. -The returned stream must be closed when you are done with it to avoid resource leaks. You should probably wrap -the result in a JarInputStream unless youre sending it somewhere, there is a convenience helper for this -on Attachment.

      +fun openAttachment(id: SecureHash): Attachment?

      Returns a handle to a locally stored attachment, or null if its not known. The handle can be used to open +a stream for the data, which will be a zip/jar file.

      diff --git a/docs/build/html/api/com.r3corda.node.services.persistence/-node-attachment-service/open-attachment.html b/docs/build/html/api/com.r3corda.node.services.persistence/-node-attachment-service/open-attachment.html index 9e304ff5b7..dd8f8d3880 100644 --- a/docs/build/html/api/com.r3corda.node.services.persistence/-node-attachment-service/open-attachment.html +++ b/docs/build/html/api/com.r3corda.node.services.persistence/-node-attachment-service/open-attachment.html @@ -10,10 +10,8 @@ fun openAttachment(id: SecureHash): Attachment?
      Overrides AttachmentStorage.openAttachment
      -

      Returns a newly opened stream for the given locally stored attachment, or null if no such attachment is known. -The returned stream must be closed when you are done with it to avoid resource leaks. You should probably wrap -the result in a JarInputStream unless youre sending it somewhere, there is a convenience helper for this -on Attachment.

      +

      Returns a handle to a locally stored attachment, or null if its not known. The handle can be used to open +a stream for the data, which will be a zip/jar file.



      diff --git a/docs/build/html/api/com.r3corda.node.services.persistence/-per-file-checkpoint-storage/checkpoints.html b/docs/build/html/api/com.r3corda.node.services.persistence/-per-file-checkpoint-storage/checkpoints.html index 01cf8c7e90..420b79c8c3 100644 --- a/docs/build/html/api/com.r3corda.node.services.persistence/-per-file-checkpoint-storage/checkpoints.html +++ b/docs/build/html/api/com.r3corda.node.services.persistence/-per-file-checkpoint-storage/checkpoints.html @@ -13,11 +13,11 @@ Overrides fun getTransaction(id: SecureHash): SignedTransaction?
      -Overrides TransactionStorage.getTransaction
      +Overrides ReadOnlyTransactionStorage.getTransaction

      Return the transaction with the given id, or null if no such transaction exists.



      diff --git a/docs/build/html/api/com.r3corda.node.services.persistence/-storage-service-impl/index.html b/docs/build/html/api/com.r3corda.node.services.persistence/-storage-service-impl/index.html index 2e5dcd470b..dc9b90fa2f 100644 --- a/docs/build/html/api/com.r3corda.node.services.persistence/-storage-service-impl/index.html +++ b/docs/build/html/api/com.r3corda.node.services.persistence/-storage-service-impl/index.html @@ -7,7 +7,7 @@ com.r3corda.node.services.persistence / StorageServiceImpl

      StorageServiceImpl

      -open class StorageServiceImpl : SingletonSerializeAsToken, StorageService
      +open class StorageServiceImpl : SingletonSerializeAsToken, TxWritableStorageService


      Constructors

      diff --git a/docs/build/html/api/com.r3corda.node.services.persistence/-storage-service-impl/validated-transactions.html b/docs/build/html/api/com.r3corda.node.services.persistence/-storage-service-impl/validated-transactions.html index 1c6573f60b..be18831cc0 100644 --- a/docs/build/html/api/com.r3corda.node.services.persistence/-storage-service-impl/validated-transactions.html +++ b/docs/build/html/api/com.r3corda.node.services.persistence/-storage-service-impl/validated-transactions.html @@ -9,7 +9,7 @@

      validatedTransactions

      open val validatedTransactions: TransactionStorage
      -Overrides StorageService.validatedTransactions
      +Overrides TxWritableStorageService.validatedTransactions

      A map of hash->tx where tx has been signature/contract validated and the states are known to be correct. The signatures arent technically needed after that point, but we keep them around so that we can relay the transaction data to other nodes that need it.

      diff --git a/docs/build/html/api/com.r3corda.node.services.persistence/index.html b/docs/build/html/api/com.r3corda.node.services.persistence/index.html index 1416e0f9a0..4d42e3fbb3 100644 --- a/docs/build/html/api/com.r3corda.node.services.persistence/index.html +++ b/docs/build/html/api/com.r3corda.node.services.persistence/index.html @@ -43,7 +43,7 @@ glue that sits between the network layer and the database layer.

      StorageServiceImpl -open class StorageServiceImpl : SingletonSerializeAsToken, StorageService +open class StorageServiceImpl : SingletonSerializeAsToken, TxWritableStorageService diff --git a/docs/build/html/api/com.r3corda.node.services.statemachine/-protocol-state-machine-impl/index.html b/docs/build/html/api/com.r3corda.node.services.statemachine/-protocol-state-machine-impl/index.html index c1273b9b9f..bcd3721b90 100644 --- a/docs/build/html/api/com.r3corda.node.services.statemachine/-protocol-state-machine-impl/index.html +++ b/docs/build/html/api/com.r3corda.node.services.statemachine/-protocol-state-machine-impl/index.html @@ -65,12 +65,6 @@ For any given flow there is only one PSM, even if that protocol invokes subproto -prepareForResumeWith - -fun prepareForResumeWith(serviceHub: ServiceHubInternal, receivedPayload: Any?, suspendAction: (FiberRequest, ProtocolStateMachineImpl<*>) -> Unit): Unit - - - receive fun <T : Any> receive(topic: String, sessionIDForReceive: Long, recvType: Class<T>): UntrustworthyData<T> @@ -85,13 +79,13 @@ For any given flow there is only one PSM, even if that protocol invokes subproto send -fun send(topic: String, destination: MessageRecipients, sessionID: Long, obj: Any): Unit +fun send(topic: String, destination: Party, sessionID: Long, payload: Any): Unit sendAndReceive -fun <T : Any> sendAndReceive(topic: String, destination: MessageRecipients, sessionIDForSend: Long, sessionIDForReceive: Long, obj: Any, recvType: Class<T>): UntrustworthyData<T> +fun <T : Any> sendAndReceive(topic: String, destination: Party, sessionIDForSend: Long, sessionIDForReceive: Long, payload: Any, recvType: Class<T>): UntrustworthyData<T> diff --git a/docs/build/html/api/com.r3corda.node.services.statemachine/-protocol-state-machine-impl/send-and-receive.html b/docs/build/html/api/com.r3corda.node.services.statemachine/-protocol-state-machine-impl/send-and-receive.html index d5acaa5f08..878461decf 100644 --- a/docs/build/html/api/com.r3corda.node.services.statemachine/-protocol-state-machine-impl/send-and-receive.html +++ b/docs/build/html/api/com.r3corda.node.services.statemachine/-protocol-state-machine-impl/send-and-receive.html @@ -7,8 +7,8 @@ com.r3corda.node.services.statemachine / ProtocolStateMachineImpl / sendAndReceive

      sendAndReceive

      - -fun <T : Any> sendAndReceive(topic: String, destination: MessageRecipients, sessionIDForSend: Long, sessionIDForReceive: Long, obj: Any, recvType: Class<T>): UntrustworthyData<T>
      + +fun <T : Any> sendAndReceive(topic: String, destination: Party, sessionIDForSend: Long, sessionIDForReceive: Long, payload: Any, recvType: Class<T>): UntrustworthyData<T>
      Overrides ProtocolStateMachine.sendAndReceive


      diff --git a/docs/build/html/api/com.r3corda.node.services.statemachine/-protocol-state-machine-impl/send.html b/docs/build/html/api/com.r3corda.node.services.statemachine/-protocol-state-machine-impl/send.html index 495a7e71b3..26fa59ee59 100644 --- a/docs/build/html/api/com.r3corda.node.services.statemachine/-protocol-state-machine-impl/send.html +++ b/docs/build/html/api/com.r3corda.node.services.statemachine/-protocol-state-machine-impl/send.html @@ -7,8 +7,8 @@ com.r3corda.node.services.statemachine / ProtocolStateMachineImpl / send

      send

      - -fun send(topic: String, destination: MessageRecipients, sessionID: Long, obj: Any): Unit
      + +fun send(topic: String, destination: Party, sessionID: Long, payload: Any): Unit
      Overrides ProtocolStateMachine.send


      diff --git a/docs/build/html/api/com.r3corda.node.services.statemachine/-state-machine-manager/-fiber-request/-expecting-response/-init-.html b/docs/build/html/api/com.r3corda.node.services.statemachine/-state-machine-manager/-fiber-request/-expecting-response/-init-.html index d931c86eb6..c4bcd5a38b 100644 --- a/docs/build/html/api/com.r3corda.node.services.statemachine/-state-machine-manager/-fiber-request/-expecting-response/-init-.html +++ b/docs/build/html/api/com.r3corda.node.services.statemachine/-state-machine-manager/-fiber-request/-expecting-response/-init-.html @@ -7,7 +7,7 @@ com.r3corda.node.services.statemachine / StateMachineManager / FiberRequest / ExpectingResponse / <init>

      <init>

      -ExpectingResponse(topic: String, destination: MessageRecipients?, sessionIDForSend: Long, sessionIDForReceive: Long, obj: Any?, responseType: Class<R>)
      +ExpectingResponse(topic: String, destination: Party?, sessionIDForSend: Long, sessionIDForReceive: Long, obj: Any?, responseType: Class<R>)


      diff --git a/docs/build/html/api/com.r3corda.node.services.statemachine/-state-machine-manager/-fiber-request/-expecting-response/index.html b/docs/build/html/api/com.r3corda.node.services.statemachine/-state-machine-manager/-fiber-request/-expecting-response/index.html index e7770d6429..8122b575b1 100644 --- a/docs/build/html/api/com.r3corda.node.services.statemachine/-state-machine-manager/-fiber-request/-expecting-response/index.html +++ b/docs/build/html/api/com.r3corda.node.services.statemachine/-state-machine-manager/-fiber-request/-expecting-response/index.html @@ -17,7 +17,7 @@ <init> -ExpectingResponse(topic: String, destination: MessageRecipients?, sessionIDForSend: Long, sessionIDForReceive: Long, obj: Any?, responseType: Class<R>) +ExpectingResponse(topic: String, destination: Party?, sessionIDForSend: Long, sessionIDForReceive: Long, obj: Any?, responseType: Class<R>) @@ -39,7 +39,7 @@ destination -val destination: MessageRecipients? +val destination: Party? diff --git a/docs/build/html/api/com.r3corda.node.services.statemachine/-state-machine-manager/-fiber-request/-init-.html b/docs/build/html/api/com.r3corda.node.services.statemachine/-state-machine-manager/-fiber-request/-init-.html index 104b4b69b3..cb46428641 100644 --- a/docs/build/html/api/com.r3corda.node.services.statemachine/-state-machine-manager/-fiber-request/-init-.html +++ b/docs/build/html/api/com.r3corda.node.services.statemachine/-state-machine-manager/-fiber-request/-init-.html @@ -7,7 +7,7 @@ com.r3corda.node.services.statemachine / StateMachineManager / FiberRequest / <init>

      <init>

      -FiberRequest(topic: String, destination: MessageRecipients?, sessionIDForSend: Long, sessionIDForReceive: Long, payload: Any?)
      +FiberRequest(topic: String, destination: Party?, sessionIDForSend: Long, sessionIDForReceive: Long, payload: Any?)


      diff --git a/docs/build/html/api/com.r3corda.node.services.statemachine/-state-machine-manager/-fiber-request/-not-expecting-response/-init-.html b/docs/build/html/api/com.r3corda.node.services.statemachine/-state-machine-manager/-fiber-request/-not-expecting-response/-init-.html index 6d7491289f..237cecc18f 100644 --- a/docs/build/html/api/com.r3corda.node.services.statemachine/-state-machine-manager/-fiber-request/-not-expecting-response/-init-.html +++ b/docs/build/html/api/com.r3corda.node.services.statemachine/-state-machine-manager/-fiber-request/-not-expecting-response/-init-.html @@ -7,7 +7,7 @@ com.r3corda.node.services.statemachine / StateMachineManager / FiberRequest / NotExpectingResponse / <init>

      <init>

      -NotExpectingResponse(topic: String, destination: MessageRecipients, sessionIDForSend: Long, obj: Any?)
      +NotExpectingResponse(topic: String, destination: Party, sessionIDForSend: Long, obj: Any?)


      diff --git a/docs/build/html/api/com.r3corda.node.services.statemachine/-state-machine-manager/-fiber-request/-not-expecting-response/index.html b/docs/build/html/api/com.r3corda.node.services.statemachine/-state-machine-manager/-fiber-request/-not-expecting-response/index.html index 28a3d08a64..6d788ec6bd 100644 --- a/docs/build/html/api/com.r3corda.node.services.statemachine/-state-machine-manager/-fiber-request/-not-expecting-response/index.html +++ b/docs/build/html/api/com.r3corda.node.services.statemachine/-state-machine-manager/-fiber-request/-not-expecting-response/index.html @@ -17,7 +17,7 @@ <init> -NotExpectingResponse(topic: String, destination: MessageRecipients, sessionIDForSend: Long, obj: Any?) +NotExpectingResponse(topic: String, destination: Party, sessionIDForSend: Long, obj: Any?) @@ -28,7 +28,7 @@ destination -val destination: MessageRecipients? +val destination: Party? diff --git a/docs/build/html/api/com.r3corda.node.services.statemachine/-state-machine-manager/-fiber-request/destination.html b/docs/build/html/api/com.r3corda.node.services.statemachine/-state-machine-manager/-fiber-request/destination.html index abc288fede..47dab798ca 100644 --- a/docs/build/html/api/com.r3corda.node.services.statemachine/-state-machine-manager/-fiber-request/destination.html +++ b/docs/build/html/api/com.r3corda.node.services.statemachine/-state-machine-manager/-fiber-request/destination.html @@ -8,7 +8,7 @@

      destination

      -val destination: MessageRecipients?
      +val destination: Party?


      diff --git a/docs/build/html/api/com.r3corda.node.services.statemachine/-state-machine-manager/-fiber-request/index.html b/docs/build/html/api/com.r3corda.node.services.statemachine/-state-machine-manager/-fiber-request/index.html index b5cc0292f1..96a93abf5d 100644 --- a/docs/build/html/api/com.r3corda.node.services.statemachine/-state-machine-manager/-fiber-request/index.html +++ b/docs/build/html/api/com.r3corda.node.services.statemachine/-state-machine-manager/-fiber-request/index.html @@ -34,7 +34,7 @@ <init> -FiberRequest(topic: String, destination: MessageRecipients?, sessionIDForSend: Long, sessionIDForReceive: Long, payload: Any?) +FiberRequest(topic: String, destination: Party?, sessionIDForSend: Long, sessionIDForReceive: Long, payload: Any?) @@ -45,7 +45,7 @@ destination -val destination: MessageRecipients? +val destination: Party? diff --git a/docs/build/html/api/com.r3corda.node.services.transactions/-in-memory-uniqueness-provider/commit.html b/docs/build/html/api/com.r3corda.node.services.transactions/-in-memory-uniqueness-provider/commit.html index c707434a89..df563e84f1 100644 --- a/docs/build/html/api/com.r3corda.node.services.transactions/-in-memory-uniqueness-provider/commit.html +++ b/docs/build/html/api/com.r3corda.node.services.transactions/-in-memory-uniqueness-provider/commit.html @@ -7,8 +7,8 @@ com.r3corda.node.services.transactions / InMemoryUniquenessProvider / commit

      commit

      - -fun commit(tx: WireTransaction, callerIdentity: Party): Unit
      + +fun commit(states: List<StateRef>, txId: SecureHash, callerIdentity: Party): Unit
      Overrides UniquenessProvider.commit

      Commits all input states of the given transaction


      diff --git a/docs/build/html/api/com.r3corda.node.services.transactions/-in-memory-uniqueness-provider/index.html b/docs/build/html/api/com.r3corda.node.services.transactions/-in-memory-uniqueness-provider/index.html index bfb7ef8a94..4760896848 100644 --- a/docs/build/html/api/com.r3corda.node.services.transactions/-in-memory-uniqueness-provider/index.html +++ b/docs/build/html/api/com.r3corda.node.services.transactions/-in-memory-uniqueness-provider/index.html @@ -30,7 +30,7 @@ commit -fun commit(tx: WireTransaction, callerIdentity: Party): Unit

      Commits all input states of the given transaction

      +fun commit(states: List<StateRef>, txId: SecureHash, callerIdentity: Party): Unit

      Commits all input states of the given transaction

      diff --git a/docs/build/html/api/com.r3corda.node.services.transactions/-notary-service/-init-.html b/docs/build/html/api/com.r3corda.node.services.transactions/-notary-service/-init-.html index d76d9bfec3..76b4d21805 100644 --- a/docs/build/html/api/com.r3corda.node.services.transactions/-notary-service/-init-.html +++ b/docs/build/html/api/com.r3corda.node.services.transactions/-notary-service/-init-.html @@ -7,7 +7,7 @@ com.r3corda.node.services.transactions / NotaryService / <init>

      <init>

      -NotaryService(smm: StateMachineManager, net: MessagingService, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider)
      +NotaryService(smm: StateMachineManager, net: MessagingService, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider, networkMapCache: NetworkMapCache)

      A Notary service acts as the final signer of a transaction ensuring two things:

      • The (optional) timestamp of the transaction is valid

      • None of the referenced input states have previously been consumed by a transaction signed by this Notary

        diff --git a/docs/build/html/api/com.r3corda.node.services.transactions/-notary-service/index.html b/docs/build/html/api/com.r3corda.node.services.transactions/-notary-service/index.html index 4fa904c814..c503fac403 100644 --- a/docs/build/html/api/com.r3corda.node.services.transactions/-notary-service/index.html +++ b/docs/build/html/api/com.r3corda.node.services.transactions/-notary-service/index.html @@ -35,7 +35,7 @@ <init> -NotaryService(smm: StateMachineManager, net: MessagingService, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider)

        A Notary service acts as the final signer of a transaction ensuring two things:

        +NotaryService(smm: StateMachineManager, net: MessagingService, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider, networkMapCache: NetworkMapCache)

        A Notary service acts as the final signer of a transaction ensuring two things:

        @@ -85,6 +85,12 @@ val net: MessagingService + + +networkMapCache + +val networkMapCache: NetworkMapCache +

        Inherited Functions

        @@ -94,10 +100,12 @@ addMessageHandler -fun <Q : AbstractRequestMessage, R : Any> addMessageHandler(topic: String, handler: (Q) -> R, exceptionConsumer: (Message, Exception) -> Unit): Unit

        Register a handler for a message topic. In comparison to using net.addMessageHandler() this manages a lot of -common boilerplate code. Exceptions are caught and passed to the provided consumer.

        -fun <Q : AbstractRequestMessage, R : Any> addMessageHandler(topic: String, handler: (Q) -> R): Unit

        Register a handler for a message topic. In comparison to using net.addMessageHandler() this manages a lot of -common boilerplate code. Exceptions are propagated to the messaging layer.

        +fun <Q : ServiceRequestMessage, R : Any> addMessageHandler(topic: String, handler: (Q) -> R, exceptionConsumer: (Message, Exception) -> Unit): Unit

        Register a handler for a message topic. In comparison to using net.addMessageHandler() this manages a lot of +common boilerplate code. Exceptions are caught and passed to the provided consumer. If you just want a simple +acknowledgement response with no content, use com.r3corda.core.messaging.Ack

        +fun <Q : ServiceRequestMessage, R : Any> addMessageHandler(topic: String, handler: (Q) -> R): Unit

        Register a handler for a message topic. In comparison to using net.addMessageHandler() this manages a lot of +common boilerplate code. Exceptions are propagated to the messaging layer. If you just want a simple +acknowledgement response with no content, use com.r3corda.core.messaging.Ack

        diff --git a/docs/build/html/api/com.r3corda.node.services.transactions/-simple-notary-service/-init-.html b/docs/build/html/api/com.r3corda.node.services.transactions/-simple-notary-service/-init-.html index 8b85c702a6..8442cab8f1 100644 --- a/docs/build/html/api/com.r3corda.node.services.transactions/-simple-notary-service/-init-.html +++ b/docs/build/html/api/com.r3corda.node.services.transactions/-simple-notary-service/-init-.html @@ -7,7 +7,7 @@ com.r3corda.node.services.transactions / SimpleNotaryService / <init>

        <init>

        -SimpleNotaryService(smm: StateMachineManager, net: MessagingService, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider)
        +SimpleNotaryService(smm: StateMachineManager, net: MessagingService, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider, networkMapCache: NetworkMapCache)

        A simple Notary service that does not perform transaction validation



        diff --git a/docs/build/html/api/com.r3corda.node.services.transactions/-simple-notary-service/index.html b/docs/build/html/api/com.r3corda.node.services.transactions/-simple-notary-service/index.html index 9fe6c8c00d..e17b6a7620 100644 --- a/docs/build/html/api/com.r3corda.node.services.transactions/-simple-notary-service/index.html +++ b/docs/build/html/api/com.r3corda.node.services.transactions/-simple-notary-service/index.html @@ -29,7 +29,7 @@ <init> -SimpleNotaryService(smm: StateMachineManager, net: MessagingService, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider)

        A simple Notary service that does not perform transaction validation

        +SimpleNotaryService(smm: StateMachineManager, net: MessagingService, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider, networkMapCache: NetworkMapCache)

        A simple Notary service that does not perform transaction validation

        diff --git a/docs/build/html/api/com.r3corda.node.services.transactions/-validating-notary-service/-init-.html b/docs/build/html/api/com.r3corda.node.services.transactions/-validating-notary-service/-init-.html index 4721976041..e100b881f7 100644 --- a/docs/build/html/api/com.r3corda.node.services.transactions/-validating-notary-service/-init-.html +++ b/docs/build/html/api/com.r3corda.node.services.transactions/-validating-notary-service/-init-.html @@ -7,7 +7,7 @@ com.r3corda.node.services.transactions / ValidatingNotaryService / <init>

        <init>

        -ValidatingNotaryService(smm: StateMachineManager, net: MessagingService, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider)
        +ValidatingNotaryService(smm: StateMachineManager, net: MessagingService, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider, networkMapCache: NetworkMapCache)

        A Notary service that validates the transaction chain of he submitted transaction before committing it



        diff --git a/docs/build/html/api/com.r3corda.node.services.transactions/-validating-notary-service/index.html b/docs/build/html/api/com.r3corda.node.services.transactions/-validating-notary-service/index.html index c5d5b27f0c..dff848d12d 100644 --- a/docs/build/html/api/com.r3corda.node.services.transactions/-validating-notary-service/index.html +++ b/docs/build/html/api/com.r3corda.node.services.transactions/-validating-notary-service/index.html @@ -29,7 +29,7 @@ <init> -ValidatingNotaryService(smm: StateMachineManager, net: MessagingService, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider)

        A Notary service that validates the transaction chain of he submitted transaction before committing it

        +ValidatingNotaryService(smm: StateMachineManager, net: MessagingService, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider, networkMapCache: NetworkMapCache)

        A Notary service that validates the transaction chain of he submitted transaction before committing it

        diff --git a/docs/build/html/api/com.r3corda.node.services.wallet/-node-wallet-service/-init-.html b/docs/build/html/api/com.r3corda.node.services.wallet/-node-wallet-service/-init-.html index 57e3cdbb98..7341e27fb8 100644 --- a/docs/build/html/api/com.r3corda.node.services.wallet/-node-wallet-service/-init-.html +++ b/docs/build/html/api/com.r3corda.node.services.wallet/-node-wallet-service/-init-.html @@ -7,10 +7,9 @@ com.r3corda.node.services.wallet / NodeWalletService / <init>

        <init>

        -NodeWalletService(services: ServiceHubInternal)
        -

        This class implements a simple, in memory wallet that tracks states that are owned by us, and also has a convenience -method to auto-generate some self-issued cash states that can be used for test trading. A real wallet would persist -states relevant to us into a database and once such a wallet is implemented, this scaffolding can be removed.

        +NodeWalletService(services: ServiceHub)
        +

        Currently, the node wallet service is just the in-memory wallet service until we have finished evaluating and +selecting a persistence layer (probably an ORM over a SQL DB).



        diff --git a/docs/build/html/api/com.r3corda.node.services.wallet/-node-wallet-service/index.html b/docs/build/html/api/com.r3corda.node.services.wallet/-node-wallet-service/index.html index 3529cbe2c0..13e89e1df5 100644 --- a/docs/build/html/api/com.r3corda.node.services.wallet/-node-wallet-service/index.html +++ b/docs/build/html/api/com.r3corda.node.services.wallet/-node-wallet-service/index.html @@ -7,10 +7,9 @@ com.r3corda.node.services.wallet / NodeWalletService

        NodeWalletService

        -class NodeWalletService : SingletonSerializeAsToken, WalletService
        -

        This class implements a simple, in memory wallet that tracks states that are owned by us, and also has a convenience -method to auto-generate some self-issued cash states that can be used for test trading. A real wallet would persist -states relevant to us into a database and once such a wallet is implemented, this scaffolding can be removed.

        +class NodeWalletService : InMemoryWalletService
        +

        Currently, the node wallet service is just the in-memory wallet service until we have finished evaluating and +selecting a persistence layer (probably an ORM over a SQL DB).



        Constructors

        @@ -20,91 +19,51 @@ states relevant to us into a database and once such a wallet is implemented, thi <init> -NodeWalletService(services: ServiceHubInternal)

        This class implements a simple, in memory wallet that tracks states that are owned by us, and also has a convenience -method to auto-generate some self-issued cash states that can be used for test trading. A real wallet would persist -states relevant to us into a database and once such a wallet is implemented, this scaffolding can be removed.

        +NodeWalletService(services: ServiceHub)

        Currently, the node wallet service is just the in-memory wallet service until we have finished evaluating and +selecting a persistence layer (probably an ORM over a SQL DB).

        -

        Properties

        +

        Inherited Properties

        +currentWallet - - - - +linearHeads +updates
        -cashBalances -val cashBalances: Map<Currency, Amount<Currency>>

        Returns a snapshot of how much cash we have in each currency, ignoring details like issuer. Note: currencies for -which we have no cash evaluate to null, not 0.

        -
        -currentWallet -val currentWallet: Wallet

        Returns a read-only snapshot of the wallet at the time the call is made. Note that if you consume states or +open val currentWallet: Wallet

        Returns a read-only snapshot of the wallet at the time the call is made. Note that if you consume states or keys in this wallet, you must inform the wallet service so it can update its internal state.

        -linearHeads -val linearHeads: Map<SecureHash, StateAndRef<LinearState>>

        Returns a snapshot of the heads of LinearStates

        +open val linearHeads: Map<SecureHash, StateAndRef<LinearState>>

        Returns a snapshot of the heads of LinearStates

        -updates -val updates: <ERROR CLASS><Update>

        Get a synchronous Observable of updates. When observations are pushed to the Observer, the Wallet will already incorporate +open val updates: <ERROR CLASS><Update>

        Get a synchronous Observable of updates. When observations are pushed to the Observer, the Wallet will already incorporate the update.

        -

        Functions

        - - - - - - - -
        -notifyAll -fun notifyAll(txns: Iterable<WireTransaction>): Wallet

        Possibly update the wallet by marking as spent states that these transactions consume, and adding any relevant -new states that they create. You should only insert transactions that have been successfully verified here

        -

        Inherited Functions

        +notifyAll - - - - - - - - - - - -
        -linearHeadsOfType_ -open fun <T : LinearState> linearHeadsOfType_(stateType: Class<T>): Map<SecureHash, StateAndRef<T>>

        Returns the linearHeads only when the type of the state would be considered an instanceof the given type.

        +open fun notifyAll(txns: Iterable<WireTransaction>): Wallet

        Possibly update the wallet by marking as spent states that these transactions consume, and adding any relevant +new states that they create. You should only insert transactions that have been successfully verified here

        -notify -open fun notify(tx: WireTransaction): Wallet

        Same as notifyAll but with a single transaction.

        -
        -statesForRefs -open fun statesForRefs(refs: List<StateRef>): Map<StateRef, ContractState?>
        -toToken -open fun toToken(context: SerializeAsTokenContext): SerializationToken

        Extension Functions

        diff --git a/docs/build/html/api/com.r3corda.node.services.wallet/index.html b/docs/build/html/api/com.r3corda.node.services.wallet/index.html index ffa951cd2d..dddfdb0d55 100644 --- a/docs/build/html/api/com.r3corda.node.services.wallet/index.html +++ b/docs/build/html/api/com.r3corda.node.services.wallet/index.html @@ -21,19 +21,8 @@ NodeWalletService -class NodeWalletService : SingletonSerializeAsToken, WalletService

        This class implements a simple, in memory wallet that tracks states that are owned by us, and also has a convenience -method to auto-generate some self-issued cash states that can be used for test trading. A real wallet would persist -states relevant to us into a database and once such a wallet is implemented, this scaffolding can be removed.

        - - - - -WalletImpl - -class WalletImpl : Wallet

        A wallet (name may be temporary) wraps a set of states that are useful for us to keep track of, for instance, -because we own them. This class represents an immutable, stable state of a wallet: it is guaranteed not to -change out from underneath you, even though the canonical currently-best-known wallet may change as we learn -about new transactions from our peers and generate new transactions that consume states ourselves.

        +class NodeWalletService : InMemoryWalletService

        Currently, the node wallet service is just the in-memory wallet service until we have finished evaluating and +selecting a persistence layer (probably an ORM over a SQL DB).

        diff --git a/docs/build/html/api/com.r3corda.node.services/-fixing-session-initiation-handler/index.html b/docs/build/html/api/com.r3corda.node.services/-fixing-session-initiation-handler/index.html new file mode 100644 index 0000000000..5a558837e1 --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.services/-fixing-session-initiation-handler/index.html @@ -0,0 +1,30 @@ + + +FixingSessionInitiationHandler - + + + +com.r3corda.node.services / FixingSessionInitiationHandler
        +
        +

        FixingSessionInitiationHandler

        +object FixingSessionInitiationHandler
        +

        This is a temporary handler required for establishing random sessionIDs for the Fixer and Floater as part of +running scheduled fixings for the InterestRateSwap contract.

        +

        TODO: This will be replaced with the automatic sessionID / session setup work.

        +
        +
        +
        +
        +

        Functions

        + + + + + + + +
        +register +fun register(node: AbstractNode): Unit
        + + diff --git a/docs/build/html/api/com.r3corda.node.services/-fixing-session-initiation-handler/register.html b/docs/build/html/api/com.r3corda.node.services/-fixing-session-initiation-handler/register.html new file mode 100644 index 0000000000..380cbf494b --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.services/-fixing-session-initiation-handler/register.html @@ -0,0 +1,15 @@ + + +FixingSessionInitiationHandler.register - + + + +com.r3corda.node.services / FixingSessionInitiationHandler / register
        +
        +

        register

        + +fun register(node: AbstractNode): Unit
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.node.services/-notary-change-service/-init-.html b/docs/build/html/api/com.r3corda.node.services/-notary-change-service/-init-.html new file mode 100644 index 0000000000..9f2352bca7 --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.services/-notary-change-service/-init-.html @@ -0,0 +1,16 @@ + + +NotaryChangeService.<init> - + + + +com.r3corda.node.services / NotaryChangeService / <init>
        +
        +

        <init>

        +NotaryChangeService(net: MessagingService, smm: StateMachineManager, networkMapCache: NetworkMapCache)
        +

        A service that monitors the network for requests for changing the notary of a state, +and immediately runs the NotaryChangeProtocol if the auto-accept criteria are met.

        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.node.services/-notary-change-service/index.html b/docs/build/html/api/com.r3corda.node.services/-notary-change-service/index.html new file mode 100644 index 0000000000..ad53553c00 --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.services/-notary-change-service/index.html @@ -0,0 +1,74 @@ + + +NotaryChangeService - + + + +com.r3corda.node.services / NotaryChangeService
        +
        +

        NotaryChangeService

        +class NotaryChangeService : AbstractNodeService
        +

        A service that monitors the network for requests for changing the notary of a state, +and immediately runs the NotaryChangeProtocol if the auto-accept criteria are met.

        +
        +
        +

        Constructors

        + + + + + + + +
        +<init> +NotaryChangeService(net: MessagingService, smm: StateMachineManager, networkMapCache: NetworkMapCache)

        A service that monitors the network for requests for changing the notary of a state, +and immediately runs the NotaryChangeProtocol if the auto-accept criteria are met.

        +
        +

        Properties

        + + + + + + + +
        +smm +val smm: StateMachineManager
        +

        Inherited Properties

        + + + + + + + + + + + +
        +net +val net: MessagingService
        +networkMapCache +val networkMapCache: NetworkMapCache
        +

        Inherited Functions

        + + + + + + + +
        +addMessageHandler +fun <Q : ServiceRequestMessage, R : Any> addMessageHandler(topic: String, handler: (Q) -> R, exceptionConsumer: (Message, Exception) -> Unit): Unit

        Register a handler for a message topic. In comparison to using net.addMessageHandler() this manages a lot of +common boilerplate code. Exceptions are caught and passed to the provided consumer. If you just want a simple +acknowledgement response with no content, use com.r3corda.core.messaging.Ack

        +fun <Q : ServiceRequestMessage, R : Any> addMessageHandler(topic: String, handler: (Q) -> R): Unit

        Register a handler for a message topic. In comparison to using net.addMessageHandler() this manages a lot of +common boilerplate code. Exceptions are propagated to the messaging layer. If you just want a simple +acknowledgement response with no content, use com.r3corda.core.messaging.Ack

        +
        + + diff --git a/docs/build/html/api/com.r3corda.node.services/-notary-change-service/smm.html b/docs/build/html/api/com.r3corda.node.services/-notary-change-service/smm.html new file mode 100644 index 0000000000..f3d3d68626 --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.services/-notary-change-service/smm.html @@ -0,0 +1,15 @@ + + +NotaryChangeService.smm - + + + +com.r3corda.node.services / NotaryChangeService / smm
        +
        +

        smm

        + +val smm: StateMachineManager
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.node.services/index.html b/docs/build/html/api/com.r3corda.node.services/index.html new file mode 100644 index 0000000000..4557db0650 --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.services/index.html @@ -0,0 +1,32 @@ + + +com.r3corda.node.services - + + + +com.r3corda.node.services
        +
        +

        Package com.r3corda.node.services

        +

        Types

        + + + + + + + + + + + +
        +FixingSessionInitiationHandler +object FixingSessionInitiationHandler

        This is a temporary handler required for establishing random sessionIDs for the Fixer and Floater as part of +running scheduled fixings for the InterestRateSwap contract.

        +
        +NotaryChangeService +class NotaryChangeService : AbstractNodeService

        A service that monitors the network for requests for changing the notary of a state, +and immediately runs the NotaryChangeProtocol if the auto-accept criteria are met.

        +
        + + diff --git a/docs/build/html/api/com.r3corda.node.utilities/-affinity-executor/-gate/is-on-thread.html b/docs/build/html/api/com.r3corda.node.utilities/-affinity-executor/-gate/is-on-thread.html index 5954600465..e35ef8f93b 100644 --- a/docs/build/html/api/com.r3corda.node.utilities/-affinity-executor/-gate/is-on-thread.html +++ b/docs/build/html/api/com.r3corda.node.utilities/-affinity-executor/-gate/is-on-thread.html @@ -11,9 +11,9 @@ val isOnThread: Boolean
        Overrides AffinityExecutor.isOnThread

        Returns true if the current thread is equal to the thread this executor is backed by.

        -Getter
        +

        Getter

        Returns true if the current thread is equal to the thread this executor is backed by.

        -
        +



        diff --git a/docs/build/html/api/com.r3corda.node.utilities/-affinity-executor/-service-affinity-executor/is-on-thread.html b/docs/build/html/api/com.r3corda.node.utilities/-affinity-executor/-service-affinity-executor/is-on-thread.html index d683a81611..c602ed4dd3 100644 --- a/docs/build/html/api/com.r3corda.node.utilities/-affinity-executor/-service-affinity-executor/is-on-thread.html +++ b/docs/build/html/api/com.r3corda.node.utilities/-affinity-executor/-service-affinity-executor/is-on-thread.html @@ -11,9 +11,9 @@ val isOnThread: Boolean
        Overrides AffinityExecutor.isOnThread

        Returns true if the current thread is equal to the thread this executor is backed by.

        -Getter
        +

        Getter

        Returns true if the current thread is equal to the thread this executor is backed by.

        -
        +



        diff --git a/docs/build/html/api/com.r3corda.node.utilities/-json-support/-public-key-deserializer/deserialize.html b/docs/build/html/api/com.r3corda.node.utilities/-json-support/-public-key-deserializer/deserialize.html new file mode 100644 index 0000000000..cae90d4fc1 --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.utilities/-json-support/-public-key-deserializer/deserialize.html @@ -0,0 +1,15 @@ + + +JsonSupport.PublicKeyDeserializer.deserialize - + + + +com.r3corda.node.utilities / JsonSupport / PublicKeyDeserializer / deserialize
        +
        +

        deserialize

        + +fun deserialize(parser: <ERROR CLASS>, context: <ERROR CLASS>): <ERROR CLASS>
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.node.utilities/-json-support/-public-key-deserializer/index.html b/docs/build/html/api/com.r3corda.node.utilities/-json-support/-public-key-deserializer/index.html new file mode 100644 index 0000000000..044f09384e --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.utilities/-json-support/-public-key-deserializer/index.html @@ -0,0 +1,25 @@ + + +JsonSupport.PublicKeyDeserializer - + + + +com.r3corda.node.utilities / JsonSupport / PublicKeyDeserializer
        +
        +

        PublicKeyDeserializer

        +object PublicKeyDeserializer
        +
        +
        +

        Functions

        + + + + + + + +
        +deserialize +fun deserialize(parser: <ERROR CLASS>, context: <ERROR CLASS>): <ERROR CLASS>
        + + diff --git a/docs/build/html/api/com.r3corda.node.utilities/-json-support/-public-key-serializer/index.html b/docs/build/html/api/com.r3corda.node.utilities/-json-support/-public-key-serializer/index.html new file mode 100644 index 0000000000..1c1bacdf8a --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.utilities/-json-support/-public-key-serializer/index.html @@ -0,0 +1,25 @@ + + +JsonSupport.PublicKeySerializer - + + + +com.r3corda.node.utilities / JsonSupport / PublicKeySerializer
        +
        +

        PublicKeySerializer

        +object PublicKeySerializer
        +
        +
        +

        Functions

        + + + + + + + +
        +serialize +fun serialize(obj: <ERROR CLASS>, generator: <ERROR CLASS>, provider: <ERROR CLASS>): Unit
        + + diff --git a/docs/build/html/api/com.r3corda.node.utilities/-json-support/-public-key-serializer/serialize.html b/docs/build/html/api/com.r3corda.node.utilities/-json-support/-public-key-serializer/serialize.html new file mode 100644 index 0000000000..cc7b23b9b2 --- /dev/null +++ b/docs/build/html/api/com.r3corda.node.utilities/-json-support/-public-key-serializer/serialize.html @@ -0,0 +1,15 @@ + + +JsonSupport.PublicKeySerializer.serialize - + + + +com.r3corda.node.utilities / JsonSupport / PublicKeySerializer / serialize
        +
        +

        serialize

        + +fun serialize(obj: <ERROR CLASS>, generator: <ERROR CLASS>, provider: <ERROR CLASS>): Unit
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.node.utilities/-json-support/index.html b/docs/build/html/api/com.r3corda.node.utilities/-json-support/index.html index ea930ba873..43902e383d 100644 --- a/docs/build/html/api/com.r3corda.node.utilities/-json-support/index.html +++ b/docs/build/html/api/com.r3corda.node.utilities/-json-support/index.html @@ -47,6 +47,18 @@ the java.time API, some core types, and Kotlin data classes.

        +PublicKeyDeserializer + +object PublicKeyDeserializer + + + +PublicKeySerializer + +object PublicKeySerializer + + + SecureHashDeserializer class SecureHashDeserializer<T : SecureHash>

        Implemented as a class so that we can instantiate for T

        diff --git a/docs/build/html/api/com.r3corda.node.utilities/-mutable-clock/index.html b/docs/build/html/api/com.r3corda.node.utilities/-mutable-clock/index.html index 02997984e6..fac91e9a32 100644 --- a/docs/build/html/api/com.r3corda.node.utilities/-mutable-clock/index.html +++ b/docs/build/html/api/com.r3corda.node.utilities/-mutable-clock/index.html @@ -86,7 +86,7 @@ used in demos or testing. This will also substitute a Fiber compatible Future i TestClock -class TestClock : MutableClock

        A Clock that can have the time advanced for use in testing

        +class TestClock : MutableClock, SerializeAsToken

        A Clock that can have the time advanced for use in testing

        diff --git a/docs/build/html/api/com.r3corda.node.utilities/-mutable-clock/mutations.html b/docs/build/html/api/com.r3corda.node.utilities/-mutable-clock/mutations.html index 4208233028..075657a01e 100644 --- a/docs/build/html/api/com.r3corda.node.utilities/-mutable-clock/mutations.html +++ b/docs/build/html/api/com.r3corda.node.utilities/-mutable-clock/mutations.html @@ -10,9 +10,9 @@ val mutations: <ERROR CLASS><Long>

        This is an observer on the mutation count of this Clock, which reflects the occurence of mutations.

        -Getter
        +

        Getter

        This is an observer on the mutation count of this Clock, which reflects the occurence of mutations.

        -
        +



        diff --git a/docs/build/html/api/com.r3corda.node.utilities/java.time.-clock/await-with-deadline.html b/docs/build/html/api/com.r3corda.node.utilities/java.time.-clock/await-with-deadline.html index 3d9f5f024f..858081b983 100644 --- a/docs/build/html/api/com.r3corda.node.utilities/java.time.-clock/await-with-deadline.html +++ b/docs/build/html/api/com.r3corda.node.utilities/java.time.-clock/await-with-deadline.html @@ -11,8 +11,8 @@ fun Clock.awaitWithDeadline(deadline: Instant, future: Future<*> = SettableFuture<Any>()): Boolean

        Wait until the given Future is complete or the deadline is reached, with support for MutableClock implementations used in demos or testing. This will also substitute a Fiber compatible Future if required

        -Return
        -true if the Future is complete, false if the deadline was reached
        +

        Return
        +true if the Future is complete, false if the deadline was reached



        diff --git a/docs/build/html/api/com.r3corda.protocols/-abstract-request-message/-init-.html b/docs/build/html/api/com.r3corda.protocols/-abstract-request-message/-init-.html index 54940ca7fe..5b993c87ee 100644 --- a/docs/build/html/api/com.r3corda.protocols/-abstract-request-message/-init-.html +++ b/docs/build/html/api/com.r3corda.protocols/-abstract-request-message/-init-.html @@ -7,9 +7,7 @@ com.r3corda.protocols / AbstractRequestMessage / <init>

        <init>

        -AbstractRequestMessage(replyTo: MessageRecipients, sessionID: Long?)
        -

        Abstract superclass for request messages sent to services, which includes common -fields such as replyTo and replyToTopic.

        +AbstractRequestMessage(replyToParty: Party)


        diff --git a/docs/build/html/api/com.r3corda.protocols/-abstract-request-message/get-reply-to.html b/docs/build/html/api/com.r3corda.protocols/-abstract-request-message/get-reply-to.html new file mode 100644 index 0000000000..23a77f2d11 --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-abstract-request-message/get-reply-to.html @@ -0,0 +1,16 @@ + + +AbstractRequestMessage.getReplyTo - + + + +com.r3corda.protocols / AbstractRequestMessage / getReplyTo
        +
        +

        getReplyTo

        + +open fun getReplyTo(networkMapCache: NetworkMapCache): MessageRecipients
        +Overrides ServiceRequestMessage.getReplyTo
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-abstract-request-message/index.html b/docs/build/html/api/com.r3corda.protocols/-abstract-request-message/index.html index 6e980b35eb..c3ffea5405 100644 --- a/docs/build/html/api/com.r3corda.protocols/-abstract-request-message/index.html +++ b/docs/build/html/api/com.r3corda.protocols/-abstract-request-message/index.html @@ -7,9 +7,7 @@ com.r3corda.protocols / AbstractRequestMessage

        AbstractRequestMessage

        -abstract class AbstractRequestMessage
        -

        Abstract superclass for request messages sent to services, which includes common -fields such as replyTo and replyToTopic.

        +abstract class AbstractRequestMessage : ServiceRequestMessage


        Constructors

        @@ -19,9 +17,7 @@ fields such as replyTo and replyToTopic.

        <init> -AbstractRequestMessage(replyTo: MessageRecipients, sessionID: Long?)

        Abstract superclass for request messages sent to services, which includes common -fields such as replyTo and replyToTopic.

        - +AbstractRequestMessage(replyToParty: Party) @@ -30,15 +26,31 @@ fields such as replyTo and replyToTopic.

        -replyTo +replyToParty -val replyTo: MessageRecipients +val replyToParty: Party + + +

        Inherited Properties

        + + +sessionID +abstract val sessionID: Long + + +
        -sessionID -val sessionID: Long?
        +

        Functions

        + + + + +
        +getReplyTo +open fun getReplyTo(networkMapCache: NetworkMapCache): MessageRecipients
        @@ -47,21 +59,15 @@ fields such as replyTo and replyToTopic.

        -FetchMapRequest - -class FetchMapRequest : AbstractRequestMessage - - - Handshake class Handshake : AbstractRequestMessage -QueryIdentityRequest +Handshake -class QueryIdentityRequest : AbstractRequestMessage +class Handshake : AbstractRequestMessage @@ -71,12 +77,6 @@ fields such as replyTo and replyToTopic.

        -RegistrationRequest - -class RegistrationRequest : AbstractRequestMessage - - - Request class Request : AbstractRequestMessage @@ -87,12 +87,6 @@ fields such as replyTo and replyToTopic.

        class SignRequest : AbstractRequestMessage - - -SubscribeRequest - -class SubscribeRequest : AbstractRequestMessage - diff --git a/docs/build/html/api/com.r3corda.protocols/-abstract-request-message/reply-to-party.html b/docs/build/html/api/com.r3corda.protocols/-abstract-request-message/reply-to-party.html new file mode 100644 index 0000000000..3d2dea4bb6 --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-abstract-request-message/reply-to-party.html @@ -0,0 +1,15 @@ + + +AbstractRequestMessage.replyToParty - + + + +com.r3corda.protocols / AbstractRequestMessage / replyToParty
        +
        +

        replyToParty

        + +val replyToParty: Party
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-fetch-attachments-protocol/-init-.html b/docs/build/html/api/com.r3corda.protocols/-fetch-attachments-protocol/-init-.html index 33637d3751..ba523ca4e7 100644 --- a/docs/build/html/api/com.r3corda.protocols/-fetch-attachments-protocol/-init-.html +++ b/docs/build/html/api/com.r3corda.protocols/-fetch-attachments-protocol/-init-.html @@ -7,7 +7,7 @@ com.r3corda.protocols / FetchAttachmentsProtocol / <init>

        <init>

        -FetchAttachmentsProtocol(requests: Set<SecureHash>, otherSide: SingleMessageRecipient)
        +FetchAttachmentsProtocol(requests: Set<SecureHash>, otherSide: Party)

        Given a set of hashes either loads from from local storage or requests them from the other peer. Downloaded attachments are saved to local storage automatically.


        diff --git a/docs/build/html/api/com.r3corda.protocols/-fetch-attachments-protocol/index.html b/docs/build/html/api/com.r3corda.protocols/-fetch-attachments-protocol/index.html index 2bda50078b..7b07d87cce 100644 --- a/docs/build/html/api/com.r3corda.protocols/-fetch-attachments-protocol/index.html +++ b/docs/build/html/api/com.r3corda.protocols/-fetch-attachments-protocol/index.html @@ -19,7 +19,7 @@ attachments are saved to local storage automatically.

        <init> -FetchAttachmentsProtocol(requests: Set<SecureHash>, otherSide: SingleMessageRecipient)

        Given a set of hashes either loads from from local storage or requests them from the other peer. Downloaded +FetchAttachmentsProtocol(requests: Set<SecureHash>, otherSide: Party)

        Given a set of hashes either loads from from local storage or requests them from the other peer. Downloaded attachments are saved to local storage automatically.

        @@ -43,7 +43,7 @@ attachments are saved to local storage automatically.

        otherSide -val otherSide: SingleMessageRecipient +val otherSide: Party diff --git a/docs/build/html/api/com.r3corda.protocols/-fetch-data-protocol/-init-.html b/docs/build/html/api/com.r3corda.protocols/-fetch-data-protocol/-init-.html index 70e5ccf6f5..d9f3452373 100644 --- a/docs/build/html/api/com.r3corda.protocols/-fetch-data-protocol/-init-.html +++ b/docs/build/html/api/com.r3corda.protocols/-fetch-data-protocol/-init-.html @@ -7,7 +7,7 @@ com.r3corda.protocols / FetchDataProtocol / <init>

        <init>

        -FetchDataProtocol(requests: Set<SecureHash>, otherSide: SingleMessageRecipient)
        +FetchDataProtocol(requests: Set<SecureHash>, otherSide: Party)

        An abstract protocol for fetching typed data from a remote peer.

        Given a set of hashes (IDs), either loads them from local disk or asks the remote peer to provide them.

        A malicious response in which the data provided by the remote peer does not hash to the requested hash results in diff --git a/docs/build/html/api/com.r3corda.protocols/-fetch-data-protocol/-request/-init-.html b/docs/build/html/api/com.r3corda.protocols/-fetch-data-protocol/-request/-init-.html index c1b1ac5b47..1e9b3752a1 100644 --- a/docs/build/html/api/com.r3corda.protocols/-fetch-data-protocol/-request/-init-.html +++ b/docs/build/html/api/com.r3corda.protocols/-fetch-data-protocol/-request/-init-.html @@ -7,7 +7,7 @@ com.r3corda.protocols / FetchDataProtocol / Request / <init>

        <init>

        -Request(hashes: List<SecureHash>, replyTo: SingleMessageRecipient, sessionID: Long)
        +Request(hashes: List<SecureHash>, replyTo: Party, sessionID: Long)


        diff --git a/docs/build/html/api/com.r3corda.protocols/-fetch-data-protocol/-request/index.html b/docs/build/html/api/com.r3corda.protocols/-fetch-data-protocol/-request/index.html index c8a35a3b22..a6e7ae7b98 100644 --- a/docs/build/html/api/com.r3corda.protocols/-fetch-data-protocol/-request/index.html +++ b/docs/build/html/api/com.r3corda.protocols/-fetch-data-protocol/-request/index.html @@ -17,7 +17,7 @@ <init> -Request(hashes: List<SecureHash>, replyTo: SingleMessageRecipient, sessionID: Long) +Request(hashes: List<SecureHash>, replyTo: Party, sessionID: Long) @@ -30,6 +30,12 @@ val hashes: List<SecureHash> + + +sessionID + +val sessionID: Long +

        Inherited Properties

        @@ -37,15 +43,20 @@ -replyTo +replyToParty -val replyTo: MessageRecipients +val replyToParty: Party + + +

        Inherited Functions

        + + +getReplyTo +open fun getReplyTo(networkMapCache: NetworkMapCache): MessageRecipients
        -sessionID -val sessionID: Long?
        diff --git a/docs/build/html/api/com.r3corda.protocols/-fetch-data-protocol/-request/session-i-d.html b/docs/build/html/api/com.r3corda.protocols/-fetch-data-protocol/-request/session-i-d.html new file mode 100644 index 0000000000..75489170f8 --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-fetch-data-protocol/-request/session-i-d.html @@ -0,0 +1,16 @@ + + +FetchDataProtocol.Request.sessionID - + + + +com.r3corda.protocols / FetchDataProtocol / Request / sessionID
        +
        +

        sessionID

        + +val sessionID: Long
        +Overrides ServiceRequestMessage.sessionID
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-fetch-data-protocol/index.html b/docs/build/html/api/com.r3corda.protocols/-fetch-data-protocol/index.html index 920f48dab7..9b00d39da2 100644 --- a/docs/build/html/api/com.r3corda.protocols/-fetch-data-protocol/index.html +++ b/docs/build/html/api/com.r3corda.protocols/-fetch-data-protocol/index.html @@ -73,7 +73,7 @@ same as the ultimate type, you must also override convert <init> -FetchDataProtocol(requests: Set<SecureHash>, otherSide: SingleMessageRecipient)

        An abstract protocol for fetching typed data from a remote peer.

        +FetchDataProtocol(requests: Set<SecureHash>, otherSide: Party)

        An abstract protocol for fetching typed data from a remote peer.

        @@ -85,7 +85,7 @@ same as the ultimate type, you must also override convert otherSide -val otherSide: SingleMessageRecipient +val otherSide: Party @@ -132,7 +132,9 @@ progress.

        serviceHub -val serviceHub: ServiceHub

        Provides access to big, heavy classes that may be reconstructed from time to time, e.g. across restarts

        +val serviceHub: ServiceHub

        Provides access to big, heavy classes that may be reconstructed from time to time, e.g. across restarts. It is +only available once the protocol has started, which means it cannnot be accessed in the constructor. Either +access this lazily or from inside call.

        @@ -181,13 +183,13 @@ progress.

        send -fun send(topic: String, destination: MessageRecipients, sessionID: Long, obj: Any): Unit +fun send(topic: String, destination: Party, sessionID: Long, payload: Any): Unit sendAndReceive -fun <T : Any> sendAndReceive(topic: String, destination: MessageRecipients, sessionIDForSend: Long, sessionIDForReceive: Long, obj: Any): UntrustworthyData<T> +fun <T : Any> sendAndReceive(topic: String, destination: Party, sessionIDForSend: Long, sessionIDForReceive: Long, payload: Any): UntrustworthyData<T> diff --git a/docs/build/html/api/com.r3corda.protocols/-fetch-data-protocol/other-side.html b/docs/build/html/api/com.r3corda.protocols/-fetch-data-protocol/other-side.html index 2b1c29c0db..6b3c698ba1 100644 --- a/docs/build/html/api/com.r3corda.protocols/-fetch-data-protocol/other-side.html +++ b/docs/build/html/api/com.r3corda.protocols/-fetch-data-protocol/other-side.html @@ -8,7 +8,7 @@

        otherSide

        -protected val otherSide: SingleMessageRecipient
        +protected val otherSide: Party


        diff --git a/docs/build/html/api/com.r3corda.protocols/-fetch-transactions-protocol/-init-.html b/docs/build/html/api/com.r3corda.protocols/-fetch-transactions-protocol/-init-.html index ee12b9d457..f96720e4f4 100644 --- a/docs/build/html/api/com.r3corda.protocols/-fetch-transactions-protocol/-init-.html +++ b/docs/build/html/api/com.r3corda.protocols/-fetch-transactions-protocol/-init-.html @@ -7,7 +7,7 @@ com.r3corda.protocols / FetchTransactionsProtocol / <init>

        <init>

        -FetchTransactionsProtocol(requests: Set<SecureHash>, otherSide: SingleMessageRecipient)
        +FetchTransactionsProtocol(requests: Set<SecureHash>, otherSide: Party)

        Given a set of tx hashes (IDs), either loads them from local disk or asks the remote peer to provide them.

        A malicious response in which the data provided by the remote peer does not hash to the requested hash results in FetchDataProtocol.DownloadedVsRequestedDataMismatch being thrown. If the remote peer doesnt have an entry, it diff --git a/docs/build/html/api/com.r3corda.protocols/-fetch-transactions-protocol/index.html b/docs/build/html/api/com.r3corda.protocols/-fetch-transactions-protocol/index.html index 5da6ca0b8b..e7f0fe9061 100644 --- a/docs/build/html/api/com.r3corda.protocols/-fetch-transactions-protocol/index.html +++ b/docs/build/html/api/com.r3corda.protocols/-fetch-transactions-protocol/index.html @@ -24,7 +24,7 @@ the database, because its up to the caller to actually verify the transactions a <init> -FetchTransactionsProtocol(requests: Set<SecureHash>, otherSide: SingleMessageRecipient)

        Given a set of tx hashes (IDs), either loads them from local disk or asks the remote peer to provide them.

        +FetchTransactionsProtocol(requests: Set<SecureHash>, otherSide: Party)

        Given a set of tx hashes (IDs), either loads them from local disk or asks the remote peer to provide them.

        @@ -47,7 +47,7 @@ the database, because its up to the caller to actually verify the transactions a otherSide -val otherSide: SingleMessageRecipient +val otherSide: Party diff --git a/docs/build/html/api/com.r3corda.protocols/-notary-error/-signatures-missing/-init-.html b/docs/build/html/api/com.r3corda.protocols/-notary-error/-signatures-missing/-init-.html new file mode 100644 index 0000000000..0e2ac5c831 --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-notary-error/-signatures-missing/-init-.html @@ -0,0 +1,14 @@ + + +NotaryError.SignaturesMissing.<init> - + + + +com.r3corda.protocols / NotaryError / SignaturesMissing / <init>
        +
        +

        <init>

        +SignaturesMissing(missingSigners: List<PublicKey>)
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-notary-error/-signatures-missing/index.html b/docs/build/html/api/com.r3corda.protocols/-notary-error/-signatures-missing/index.html new file mode 100644 index 0000000000..fccdcec069 --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-notary-error/-signatures-missing/index.html @@ -0,0 +1,36 @@ + + +NotaryError.SignaturesMissing - + + + +com.r3corda.protocols / NotaryError / SignaturesMissing
        +
        +

        SignaturesMissing

        +class SignaturesMissing : NotaryError
        +
        +
        +

        Constructors

        + + + + + + + +
        +<init> +SignaturesMissing(missingSigners: List<PublicKey>)
        +

        Properties

        + + + + + + + +
        +missingSigners +val missingSigners: List<PublicKey>
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-notary-error/-signatures-missing/missing-signers.html b/docs/build/html/api/com.r3corda.protocols/-notary-error/-signatures-missing/missing-signers.html new file mode 100644 index 0000000000..30d8736421 --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-notary-error/-signatures-missing/missing-signers.html @@ -0,0 +1,15 @@ + + +NotaryError.SignaturesMissing.missingSigners - + + + +com.r3corda.protocols / NotaryError / SignaturesMissing / missingSigners
        +
        +

        missingSigners

        + +val missingSigners: List<PublicKey>
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-notary-error/index.html b/docs/build/html/api/com.r3corda.protocols/-notary-error/index.html index 75451724b6..cb59a7e405 100644 --- a/docs/build/html/api/com.r3corda.protocols/-notary-error/index.html +++ b/docs/build/html/api/com.r3corda.protocols/-notary-error/index.html @@ -34,6 +34,12 @@ +SignaturesMissing + +class SignaturesMissing : NotaryError + + + TimestampInvalid class TimestampInvalid : NotaryError

        Thrown if the time specified in the timestamp command is outside the allowed tolerance

        @@ -71,6 +77,12 @@ +SignaturesMissing + +class SignaturesMissing : NotaryError + + + TimestampInvalid class TimestampInvalid : NotaryError

        Thrown if the time specified in the timestamp command is outside the allowed tolerance

        diff --git a/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-client/-init-.html b/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-client/-init-.html index 81a131dc15..de6eddabdd 100644 --- a/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-client/-init-.html +++ b/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-client/-init-.html @@ -7,7 +7,7 @@ com.r3corda.protocols / NotaryProtocol / Client / <init>

        <init>

        -Client(wtx: WireTransaction, progressTracker: ProgressTracker = Client.tracker())
        +Client(stx: SignedTransaction, progressTracker: ProgressTracker = Client.tracker())

        A protocol to be used for obtaining a signature from a NotaryService ascertaining the transaction timestamp is correct and none of its inputs have been used in another completed transaction

        Exceptions

        diff --git a/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-client/index.html b/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-client/index.html index 6475462376..acf511d2d5 100644 --- a/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-client/index.html +++ b/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-client/index.html @@ -40,7 +40,7 @@ by another transaction or the timestamp is invalid
        <init> -Client(wtx: WireTransaction, progressTracker: ProgressTracker = Client.tracker())

        A protocol to be used for obtaining a signature from a NotaryService ascertaining the transaction +Client(stx: SignedTransaction, progressTracker: ProgressTracker = Client.tracker())

        A protocol to be used for obtaining a signature from a NotaryService ascertaining the transaction timestamp is correct and none of its inputs have been used in another completed transaction

        @@ -51,9 +51,9 @@ timestamp is correct and none of its inputs have been used in another completed -notaryNode +notaryParty -lateinit var notaryNode: NodeInfo +lateinit var notaryParty: Party @@ -88,7 +88,9 @@ progress.

        serviceHub -val serviceHub: ServiceHub

        Provides access to big, heavy classes that may be reconstructed from time to time, e.g. across restarts

        +val serviceHub: ServiceHub

        Provides access to big, heavy classes that may be reconstructed from time to time, e.g. across restarts. It is +only available once the protocol has started, which means it cannnot be accessed in the constructor. Either +access this lazily or from inside call.

        @@ -112,20 +114,20 @@ progress.

        receive -fun <T : Any> receive(topic: String, sessionIDForReceive: Long, clazz: Class<T>): UntrustworthyData<T>
        -fun <T : Any> receive(topic: String, sessionIDForReceive: Long): UntrustworthyData<T> +fun <T : Any> receive(topic: String, sessionIDForReceive: Long): UntrustworthyData<T>
        +fun <T : Any> receive(topic: String, sessionIDForReceive: Long, clazz: Class<T>): UntrustworthyData<T> send -fun send(topic: String, destination: MessageRecipients, sessionID: Long, obj: Any): Unit +fun send(topic: String, destination: Party, sessionID: Long, payload: Any): Unit sendAndReceive -fun <T : Any> sendAndReceive(topic: String, destination: MessageRecipients, sessionIDForSend: Long, sessionIDForReceive: Long, obj: Any): UntrustworthyData<T> +fun <T : Any> sendAndReceive(topic: String, destination: Party, sessionIDForSend: Long, sessionIDForReceive: Long, payload: Any): UntrustworthyData<T> diff --git a/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-client/notary-party.html b/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-client/notary-party.html new file mode 100644 index 0000000000..cb6af79ab5 --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-client/notary-party.html @@ -0,0 +1,15 @@ + + +NotaryProtocol.Client.notaryParty - + + + +com.r3corda.protocols / NotaryProtocol / Client / notaryParty
        +
        +

        notaryParty

        + +lateinit var notaryParty: Party
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-default-factory/create.html b/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-default-factory/create.html index 6a736e9e8e..9b88e30bdd 100644 --- a/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-default-factory/create.html +++ b/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-default-factory/create.html @@ -7,8 +7,8 @@ com.r3corda.protocols / NotaryProtocol / DefaultFactory / create

        create

        - -fun create(otherSide: SingleMessageRecipient, sendSessionID: Long, receiveSessionID: Long, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider): Service
        + +fun create(otherSide: Party, sendSessionID: Long, receiveSessionID: Long, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider): Service
        Overrides Factory.create


        diff --git a/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-default-factory/index.html b/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-default-factory/index.html index d0302b4e8a..b3c9ee74e0 100644 --- a/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-default-factory/index.html +++ b/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-default-factory/index.html @@ -17,7 +17,7 @@ create -fun create(otherSide: SingleMessageRecipient, sendSessionID: Long, receiveSessionID: Long, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider): Service +fun create(otherSide: Party, sendSessionID: Long, receiveSessionID: Long, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider): Service diff --git a/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-factory/create.html b/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-factory/create.html index 03b5ef7da7..72aa0b33b7 100644 --- a/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-factory/create.html +++ b/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-factory/create.html @@ -7,8 +7,8 @@ com.r3corda.protocols / NotaryProtocol / Factory / create

        create

        - -abstract fun create(otherSide: SingleMessageRecipient, sendSessionID: Long, receiveSessionID: Long, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider): Service
        + +abstract fun create(otherSide: Party, sendSessionID: Long, receiveSessionID: Long, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider): Service


        diff --git a/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-factory/index.html b/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-factory/index.html index 9a43703caf..8a1c1dcb9e 100644 --- a/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-factory/index.html +++ b/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-factory/index.html @@ -17,7 +17,7 @@ create -abstract fun create(otherSide: SingleMessageRecipient, sendSessionID: Long, receiveSessionID: Long, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider): Service +abstract fun create(otherSide: Party, sendSessionID: Long, receiveSessionID: Long, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider): Service diff --git a/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-handshake/-init-.html b/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-handshake/-init-.html index 074d1dbee7..7e4dc37026 100644 --- a/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-handshake/-init-.html +++ b/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-handshake/-init-.html @@ -7,7 +7,7 @@ com.r3corda.protocols / NotaryProtocol / Handshake / <init>

        <init>

        -Handshake(replyTo: SingleMessageRecipient, sendSessionID: Long, sessionID: Long)
        +Handshake(replyTo: Party, sendSessionID: Long, sessionID: Long)


        diff --git a/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-handshake/index.html b/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-handshake/index.html index 1297361f9f..6ceb0b627b 100644 --- a/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-handshake/index.html +++ b/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-handshake/index.html @@ -17,7 +17,7 @@ <init> -Handshake(replyTo: SingleMessageRecipient, sendSessionID: Long, sessionID: Long) +Handshake(replyTo: Party, sendSessionID: Long, sessionID: Long) @@ -30,6 +30,12 @@ val sendSessionID: Long + + +sessionID + +val sessionID: Long +

        Inherited Properties

        @@ -37,15 +43,20 @@ -replyTo +replyToParty -val replyTo: MessageRecipients +val replyToParty: Party + + +

        Inherited Functions

        + + +getReplyTo +open fun getReplyTo(networkMapCache: NetworkMapCache): MessageRecipients
        -sessionID -val sessionID: Long?
        diff --git a/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-handshake/session-i-d.html b/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-handshake/session-i-d.html new file mode 100644 index 0000000000..fca7e1c6e8 --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-handshake/session-i-d.html @@ -0,0 +1,16 @@ + + +NotaryProtocol.Handshake.sessionID - + + + +com.r3corda.protocols / NotaryProtocol / Handshake / sessionID
        +
        +

        sessionID

        + +val sessionID: Long
        +Overrides ServiceRequestMessage.sessionID
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-service/-init-.html b/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-service/-init-.html index 01baddf5e8..abdae62367 100644 --- a/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-service/-init-.html +++ b/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-service/-init-.html @@ -7,7 +7,7 @@ com.r3corda.protocols / NotaryProtocol / Service / <init>

        <init>

        -Service(otherSide: SingleMessageRecipient, sendSessionID: Long, receiveSessionID: Long, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider)
        +Service(otherSide: Party, sendSessionID: Long, receiveSessionID: Long, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider)

        Checks that the timestamp command is valid (if present) and commits the input state, or returns a conflict if any of the input states have been previously committed.

        Extend this class, overriding beforeCommit to add custom transaction processing/validation logic.

        diff --git a/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-service/before-commit.html b/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-service/before-commit.html index 12ea6799f1..077ca8b369 100644 --- a/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-service/before-commit.html +++ b/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-service/before-commit.html @@ -7,8 +7,8 @@ com.r3corda.protocols / NotaryProtocol / Service / beforeCommit

        beforeCommit

        - -open fun beforeCommit(wtx: WireTransaction, reqIdentity: Party): Unit
        + +open fun beforeCommit(stx: SignedTransaction, reqIdentity: Party): Unit

        No pre-commit processing is done. Transaction is not checked for contract-validity, as that would require fully resolving it into a TransactionForVerification, for which the caller would have to reveal the whole transaction history chain. diff --git a/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-service/index.html b/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-service/index.html index 24f1a6795b..7156a0fb1e 100644 --- a/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-service/index.html +++ b/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-service/index.html @@ -23,7 +23,7 @@ if any of the input states have been previously committed.

        <init> -Service(otherSide: SingleMessageRecipient, sendSessionID: Long, receiveSessionID: Long, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider)

        Checks that the timestamp command is valid (if present) and commits the input state, or returns a conflict +Service(otherSide: Party, sendSessionID: Long, receiveSessionID: Long, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider)

        Checks that the timestamp command is valid (if present) and commits the input state, or returns a conflict if any of the input states have been previously committed.

        @@ -36,7 +36,7 @@ if any of the input states have been previously committed.

        otherSide -val otherSide: SingleMessageRecipient +val otherSide: Party @@ -95,7 +95,9 @@ progress.

        serviceHub -val serviceHub: ServiceHub

        Provides access to big, heavy classes that may be reconstructed from time to time, e.g. across restarts

        +val serviceHub: ServiceHub

        Provides access to big, heavy classes that may be reconstructed from time to time, e.g. across restarts. It is +only available once the protocol has started, which means it cannnot be accessed in the constructor. Either +access this lazily or from inside call.

        @@ -107,7 +109,7 @@ progress.

        beforeCommit -open fun beforeCommit(wtx: WireTransaction, reqIdentity: Party): Unit

        No pre-commit processing is done. Transaction is not checked for contract-validity, as that would require fully +open fun beforeCommit(stx: SignedTransaction, reqIdentity: Party): Unit

        No pre-commit processing is done. Transaction is not checked for contract-validity, as that would require fully resolving it into a TransactionForVerification, for which the caller would have to reveal the whole transaction history chain. As a result, the Notary will commit invalid transactions as well, but as it also records the identity of @@ -138,13 +140,13 @@ undo the commit of the input states (the exact mechanism still needs to be worke send -fun send(topic: String, destination: MessageRecipients, sessionID: Long, obj: Any): Unit +fun send(topic: String, destination: Party, sessionID: Long, payload: Any): Unit sendAndReceive -fun <T : Any> sendAndReceive(topic: String, destination: MessageRecipients, sessionIDForSend: Long, sessionIDForReceive: Long, obj: Any): UntrustworthyData<T> +fun <T : Any> sendAndReceive(topic: String, destination: Party, sessionIDForSend: Long, sessionIDForReceive: Long, payload: Any): UntrustworthyData<T> diff --git a/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-service/other-side.html b/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-service/other-side.html index 6f53c2667d..1b1772344b 100644 --- a/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-service/other-side.html +++ b/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-service/other-side.html @@ -8,7 +8,7 @@

        otherSide

        -val otherSide: SingleMessageRecipient
        +val otherSide: Party


        diff --git a/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-sign-request/-init-.html b/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-sign-request/-init-.html index d5f7cc9dbe..ee0b5e8fd9 100644 --- a/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-sign-request/-init-.html +++ b/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-sign-request/-init-.html @@ -7,7 +7,7 @@ com.r3corda.protocols / NotaryProtocol / SignRequest / <init>

        <init>

        -SignRequest(txBits: SerializedBytes<WireTransaction>, callerIdentity: Party)
        +SignRequest(tx: SignedTransaction, callerIdentity: Party)

        TODO: The caller must authenticate instead of just specifying its identity



        diff --git a/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-sign-request/index.html b/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-sign-request/index.html index 51d792d627..7dd74ff415 100644 --- a/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-sign-request/index.html +++ b/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-sign-request/index.html @@ -18,7 +18,7 @@ <init> -SignRequest(txBits: SerializedBytes<WireTransaction>, callerIdentity: Party)

        TODO: The caller must authenticate instead of just specifying its identity

        +SignRequest(tx: SignedTransaction, callerIdentity: Party)

        TODO: The caller must authenticate instead of just specifying its identity

        @@ -34,9 +34,9 @@ -txBits +tx -val txBits: SerializedBytes<WireTransaction> +val tx: SignedTransaction diff --git a/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-sign-request/tx.html b/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-sign-request/tx.html new file mode 100644 index 0000000000..48bdf26c3f --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-notary-protocol/-sign-request/tx.html @@ -0,0 +1,15 @@ + + +NotaryProtocol.SignRequest.tx - + + + +com.r3corda.protocols / NotaryProtocol / SignRequest / tx
        +
        +

        tx

        + +val tx: SignedTransaction
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-rates-fix-protocol/-init-.html b/docs/build/html/api/com.r3corda.protocols/-rates-fix-protocol/-init-.html index 4fbd27e9c9..23c6fb94d5 100644 --- a/docs/build/html/api/com.r3corda.protocols/-rates-fix-protocol/-init-.html +++ b/docs/build/html/api/com.r3corda.protocols/-rates-fix-protocol/-init-.html @@ -7,7 +7,7 @@ com.r3corda.protocols / RatesFixProtocol / <init>

        <init>

        -RatesFixProtocol(tx: TransactionBuilder, oracle: NodeInfo, fixOf: FixOf, expectedRate: BigDecimal, rateTolerance: BigDecimal, progressTracker: ProgressTracker = RatesFixProtocol.tracker(fixOf.name))
        +RatesFixProtocol(tx: TransactionBuilder, oracle: Party, fixOf: FixOf, expectedRate: BigDecimal, rateTolerance: BigDecimal, timeOut: Duration, progressTracker: ProgressTracker = RatesFixProtocol.tracker(fixOf.name))

        This protocol queries the given oracle for an interest rate fix, and if it is within the given tolerance embeds the fix in the transaction and then proceeds to get the oracle to sign it. Although the call method combines the query and signing step, you can run the steps individually by constructing this object and then using the public methods diff --git a/docs/build/html/api/com.r3corda.protocols/-rates-fix-protocol/-query-request/-init-.html b/docs/build/html/api/com.r3corda.protocols/-rates-fix-protocol/-query-request/-init-.html index 59284c1eb3..072a4f3cf8 100644 --- a/docs/build/html/api/com.r3corda.protocols/-rates-fix-protocol/-query-request/-init-.html +++ b/docs/build/html/api/com.r3corda.protocols/-rates-fix-protocol/-query-request/-init-.html @@ -7,7 +7,7 @@ com.r3corda.protocols / RatesFixProtocol / QueryRequest / <init>

        <init>

        -QueryRequest(queries: List<FixOf>, replyTo: SingleMessageRecipient, sessionID: Long)
        +QueryRequest(queries: List<FixOf>, replyTo: Party, sessionID: Long, deadline: Instant)


        diff --git a/docs/build/html/api/com.r3corda.protocols/-rates-fix-protocol/-query-request/deadline.html b/docs/build/html/api/com.r3corda.protocols/-rates-fix-protocol/-query-request/deadline.html new file mode 100644 index 0000000000..3c91392aa4 --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-rates-fix-protocol/-query-request/deadline.html @@ -0,0 +1,15 @@ + + +RatesFixProtocol.QueryRequest.deadline - + + + +com.r3corda.protocols / RatesFixProtocol / QueryRequest / deadline
        +
        +

        deadline

        + +val deadline: Instant
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-rates-fix-protocol/-query-request/index.html b/docs/build/html/api/com.r3corda.protocols/-rates-fix-protocol/-query-request/index.html index ff1e3afeed..4a55bc6c68 100644 --- a/docs/build/html/api/com.r3corda.protocols/-rates-fix-protocol/-query-request/index.html +++ b/docs/build/html/api/com.r3corda.protocols/-rates-fix-protocol/-query-request/index.html @@ -17,7 +17,7 @@ <init> -QueryRequest(queries: List<FixOf>, replyTo: SingleMessageRecipient, sessionID: Long) +QueryRequest(queries: List<FixOf>, replyTo: Party, sessionID: Long, deadline: Instant) @@ -26,10 +26,22 @@ +deadline + +val deadline: Instant + + + queries val queries: List<FixOf> + + +sessionID + +val sessionID: Long +

        Inherited Properties

        @@ -37,15 +49,20 @@ -replyTo +replyToParty -val replyTo: MessageRecipients +val replyToParty: Party + + +

        Inherited Functions

        + + +getReplyTo +open fun getReplyTo(networkMapCache: NetworkMapCache): MessageRecipients
        -sessionID -val sessionID: Long?
        diff --git a/docs/build/html/api/com.r3corda.protocols/-rates-fix-protocol/-query-request/session-i-d.html b/docs/build/html/api/com.r3corda.protocols/-rates-fix-protocol/-query-request/session-i-d.html new file mode 100644 index 0000000000..bf45e9fe03 --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-rates-fix-protocol/-query-request/session-i-d.html @@ -0,0 +1,16 @@ + + +RatesFixProtocol.QueryRequest.sessionID - + + + +com.r3corda.protocols / RatesFixProtocol / QueryRequest / sessionID
        +
        +

        sessionID

        + +val sessionID: Long
        +Overrides ServiceRequestMessage.sessionID
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-rates-fix-protocol/-sign-request/-init-.html b/docs/build/html/api/com.r3corda.protocols/-rates-fix-protocol/-sign-request/-init-.html index b7a627088c..2ee1b5c0fc 100644 --- a/docs/build/html/api/com.r3corda.protocols/-rates-fix-protocol/-sign-request/-init-.html +++ b/docs/build/html/api/com.r3corda.protocols/-rates-fix-protocol/-sign-request/-init-.html @@ -7,7 +7,7 @@ com.r3corda.protocols / RatesFixProtocol / SignRequest / <init>

        <init>

        -SignRequest(tx: WireTransaction, replyTo: SingleMessageRecipient, sessionID: Long)
        +SignRequest(tx: WireTransaction, replyTo: Party, sessionID: Long)


        diff --git a/docs/build/html/api/com.r3corda.protocols/-rates-fix-protocol/-sign-request/index.html b/docs/build/html/api/com.r3corda.protocols/-rates-fix-protocol/-sign-request/index.html index 71451b5476..831f76e5b1 100644 --- a/docs/build/html/api/com.r3corda.protocols/-rates-fix-protocol/-sign-request/index.html +++ b/docs/build/html/api/com.r3corda.protocols/-rates-fix-protocol/-sign-request/index.html @@ -17,7 +17,7 @@ <init> -SignRequest(tx: WireTransaction, replyTo: SingleMessageRecipient, sessionID: Long) +SignRequest(tx: WireTransaction, replyTo: Party, sessionID: Long) @@ -26,6 +26,12 @@ +sessionID + +val sessionID: Long + + + tx val tx: WireTransaction @@ -37,15 +43,20 @@ -replyTo +replyToParty -val replyTo: MessageRecipients +val replyToParty: Party + + +

        Inherited Functions

        + + +getReplyTo +open fun getReplyTo(networkMapCache: NetworkMapCache): MessageRecipients
        -sessionID -val sessionID: Long?
        diff --git a/docs/build/html/api/com.r3corda.protocols/-rates-fix-protocol/-sign-request/session-i-d.html b/docs/build/html/api/com.r3corda.protocols/-rates-fix-protocol/-sign-request/session-i-d.html new file mode 100644 index 0000000000..efe052d1ff --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-rates-fix-protocol/-sign-request/session-i-d.html @@ -0,0 +1,16 @@ + + +RatesFixProtocol.SignRequest.sessionID - + + + +com.r3corda.protocols / RatesFixProtocol / SignRequest / sessionID
        +
        +

        sessionID

        + +val sessionID: Long
        +Overrides ServiceRequestMessage.sessionID
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-rates-fix-protocol/index.html b/docs/build/html/api/com.r3corda.protocols/-rates-fix-protocol/index.html index cab8f669d2..072f7e9091 100644 --- a/docs/build/html/api/com.r3corda.protocols/-rates-fix-protocol/index.html +++ b/docs/build/html/api/com.r3corda.protocols/-rates-fix-protocol/index.html @@ -70,7 +70,7 @@ for each step.

        <init> -RatesFixProtocol(tx: TransactionBuilder, oracle: NodeInfo, fixOf: FixOf, expectedRate: BigDecimal, rateTolerance: BigDecimal, progressTracker: ProgressTracker = RatesFixProtocol.tracker(fixOf.name))

        This protocol queries the given oracle for an interest rate fix, and if it is within the given tolerance embeds the +RatesFixProtocol(tx: TransactionBuilder, oracle: Party, fixOf: FixOf, expectedRate: BigDecimal, rateTolerance: BigDecimal, timeOut: Duration, progressTracker: ProgressTracker = RatesFixProtocol.tracker(fixOf.name))

        This protocol queries the given oracle for an interest rate fix, and if it is within the given tolerance embeds the fix in the transaction and then proceeds to get the oracle to sign it. Although the call method combines the query and signing step, you can run the steps individually by constructing this object and then using the public methods for each step.

        @@ -120,7 +120,9 @@ progress.

        serviceHub -val serviceHub: ServiceHub

        Provides access to big, heavy classes that may be reconstructed from time to time, e.g. across restarts

        +val serviceHub: ServiceHub

        Provides access to big, heavy classes that may be reconstructed from time to time, e.g. across restarts. It is +only available once the protocol has started, which means it cannnot be accessed in the constructor. Either +access this lazily or from inside call.

        @@ -164,20 +166,20 @@ before its sent back to the oracle for signing (for example, adding output state receive -fun <T : Any> receive(topic: String, sessionIDForReceive: Long): UntrustworthyData<T>
        -fun <T : Any> receive(topic: String, sessionIDForReceive: Long, clazz: Class<T>): UntrustworthyData<T> +fun <T : Any> receive(topic: String, sessionIDForReceive: Long, clazz: Class<T>): UntrustworthyData<T>
        +fun <T : Any> receive(topic: String, sessionIDForReceive: Long): UntrustworthyData<T> send -fun send(topic: String, destination: MessageRecipients, sessionID: Long, obj: Any): Unit +fun send(topic: String, destination: Party, sessionID: Long, payload: Any): Unit sendAndReceive -fun <T : Any> sendAndReceive(topic: String, destination: MessageRecipients, sessionIDForSend: Long, sessionIDForReceive: Long, obj: Any): UntrustworthyData<T> +fun <T : Any> sendAndReceive(topic: String, destination: Party, sessionIDForSend: Long, sessionIDForReceive: Long, payload: Any): UntrustworthyData<T> diff --git a/docs/build/html/api/com.r3corda.protocols/-resolve-transactions-protocol/-init-.html b/docs/build/html/api/com.r3corda.protocols/-resolve-transactions-protocol/-init-.html index 2b6b24568e..ca646043e5 100644 --- a/docs/build/html/api/com.r3corda.protocols/-resolve-transactions-protocol/-init-.html +++ b/docs/build/html/api/com.r3corda.protocols/-resolve-transactions-protocol/-init-.html @@ -7,11 +7,11 @@ com.r3corda.protocols / ResolveTransactionsProtocol / <init>

        <init>

        -ResolveTransactionsProtocol(stx: SignedTransaction, otherSide: SingleMessageRecipient)
        -ResolveTransactionsProtocol(wtx: WireTransaction, otherSide: SingleMessageRecipient)
        +ResolveTransactionsProtocol(stx: SignedTransaction, otherSide: Party)
        +ResolveTransactionsProtocol(wtx: WireTransaction, otherSide: Party)


        -ResolveTransactionsProtocol(txHashes: Set<SecureHash>, otherSide: SingleMessageRecipient)
        +ResolveTransactionsProtocol(txHashes: Set<SecureHash>, otherSide: Party)

        This protocol fetches each transaction identified by the given hashes from either disk or network, along with all their dependencies, and verifies them together using a single TransactionGroup. If no exception is thrown, then all the transactions have been successfully verified and inserted into the local database.

        diff --git a/docs/build/html/api/com.r3corda.protocols/-resolve-transactions-protocol/index.html b/docs/build/html/api/com.r3corda.protocols/-resolve-transactions-protocol/index.html index c7f10aa81c..e38471d22d 100644 --- a/docs/build/html/api/com.r3corda.protocols/-resolve-transactions-protocol/index.html +++ b/docs/build/html/api/com.r3corda.protocols/-resolve-transactions-protocol/index.html @@ -38,8 +38,8 @@ protocol is helpful when resolving and verifying a finished but partially signed <init> -ResolveTransactionsProtocol(stx: SignedTransaction, otherSide: SingleMessageRecipient)
        -ResolveTransactionsProtocol(wtx: WireTransaction, otherSide: SingleMessageRecipient)ResolveTransactionsProtocol(txHashes: Set<SecureHash>, otherSide: SingleMessageRecipient)

        This protocol fetches each transaction identified by the given hashes from either disk or network, along with all +ResolveTransactionsProtocol(stx: SignedTransaction, otherSide: Party)
        +ResolveTransactionsProtocol(wtx: WireTransaction, otherSide: Party)ResolveTransactionsProtocol(txHashes: Set<SecureHash>, otherSide: Party)

        This protocol fetches each transaction identified by the given hashes from either disk or network, along with all their dependencies, and verifies them together using a single TransactionGroup. If no exception is thrown, then all the transactions have been successfully verified and inserted into the local database.

        @@ -77,7 +77,9 @@ progress.

        serviceHub -val serviceHub: ServiceHub

        Provides access to big, heavy classes that may be reconstructed from time to time, e.g. across restarts

        +val serviceHub: ServiceHub

        Provides access to big, heavy classes that may be reconstructed from time to time, e.g. across restarts. It is +only available once the protocol has started, which means it cannnot be accessed in the constructor. Either +access this lazily or from inside call.

        @@ -101,20 +103,20 @@ progress.

        receive -fun <T : Any> receive(topic: String, sessionIDForReceive: Long): UntrustworthyData<T>
        -fun <T : Any> receive(topic: String, sessionIDForReceive: Long, clazz: Class<T>): UntrustworthyData<T> +fun <T : Any> receive(topic: String, sessionIDForReceive: Long, clazz: Class<T>): UntrustworthyData<T>
        +fun <T : Any> receive(topic: String, sessionIDForReceive: Long): UntrustworthyData<T> send -fun send(topic: String, destination: MessageRecipients, sessionID: Long, obj: Any): Unit +fun send(topic: String, destination: Party, sessionID: Long, payload: Any): Unit sendAndReceive -fun <T : Any> sendAndReceive(topic: String, destination: MessageRecipients, sessionIDForSend: Long, sessionIDForReceive: Long, obj: Any): UntrustworthyData<T> +fun <T : Any> sendAndReceive(topic: String, destination: Party, sessionIDForSend: Long, sessionIDForReceive: Long, payload: Any): UntrustworthyData<T> diff --git a/docs/build/html/api/com.r3corda.protocols/-service-request-message/get-reply-to.html b/docs/build/html/api/com.r3corda.protocols/-service-request-message/get-reply-to.html new file mode 100644 index 0000000000..ebfe8e1354 --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-service-request-message/get-reply-to.html @@ -0,0 +1,15 @@ + + +ServiceRequestMessage.getReplyTo - + + + +com.r3corda.protocols / ServiceRequestMessage / getReplyTo
        +
        +

        getReplyTo

        + +abstract fun getReplyTo(networkMapCache: NetworkMapCache): MessageRecipients
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-service-request-message/index.html b/docs/build/html/api/com.r3corda.protocols/-service-request-message/index.html new file mode 100644 index 0000000000..74df70d2c3 --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-service-request-message/index.html @@ -0,0 +1,55 @@ + + +ServiceRequestMessage - + + + +com.r3corda.protocols / ServiceRequestMessage
        +
        +

        ServiceRequestMessage

        +interface ServiceRequestMessage
        +

        Abstract superclass for request messages sent to services, which includes common +fields such as replyTo and replyToTopic.

        +
        +
        +

        Properties

        + + + + + + + +
        +sessionID +abstract val sessionID: Long
        +

        Functions

        + + + + + + + +
        +getReplyTo +abstract fun getReplyTo(networkMapCache: NetworkMapCache): MessageRecipients
        +

        Inheritors

        + + + + + + + + + + + +
        +AbstractRequestMessage +abstract class AbstractRequestMessage : ServiceRequestMessage
        +NetworkMapRequestMessage +abstract class NetworkMapRequestMessage : ServiceRequestMessage
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-service-request-message/session-i-d.html b/docs/build/html/api/com.r3corda.protocols/-service-request-message/session-i-d.html new file mode 100644 index 0000000000..e16311b759 --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-service-request-message/session-i-d.html @@ -0,0 +1,15 @@ + + +ServiceRequestMessage.sessionID - + + + +com.r3corda.protocols / ServiceRequestMessage / sessionID
        +
        +

        sessionID

        + +abstract val sessionID: Long
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-acceptor/-init-.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-acceptor/-init-.html index e6ce3d479a..1740ae331b 100644 --- a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-acceptor/-init-.html +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-acceptor/-init-.html @@ -7,7 +7,7 @@ com.r3corda.protocols / TwoPartyDealProtocol / Acceptor / <init>

        <init>

        -Acceptor(otherSide: SingleMessageRecipient, notary: Party, dealToBuy: T, sessionID: Long, progressTracker: ProgressTracker = Secondary.tracker())
        +Acceptor(otherSide: Party, notary: Party, dealToBuy: T, sessionID: Long, progressTracker: ProgressTracker = Secondary.tracker())

        One side of the protocol for inserting a pre-agreed deal.



        diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-acceptor/index.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-acceptor/index.html index bfa0a41639..03f980cd59 100644 --- a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-acceptor/index.html +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-acceptor/index.html @@ -18,7 +18,7 @@ <init> -Acceptor(otherSide: SingleMessageRecipient, notary: Party, dealToBuy: T, sessionID: Long, progressTracker: ProgressTracker = Secondary.tracker())

        One side of the protocol for inserting a pre-agreed deal.

        +Acceptor(otherSide: Party, notary: Party, dealToBuy: T, sessionID: Long, progressTracker: ProgressTracker = Secondary.tracker())

        One side of the protocol for inserting a pre-agreed deal.

        @@ -34,6 +34,18 @@ +notary + +val notary: Party + + + +otherSide + +open val otherSide: Party + + + progressTracker open val progressTracker: ProgressTracker

        Override this to provide a ProgressTracker. If one is provided and stepped, the framework will do something @@ -42,28 +54,11 @@ tracker will be made a child of the current step in the parent. If its null, thi progress.

        - - -

        Inherited Properties

        - - +sessionID - - - - - - - - +open val sessionID: Long
        -notary -val notary: Party
        -otherSide -val otherSide: SingleMessageRecipient
        -sessionID -val sessionID: Long
        diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-acceptor/notary.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-acceptor/notary.html new file mode 100644 index 0000000000..21a6b0190e --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-acceptor/notary.html @@ -0,0 +1,15 @@ + + +TwoPartyDealProtocol.Acceptor.notary - + + + +com.r3corda.protocols / TwoPartyDealProtocol / Acceptor / notary
        +
        +

        notary

        + +val notary: Party
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-acceptor/other-side.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-acceptor/other-side.html new file mode 100644 index 0000000000..612449703a --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-acceptor/other-side.html @@ -0,0 +1,16 @@ + + +TwoPartyDealProtocol.Acceptor.otherSide - + + + +com.r3corda.protocols / TwoPartyDealProtocol / Acceptor / otherSide
        +
        +

        otherSide

        + +open val otherSide: Party
        +Overrides Secondary.otherSide
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-acceptor/session-i-d.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-acceptor/session-i-d.html new file mode 100644 index 0000000000..a4b7f8e575 --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-acceptor/session-i-d.html @@ -0,0 +1,16 @@ + + +TwoPartyDealProtocol.Acceptor.sessionID - + + + +com.r3corda.protocols / TwoPartyDealProtocol / Acceptor / sessionID
        +
        +

        sessionID

        + +open val sessionID: Long
        +Overrides Secondary.sessionID
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-f-i-x_-i-n-i-t-i-a-t-e_-t-o-p-i-c.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-f-i-x_-i-n-i-t-i-a-t-e_-t-o-p-i-c.html new file mode 100644 index 0000000000..90cb5fc58f --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-f-i-x_-i-n-i-t-i-a-t-e_-t-o-p-i-c.html @@ -0,0 +1,16 @@ + + +TwoPartyDealProtocol.FIX_INITIATE_TOPIC - + + + +com.r3corda.protocols / TwoPartyDealProtocol / FIX_INITIATE_TOPIC
        +
        +

        FIX_INITIATE_TOPIC

        + +val FIX_INITIATE_TOPIC: String
        +

        This topic exists purely for FixingSessionInitiation to be sent from FixingRoleDecider to FixingSessionInitiationHandler

        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixer/-init-.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixer/-init-.html index c937f9ec4b..1151015509 100644 --- a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixer/-init-.html +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixer/-init-.html @@ -7,10 +7,10 @@ com.r3corda.protocols / TwoPartyDealProtocol / Fixer / <init>

        <init>

        -Fixer(otherSide: SingleMessageRecipient, notary: Party, dealToFix: StateAndRef<T>, sessionID: Long, replacementProgressTracker: ProgressTracker? = null)
        +Fixer(initiation: FixingSessionInitiation, progressTracker: ProgressTracker = Secondary.tracker())

        One side of the fixing protocol for an interest rate swap, but could easily be generalised further.

        Do not infer too much from the name of the class. This is just to indicate that it is the "side" -of the protocol that is run by the party with the fixed leg of swap deal, which is the basis for decided +of the protocol that is run by the party with the fixed leg of swap deal, which is the basis for deciding who does what in the protocol.



        diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixer/assemble-shared-t-x.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixer/assemble-shared-t-x.html index a67b63d287..d779b66114 100644 --- a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixer/assemble-shared-t-x.html +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixer/assemble-shared-t-x.html @@ -8,7 +8,7 @@

        assembleSharedTX

        -protected open fun assembleSharedTX(handshake: Handshake<StateRef>): <ERROR CLASS><TransactionBuilder, List<PublicKey>>
        +protected fun assembleSharedTX(handshake: Handshake<StateRef>): <ERROR CLASS><TransactionBuilder, List<PublicKey>>


        diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixer/index.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixer/index.html index 2a2f597d1b..42fa221e1a 100644 --- a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixer/index.html +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixer/index.html @@ -7,10 +7,10 @@ com.r3corda.protocols / TwoPartyDealProtocol / Fixer

        Fixer

        -class Fixer<T : FixableDealState> : Secondary<StateRef>
        +class Fixer : Secondary<StateRef>

        One side of the fixing protocol for an interest rate swap, but could easily be generalised further.

        Do not infer too much from the name of the class. This is just to indicate that it is the "side" -of the protocol that is run by the party with the fixed leg of swap deal, which is the basis for decided +of the protocol that is run by the party with the fixed leg of swap deal, which is the basis for deciding who does what in the protocol.



        @@ -23,7 +23,7 @@ who does what in the protocol.

        <init> -Fixer(otherSide: SingleMessageRecipient, notary: Party, dealToFix: StateAndRef<T>, sessionID: Long, replacementProgressTracker: ProgressTracker? = null)

        One side of the fixing protocol for an interest rate swap, but could easily be generalised further.

        +Fixer(initiation: FixingSessionInitiation, progressTracker: ProgressTracker = Secondary.tracker())

        One side of the fixing protocol for an interest rate swap, but could easily be generalised further.

        @@ -33,15 +33,21 @@ who does what in the protocol.

        -dealToFix +initiation -val dealToFix: StateAndRef<T> +val initiation: FixingSessionInitiation + + + +otherSide + +val otherSide: Party progressTracker -open val progressTracker: ProgressTracker

        Override this to provide a ProgressTracker. If one is provided and stepped, the framework will do something +val progressTracker: ProgressTracker

        Override this to provide a ProgressTracker. If one is provided and stepped, the framework will do something helpful with the progress reports. If this protocol is invoked as a sub-protocol of another, then the tracker will be made a child of the current step in the parent. If its null, this protocol doesnt track progress.

        @@ -49,30 +55,7 @@ progress.

        -replacementProgressTracker - -val replacementProgressTracker: ProgressTracker? - - - -

        Inherited Properties

        - - - - - - - - - - - - +sessionID @@ -85,19 +68,13 @@ progress.

        - - - - +fun assembleSharedTX(handshake: Handshake<StateRef>): <ERROR CLASS><TransactionBuilder, List<PublicKey>> +fun validateHandshake(handshake: Handshake<StateRef>): Handshake<StateRef>
        -notary -val notary: Party
        -otherSide -val otherSide: SingleMessageRecipient
        -sessionID val sessionID: Long
        assembleSharedTX -open fun assembleSharedTX(handshake: Handshake<StateRef>): <ERROR CLASS><TransactionBuilder, List<PublicKey>>
        -createTracker -fun createTracker(): ProgressTracker
        validateHandshake -open fun validateHandshake(handshake: Handshake<StateRef>): Handshake<StateRef>
        diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixer/initiation.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixer/initiation.html new file mode 100644 index 0000000000..9fc8fc0dc4 --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixer/initiation.html @@ -0,0 +1,15 @@ + + +TwoPartyDealProtocol.Fixer.initiation - + + + +com.r3corda.protocols / TwoPartyDealProtocol / Fixer / initiation
        +
        +

        initiation

        + +val initiation: FixingSessionInitiation
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixer/other-side.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixer/other-side.html new file mode 100644 index 0000000000..d405add903 --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixer/other-side.html @@ -0,0 +1,16 @@ + + +TwoPartyDealProtocol.Fixer.otherSide - + + + +com.r3corda.protocols / TwoPartyDealProtocol / Fixer / otherSide
        +
        +

        otherSide

        + +val otherSide: Party
        +Overrides Secondary.otherSide
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixer/progress-tracker.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixer/progress-tracker.html index 33f8c3fd18..a63acc54c2 100644 --- a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixer/progress-tracker.html +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixer/progress-tracker.html @@ -8,7 +8,7 @@

        progressTracker

        -open val progressTracker: ProgressTracker
        +val progressTracker: ProgressTracker
        Overrides Secondary.progressTracker

        Override this to provide a ProgressTracker. If one is provided and stepped, the framework will do something helpful with the progress reports. If this protocol is invoked as a sub-protocol of another, then the diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixer/session-i-d.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixer/session-i-d.html new file mode 100644 index 0000000000..fd38c048c4 --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixer/session-i-d.html @@ -0,0 +1,16 @@ + + +TwoPartyDealProtocol.Fixer.sessionID - + + + +com.r3corda.protocols / TwoPartyDealProtocol / Fixer / sessionID
        +
        +

        sessionID

        + +val sessionID: Long
        +Overrides Secondary.sessionID
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixer/validate-handshake.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixer/validate-handshake.html index 8455853d0d..b7d1c399a3 100644 --- a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixer/validate-handshake.html +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixer/validate-handshake.html @@ -8,7 +8,7 @@

        validateHandshake

        -protected open fun validateHandshake(handshake: Handshake<StateRef>): Handshake<StateRef>
        +protected fun validateHandshake(handshake: Handshake<StateRef>): Handshake<StateRef>


        diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-role-decider/-init-.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-role-decider/-init-.html new file mode 100644 index 0000000000..5feb5958c7 --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-role-decider/-init-.html @@ -0,0 +1,21 @@ + + +TwoPartyDealProtocol.FixingRoleDecider.<init> - + + + +com.r3corda.protocols / TwoPartyDealProtocol / FixingRoleDecider / <init>
        +
        +

        <init>

        +FixingRoleDecider(ref: StateRef, timeout: Duration, progressTracker: ProgressTracker = tracker(ref.toString()))
        +

        This protocol looks at the deal and decides whether to be the Fixer or Floater role in agreeing a fixing.

        +

        It is kicked off as an activity on both participant nodes by the scheduler when its time for a fixing. If the +Fixer role is chosen, then that will be initiated by the FixingSessionInitiation message sent from the other party and +handled by the FixingSessionInitiationHandler.

        +

        TODO: Replace FixingSessionInitiation and FixingSessionInitiationHandler with generic session initiation logic once it exists.

        +
        +
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-role-decider/-l-o-a-d-i-n-g/-init-.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-role-decider/-l-o-a-d-i-n-g/-init-.html new file mode 100644 index 0000000000..7f9e377edc --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-role-decider/-l-o-a-d-i-n-g/-init-.html @@ -0,0 +1,14 @@ + + +TwoPartyDealProtocol.FixingRoleDecider.LOADING.<init> - + + + +com.r3corda.protocols / TwoPartyDealProtocol / FixingRoleDecider / LOADING / <init>
        +
        +

        <init>

        +LOADING(ref: String)
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-role-decider/-l-o-a-d-i-n-g/index.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-role-decider/-l-o-a-d-i-n-g/index.html new file mode 100644 index 0000000000..94ab051357 --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-role-decider/-l-o-a-d-i-n-g/index.html @@ -0,0 +1,53 @@ + + +TwoPartyDealProtocol.FixingRoleDecider.LOADING - + + + +com.r3corda.protocols / TwoPartyDealProtocol / FixingRoleDecider / LOADING
        +
        +

        LOADING

        +class LOADING : Step
        +
        +
        +

        Constructors

        + + + + + + + +
        +<init> +LOADING(ref: String)
        +

        Inherited Properties

        + + + + + + + + + + + +
        +changes +open val changes: <ERROR CLASS><Change>
        +label +open val label: String
        +

        Inherited Functions

        + + + + + + + +
        +childProgressTracker +open fun childProgressTracker(): ProgressTracker?
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-role-decider/call.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-role-decider/call.html new file mode 100644 index 0000000000..99992db987 --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-role-decider/call.html @@ -0,0 +1,17 @@ + + +TwoPartyDealProtocol.FixingRoleDecider.call - + + + +com.r3corda.protocols / TwoPartyDealProtocol / FixingRoleDecider / call
        +
        +

        call

        + +fun call(): Unit
        +Overrides ProtocolLogic.call
        +

        This is where you fill out your business logic.

        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-role-decider/index.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-role-decider/index.html new file mode 100644 index 0000000000..16be54e476 --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-role-decider/index.html @@ -0,0 +1,154 @@ + + +TwoPartyDealProtocol.FixingRoleDecider - + + + +com.r3corda.protocols / TwoPartyDealProtocol / FixingRoleDecider
        +
        +

        FixingRoleDecider

        +class FixingRoleDecider : ProtocolLogic<Unit>
        +

        This protocol looks at the deal and decides whether to be the Fixer or Floater role in agreeing a fixing.

        +

        It is kicked off as an activity on both participant nodes by the scheduler when its time for a fixing. If the +Fixer role is chosen, then that will be initiated by the FixingSessionInitiation message sent from the other party and +handled by the FixingSessionInitiationHandler.

        +

        TODO: Replace FixingSessionInitiation and FixingSessionInitiationHandler with generic session initiation logic once it exists.

        +
        +
        +
        +
        +

        Types

        + + + + + + + +
        +LOADING +class LOADING : Step
        +

        Constructors

        + + + + + + + +
        +<init> +FixingRoleDecider(ref: StateRef, timeout: Duration, progressTracker: ProgressTracker = tracker(ref.toString()))

        This protocol looks at the deal and decides whether to be the Fixer or Floater role in agreeing a fixing.

        +
        +

        Properties

        + + + + + + + + + + + + + + + +
        +progressTracker +val progressTracker: ProgressTracker

        Override this to provide a ProgressTracker. If one is provided and stepped, the framework will do something +helpful with the progress reports. If this protocol is invoked as a sub-protocol of another, then the +tracker will be made a child of the current step in the parent. If its null, this protocol doesnt track +progress.

        +
        +ref +val ref: StateRef
        +timeout +val timeout: Duration
        +

        Inherited Properties

        + + + + + + + + + + + + + + + +
        +logger +val logger: <ERROR CLASS>

        This is where you should log things to.

        +
        +psm +lateinit var psm: ProtocolStateMachine<*>

        Reference to the Fiber instance that is the top level controller for the entire flow.

        +
        +serviceHub +val serviceHub: ServiceHub

        Provides access to big, heavy classes that may be reconstructed from time to time, e.g. across restarts. It is +only available once the protocol has started, which means it cannnot be accessed in the constructor. Either +access this lazily or from inside call.

        +
        +

        Functions

        + + + + + + + +
        +call +fun call(): Unit

        This is where you fill out your business logic.

        +
        +

        Inherited Functions

        + + + + + + + + + + + + + + + + + + + +
        +receive +fun <T : Any> receive(topic: String, sessionIDForReceive: Long, clazz: Class<T>): UntrustworthyData<T>
        +fun <T : Any> receive(topic: String, sessionIDForReceive: Long): UntrustworthyData<T>
        +send +fun send(topic: String, destination: Party, sessionID: Long, payload: Any): Unit
        +sendAndReceive +fun <T : Any> sendAndReceive(topic: String, destination: Party, sessionIDForSend: Long, sessionIDForReceive: Long, payload: Any): UntrustworthyData<T>
        +subProtocol +fun <R> subProtocol(subLogic: ProtocolLogic<R>): R

        Invokes the given subprotocol by simply passing through this ProtocolLogics reference to the +ProtocolStateMachine and then calling the call method.

        +
        +

        Companion Object Functions

        + + + + + + + +
        +tracker +fun tracker(ref: String): ProgressTracker
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-role-decider/progress-tracker.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-role-decider/progress-tracker.html new file mode 100644 index 0000000000..4ba805a381 --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-role-decider/progress-tracker.html @@ -0,0 +1,24 @@ + + +TwoPartyDealProtocol.FixingRoleDecider.progressTracker - + + + +com.r3corda.protocols / TwoPartyDealProtocol / FixingRoleDecider / progressTracker
        +
        +

        progressTracker

        + +val progressTracker: ProgressTracker
        +Overrides ProtocolLogic.progressTracker
        +

        Override this to provide a ProgressTracker. If one is provided and stepped, the framework will do something +helpful with the progress reports. If this protocol is invoked as a sub-protocol of another, then the +tracker will be made a child of the current step in the parent. If its null, this protocol doesnt track +progress.

        +

        Note that this has to return a tracker before the protocol is invoked. You cant change your mind half way +through.

        +
        +
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-role-decider/ref.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-role-decider/ref.html new file mode 100644 index 0000000000..a0c74f6677 --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-role-decider/ref.html @@ -0,0 +1,15 @@ + + +TwoPartyDealProtocol.FixingRoleDecider.ref - + + + +com.r3corda.protocols / TwoPartyDealProtocol / FixingRoleDecider / ref
        +
        +

        ref

        + +val ref: StateRef
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-role-decider/timeout.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-role-decider/timeout.html new file mode 100644 index 0000000000..06b1a050bb --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-role-decider/timeout.html @@ -0,0 +1,15 @@ + + +TwoPartyDealProtocol.FixingRoleDecider.timeout - + + + +com.r3corda.protocols / TwoPartyDealProtocol / FixingRoleDecider / timeout
        +
        +

        timeout

        + +val timeout: Duration
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-role-decider/tracker.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-role-decider/tracker.html new file mode 100644 index 0000000000..4c649b257b --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-role-decider/tracker.html @@ -0,0 +1,15 @@ + + +TwoPartyDealProtocol.FixingRoleDecider.tracker - + + + +com.r3corda.protocols / TwoPartyDealProtocol / FixingRoleDecider / tracker
        +
        +

        tracker

        + +fun tracker(ref: String): ProgressTracker
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-session-initiation/-init-.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-session-initiation/-init-.html new file mode 100644 index 0000000000..454587952e --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-session-initiation/-init-.html @@ -0,0 +1,15 @@ + + +TwoPartyDealProtocol.FixingSessionInitiation.<init> - + + + +com.r3corda.protocols / TwoPartyDealProtocol / FixingSessionInitiation / <init>
        +
        +

        <init>

        +FixingSessionInitiation(sessionID: Long, party: Party, sender: Party, timeout: Duration)
        +

        Used to set up the session between Floater and Fixer

        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-session-initiation/index.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-session-initiation/index.html new file mode 100644 index 0000000000..6bfd8781bc --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-session-initiation/index.html @@ -0,0 +1,56 @@ + + +TwoPartyDealProtocol.FixingSessionInitiation - + + + +com.r3corda.protocols / TwoPartyDealProtocol / FixingSessionInitiation
        +
        +

        FixingSessionInitiation

        +data class FixingSessionInitiation
        +

        Used to set up the session between Floater and Fixer

        +
        +
        +

        Constructors

        + + + + + + + +
        +<init> +FixingSessionInitiation(sessionID: Long, party: Party, sender: Party, timeout: Duration)

        Used to set up the session between Floater and Fixer

        +
        +

        Properties

        + + + + + + + + + + + + + + + + + + + +
        +party +val party: Party
        +sender +val sender: Party
        +sessionID +val sessionID: Long
        +timeout +val timeout: Duration
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-session-initiation/party.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-session-initiation/party.html new file mode 100644 index 0000000000..8a33b57054 --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-session-initiation/party.html @@ -0,0 +1,15 @@ + + +TwoPartyDealProtocol.FixingSessionInitiation.party - + + + +com.r3corda.protocols / TwoPartyDealProtocol / FixingSessionInitiation / party
        +
        +

        party

        + +val party: Party
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-session-initiation/sender.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-session-initiation/sender.html new file mode 100644 index 0000000000..18c06ea640 --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-session-initiation/sender.html @@ -0,0 +1,15 @@ + + +TwoPartyDealProtocol.FixingSessionInitiation.sender - + + + +com.r3corda.protocols / TwoPartyDealProtocol / FixingSessionInitiation / sender
        +
        +

        sender

        + +val sender: Party
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-session-initiation/session-i-d.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-session-initiation/session-i-d.html new file mode 100644 index 0000000000..d6d1b6c660 --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-session-initiation/session-i-d.html @@ -0,0 +1,15 @@ + + +TwoPartyDealProtocol.FixingSessionInitiation.sessionID - + + + +com.r3corda.protocols / TwoPartyDealProtocol / FixingSessionInitiation / sessionID
        +
        +

        sessionID

        + +val sessionID: Long
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-session-initiation/timeout.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-session-initiation/timeout.html new file mode 100644 index 0000000000..fa02141b99 --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-fixing-session-initiation/timeout.html @@ -0,0 +1,15 @@ + + +TwoPartyDealProtocol.FixingSessionInitiation.timeout - + + + +com.r3corda.protocols / TwoPartyDealProtocol / FixingSessionInitiation / timeout
        +
        +

        timeout

        + +val timeout: Duration
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-floater/-init-.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-floater/-init-.html index 62a0e13462..bbef5b3954 100644 --- a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-floater/-init-.html +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-floater/-init-.html @@ -7,7 +7,7 @@ com.r3corda.protocols / TwoPartyDealProtocol / Floater / <init>

        <init>

        -Floater(otherSide: SingleMessageRecipient, otherSessionID: Long, notary: NodeInfo, dealToFix: StateAndRef<T>, myKeyPair: KeyPair, sessionID: Long, progressTracker: ProgressTracker = Primary.tracker())
        +Floater(payload: StateRef, otherSessionID: Long, progressTracker: ProgressTracker = Primary.tracker())

        One side of the fixing protocol for an interest rate swap, but could easily be generalised furher

        As per the Fixer, do not infer too much from this class name in terms of business roles. This is just the "side" of the protocol run by the party with the floating leg as a way of deciding who diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-floater/index.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-floater/index.html index 4bb3535716..e6eddcfe2e 100644 --- a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-floater/index.html +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-floater/index.html @@ -7,7 +7,7 @@ com.r3corda.protocols / TwoPartyDealProtocol / Floater

        Floater

        -class Floater<T : FixableDealState> : Primary<StateRef>
        +class Floater : Primary<StateRef>

        One side of the fixing protocol for an interest rate swap, but could easily be generalised furher

        As per the Fixer, do not infer too much from this class name in terms of business roles. This is just the "side" of the protocol run by the party with the floating leg as a way of deciding who @@ -23,7 +23,7 @@ does what in the protocol.

        <init> -Floater(otherSide: SingleMessageRecipient, otherSessionID: Long, notary: NodeInfo, dealToFix: StateAndRef<T>, myKeyPair: KeyPair, sessionID: Long, progressTracker: ProgressTracker = Primary.tracker())

        One side of the fixing protocol for an interest rate swap, but could easily be generalised furher

        +Floater(payload: StateRef, otherSessionID: Long, progressTracker: ProgressTracker = Primary.tracker())

        One side of the fixing protocol for an interest rate swap, but could easily be generalised furher

        @@ -33,54 +33,43 @@ does what in the protocol.

        -progressTracker - -open val progressTracker: ProgressTracker

        Override this to provide a ProgressTracker. If one is provided and stepped, the framework will do something -helpful with the progress reports. If this protocol is invoked as a sub-protocol of another, then the -tracker will be made a child of the current step in the parent. If its null, this protocol doesnt track -progress.

        - - - - -sessionID - -val sessionID: Long - - - -

        Inherited Properties

        - - - - +myKeyPair +notaryNode +otherSessionID +otherSide +val otherSide: Party +payload +val payload: StateRef + + + +
        -myKeyPair val myKeyPair: KeyPair
        -notaryNode val notaryNode: NodeInfo
        -otherSessionID val otherSessionID: Long
        -otherSide -val otherSide: SingleMessageRecipient
        -payload -val payload: U
        +progressTracker +val progressTracker: ProgressTracker

        Override this to provide a ProgressTracker. If one is provided and stepped, the framework will do something +helpful with the progress reports. If this protocol is invoked as a sub-protocol of another, then the +tracker will be made a child of the current step in the parent. If its null, this protocol doesnt track +progress.

        +
        diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-floater/my-key-pair.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-floater/my-key-pair.html new file mode 100644 index 0000000000..464d66d738 --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-floater/my-key-pair.html @@ -0,0 +1,16 @@ + + +TwoPartyDealProtocol.Floater.myKeyPair - + + + +com.r3corda.protocols / TwoPartyDealProtocol / Floater / myKeyPair
        +
        +

        myKeyPair

        + +val myKeyPair: KeyPair
        +Overrides Primary.myKeyPair
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-floater/notary-node.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-floater/notary-node.html new file mode 100644 index 0000000000..af61914e72 --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-floater/notary-node.html @@ -0,0 +1,16 @@ + + +TwoPartyDealProtocol.Floater.notaryNode - + + + +com.r3corda.protocols / TwoPartyDealProtocol / Floater / notaryNode
        +
        +

        notaryNode

        + +val notaryNode: NodeInfo
        +Overrides Primary.notaryNode
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-floater/other-session-i-d.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-floater/other-session-i-d.html new file mode 100644 index 0000000000..e062563a0a --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-floater/other-session-i-d.html @@ -0,0 +1,16 @@ + + +TwoPartyDealProtocol.Floater.otherSessionID - + + + +com.r3corda.protocols / TwoPartyDealProtocol / Floater / otherSessionID
        +
        +

        otherSessionID

        + +val otherSessionID: Long
        +Overrides Primary.otherSessionID
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-floater/other-side.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-floater/other-side.html new file mode 100644 index 0000000000..c47e99850c --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-floater/other-side.html @@ -0,0 +1,16 @@ + + +TwoPartyDealProtocol.Floater.otherSide - + + + +com.r3corda.protocols / TwoPartyDealProtocol / Floater / otherSide
        +
        +

        otherSide

        + +val otherSide: Party
        +Overrides Primary.otherSide
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-floater/payload.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-floater/payload.html new file mode 100644 index 0000000000..4df7541209 --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-floater/payload.html @@ -0,0 +1,16 @@ + + +TwoPartyDealProtocol.Floater.payload - + + + +com.r3corda.protocols / TwoPartyDealProtocol / Floater / payload
        +
        +

        payload

        + +val payload: StateRef
        +Overrides Primary.payload
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-floater/progress-tracker.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-floater/progress-tracker.html index c4419152a7..a780ac13ea 100644 --- a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-floater/progress-tracker.html +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-floater/progress-tracker.html @@ -8,7 +8,7 @@

        progressTracker

        -open val progressTracker: ProgressTracker
        +val progressTracker: ProgressTracker
        Overrides Primary.progressTracker

        Override this to provide a ProgressTracker. If one is provided and stepped, the framework will do something helpful with the progress reports. If this protocol is invoked as a sub-protocol of another, then the diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-instigator/-init-.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-instigator/-init-.html index 11d9d64d5f..c8b5bb5929 100644 --- a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-instigator/-init-.html +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-instigator/-init-.html @@ -7,7 +7,7 @@ com.r3corda.protocols / TwoPartyDealProtocol / Instigator / <init>

        <init>

        -Instigator(otherSide: SingleMessageRecipient, notaryNode: NodeInfo, dealBeingOffered: T, myKeyPair: KeyPair, buyerSessionID: Long, progressTracker: ProgressTracker = Primary.tracker())
        +Instigator(otherSide: Party, notary: Party, payload: T, myKeyPair: KeyPair, otherSessionID: Long, progressTracker: ProgressTracker = Primary.tracker())

        One side of the protocol for inserting a pre-agreed deal.



        diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-instigator/index.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-instigator/index.html index 1b876b151f..5061804d91 100644 --- a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-instigator/index.html +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-instigator/index.html @@ -18,7 +18,7 @@ <init> -Instigator(otherSide: SingleMessageRecipient, notaryNode: NodeInfo, dealBeingOffered: T, myKeyPair: KeyPair, buyerSessionID: Long, progressTracker: ProgressTracker = Primary.tracker())

        One side of the protocol for inserting a pre-agreed deal.

        +Instigator(otherSide: Party, notary: Party, payload: T, myKeyPair: KeyPair, otherSessionID: Long, progressTracker: ProgressTracker = Primary.tracker())

        One side of the protocol for inserting a pre-agreed deal.

        @@ -28,6 +28,42 @@ +myKeyPair + +open val myKeyPair: KeyPair + + + +notary + +val notary: Party + + + +notaryNode + +open val notaryNode: NodeInfo + + + +otherSessionID + +open val otherSessionID: Long + + + +otherSide + +open val otherSide: Party + + + +payload + +open val payload: T + + + progressTracker open val progressTracker: ProgressTracker

        Override this to provide a ProgressTracker. If one is provided and stepped, the framework will do something @@ -38,41 +74,6 @@ progress.

        -

        Inherited Properties

        - - - - - - - - - - - - - - - - - - - - - - - -
        -myKeyPair -val myKeyPair: KeyPair
        -notaryNode -val notaryNode: NodeInfo
        -otherSessionID -val otherSessionID: Long
        -otherSide -val otherSide: SingleMessageRecipient
        -payload -val payload: U

        Inherited Functions

        diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-instigator/my-key-pair.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-instigator/my-key-pair.html new file mode 100644 index 0000000000..0aa8dac5c4 --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-instigator/my-key-pair.html @@ -0,0 +1,16 @@ + + +TwoPartyDealProtocol.Instigator.myKeyPair - + + + +com.r3corda.protocols / TwoPartyDealProtocol / Instigator / myKeyPair
        +
        +

        myKeyPair

        + +open val myKeyPair: KeyPair
        +Overrides Primary.myKeyPair
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-instigator/notary-node.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-instigator/notary-node.html new file mode 100644 index 0000000000..cd84317de2 --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-instigator/notary-node.html @@ -0,0 +1,16 @@ + + +TwoPartyDealProtocol.Instigator.notaryNode - + + + +com.r3corda.protocols / TwoPartyDealProtocol / Instigator / notaryNode
        +
        +

        notaryNode

        + +open val notaryNode: NodeInfo
        +Overrides Primary.notaryNode
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-instigator/notary.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-instigator/notary.html new file mode 100644 index 0000000000..9886189510 --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-instigator/notary.html @@ -0,0 +1,15 @@ + + +TwoPartyDealProtocol.Instigator.notary - + + + +com.r3corda.protocols / TwoPartyDealProtocol / Instigator / notary
        +
        +

        notary

        + +val notary: Party
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-instigator/other-session-i-d.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-instigator/other-session-i-d.html new file mode 100644 index 0000000000..5d557604bc --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-instigator/other-session-i-d.html @@ -0,0 +1,16 @@ + + +TwoPartyDealProtocol.Instigator.otherSessionID - + + + +com.r3corda.protocols / TwoPartyDealProtocol / Instigator / otherSessionID
        +
        +

        otherSessionID

        + +open val otherSessionID: Long
        +Overrides Primary.otherSessionID
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-instigator/other-side.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-instigator/other-side.html new file mode 100644 index 0000000000..4584fcae3d --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-instigator/other-side.html @@ -0,0 +1,16 @@ + + +TwoPartyDealProtocol.Instigator.otherSide - + + + +com.r3corda.protocols / TwoPartyDealProtocol / Instigator / otherSide
        +
        +

        otherSide

        + +open val otherSide: Party
        +Overrides Primary.otherSide
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-instigator/payload.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-instigator/payload.html new file mode 100644 index 0000000000..232e51a601 --- /dev/null +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-instigator/payload.html @@ -0,0 +1,16 @@ + + +TwoPartyDealProtocol.Instigator.payload - + + + +com.r3corda.protocols / TwoPartyDealProtocol / Instigator / payload
        +
        +

        payload

        + +open val payload: T
        +Overrides Primary.payload
        +
        +
        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-primary/-init-.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-primary/-init-.html index 1518b31109..c93ec61e33 100644 --- a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-primary/-init-.html +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-primary/-init-.html @@ -7,7 +7,7 @@ com.r3corda.protocols / TwoPartyDealProtocol / Primary / <init>

        <init>

        -Primary(payload: U, otherSide: SingleMessageRecipient, otherSessionID: Long, myKeyPair: KeyPair, notaryNode: NodeInfo, progressTracker: ProgressTracker = Primary.tracker())
        +Primary(progressTracker: ProgressTracker = Primary.tracker())

        Abstracted bilateral deal protocol participant that initiates communication/handshake.

        Theres a good chance we can push at least some of this logic down into core protocol logic and helper methods etc.

        diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-primary/index.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-primary/index.html index 0661879436..670f42ecef 100644 --- a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-primary/index.html +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-primary/index.html @@ -69,7 +69,7 @@ and helper methods etc.

        @@ -81,31 +81,31 @@ and helper methods etc.

        +abstract val myKeyPair: KeyPair +abstract val notaryNode: NodeInfo +abstract val otherSessionID: Long +abstract val otherSide: Party +abstract val payload: U @@ -182,20 +184,20 @@ progress.

        +fun <T : Any> receive(topic: String, sessionIDForReceive: Long, clazz: Class<T>): UntrustworthyData<T>
        +fun <T : Any> receive(topic: String, sessionIDForReceive: Long): UntrustworthyData<T> +fun send(topic: String, destination: Party, sessionID: Long, payload: Any): Unit +fun <T : Any> sendAndReceive(topic: String, destination: Party, sessionIDForSend: Long, sessionIDForReceive: Long, payload: Any): UntrustworthyData<T> diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-primary/my-key-pair.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-primary/my-key-pair.html index e7b70fcb20..c94f0a621f 100644 --- a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-primary/my-key-pair.html +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-primary/my-key-pair.html @@ -8,7 +8,7 @@

        myKeyPair

        -val myKeyPair: KeyPair
        +abstract val myKeyPair: KeyPair


        diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-primary/notary-node.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-primary/notary-node.html index 6d7aa9f5b4..08ddd62297 100644 --- a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-primary/notary-node.html +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-primary/notary-node.html @@ -8,7 +8,7 @@

        notaryNode

        -val notaryNode: NodeInfo
        +abstract val notaryNode: NodeInfo


        diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-primary/other-session-i-d.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-primary/other-session-i-d.html index 3d70279932..a2461eed60 100644 --- a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-primary/other-session-i-d.html +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-primary/other-session-i-d.html @@ -8,7 +8,7 @@

        otherSessionID

        -val otherSessionID: Long
        +abstract val otherSessionID: Long


        diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-primary/other-side.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-primary/other-side.html index bc504c33f7..595f90926b 100644 --- a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-primary/other-side.html +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-primary/other-side.html @@ -8,7 +8,7 @@

        otherSide

        -val otherSide: SingleMessageRecipient
        +abstract val otherSide: Party


        diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-primary/payload.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-primary/payload.html index d13eb47669..7227e9f884 100644 --- a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-primary/payload.html +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-primary/payload.html @@ -8,7 +8,7 @@

        payload

        -val payload: U
        +abstract val payload: U


        diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-secondary/-init-.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-secondary/-init-.html index 96a6112082..bd12a06009 100644 --- a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-secondary/-init-.html +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-secondary/-init-.html @@ -7,7 +7,7 @@ com.r3corda.protocols / TwoPartyDealProtocol / Secondary / <init>

        <init>

        -Secondary(otherSide: SingleMessageRecipient, notary: Party, sessionID: Long, progressTracker: ProgressTracker = Secondary.tracker())
        +Secondary(progressTracker: ProgressTracker = Secondary.tracker())

        Abstracted bilateral deal protocol participant that is recipient of initial communication.

        Theres a good chance we can push at least some of this logic down into core protocol logic and helper methods etc.

        diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-secondary/index.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-secondary/index.html index 523de25156..47e4729817 100644 --- a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-secondary/index.html +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-secondary/index.html @@ -57,7 +57,7 @@ and helper methods etc.

        @@ -67,15 +67,9 @@ and helper methods etc.

        - - - - +abstract val otherSide: Party +abstract val sessionID: Long
        <init> -Primary(payload: U, otherSide: SingleMessageRecipient, otherSessionID: Long, myKeyPair: KeyPair, notaryNode: NodeInfo, progressTracker: ProgressTracker = Primary.tracker())

        Abstracted bilateral deal protocol participant that initiates communication/handshake.

        +Primary(progressTracker: ProgressTracker = Primary.tracker())

        Abstracted bilateral deal protocol participant that initiates communication/handshake.

        myKeyPair -val myKeyPair: KeyPair
        notaryNode -val notaryNode: NodeInfo
        otherSessionID -val otherSessionID: Long
        otherSide -val otherSide: SingleMessageRecipient
        payload -val payload: U
        @@ -140,7 +140,9 @@ progress.

        serviceHub -val serviceHub: ServiceHub

        Provides access to big, heavy classes that may be reconstructed from time to time, e.g. across restarts

        +val serviceHub: ServiceHub

        Provides access to big, heavy classes that may be reconstructed from time to time, e.g. across restarts. It is +only available once the protocol has started, which means it cannnot be accessed in the constructor. Either +access this lazily or from inside call.

        receive -fun <T : Any> receive(topic: String, sessionIDForReceive: Long): UntrustworthyData<T>
        -fun <T : Any> receive(topic: String, sessionIDForReceive: Long, clazz: Class<T>): UntrustworthyData<T>
        send -fun send(topic: String, destination: MessageRecipients, sessionID: Long, obj: Any): Unit
        sendAndReceive -fun <T : Any> sendAndReceive(topic: String, destination: MessageRecipients, sessionIDForSend: Long, sessionIDForReceive: Long, obj: Any): UntrustworthyData<T>
        @@ -225,7 +227,7 @@ progress.

        Floater -class Floater<T : FixableDealState> : Primary<StateRef>

        One side of the fixing protocol for an interest rate swap, but could easily be generalised furher

        +class Floater : Primary<StateRef>

        One side of the fixing protocol for an interest rate swap, but could easily be generalised furher

        <init> -Secondary(otherSide: SingleMessageRecipient, notary: Party, sessionID: Long, progressTracker: ProgressTracker = Secondary.tracker())

        Abstracted bilateral deal protocol participant that is recipient of initial communication.

        +Secondary(progressTracker: ProgressTracker = Secondary.tracker())

        Abstracted bilateral deal protocol participant that is recipient of initial communication.

        -notary -val notary: Party
        otherSide -val otherSide: SingleMessageRecipient
        @@ -91,7 +85,7 @@ progress.

        sessionID -val sessionID: Long
        @@ -116,7 +110,9 @@ progress.

        serviceHub -val serviceHub: ServiceHub

        Provides access to big, heavy classes that may be reconstructed from time to time, e.g. across restarts

        +val serviceHub: ServiceHub

        Provides access to big, heavy classes that may be reconstructed from time to time, e.g. across restarts. It is +only available once the protocol has started, which means it cannnot be accessed in the constructor. Either +access this lazily or from inside call.

        @@ -159,13 +155,13 @@ progress.

        send -fun send(topic: String, destination: MessageRecipients, sessionID: Long, obj: Any): Unit +fun send(topic: String, destination: Party, sessionID: Long, payload: Any): Unit sendAndReceive -fun <T : Any> sendAndReceive(topic: String, destination: MessageRecipients, sessionIDForSend: Long, sessionIDForReceive: Long, obj: Any): UntrustworthyData<T> +fun <T : Any> sendAndReceive(topic: String, destination: Party, sessionIDForSend: Long, sessionIDForReceive: Long, payload: Any): UntrustworthyData<T> @@ -202,7 +198,7 @@ progress.

        Fixer -class Fixer<T : FixableDealState> : Secondary<StateRef>

        One side of the fixing protocol for an interest rate swap, but could easily be generalised further.

        +class Fixer : Secondary<StateRef>

        One side of the fixing protocol for an interest rate swap, but could easily be generalised further.

        diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-secondary/other-side.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-secondary/other-side.html index 11afc2a59a..8c4a359e84 100644 --- a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-secondary/other-side.html +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-secondary/other-side.html @@ -8,7 +8,7 @@

        otherSide

        -val otherSide: SingleMessageRecipient
        +abstract val otherSide: Party


        diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-secondary/session-i-d.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-secondary/session-i-d.html index 9ddba69295..bf371642bd 100644 --- a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-secondary/session-i-d.html +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/-secondary/session-i-d.html @@ -8,7 +8,7 @@

        sessionID

        -val sessionID: Long
        +abstract val sessionID: Long


        diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/index.html b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/index.html index babad0437d..88bc1a28e3 100644 --- a/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/index.html +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-deal-protocol/index.html @@ -11,6 +11,7 @@

        Classes for manipulating a two party deal or agreement.

        TODO: The subclasses should probably be broken out into individual protocols rather than making this an ever expanding collection of subclasses.

        TODO: Also, the term Deal is used here where we might prefer Agreement.

        +

        TODO: Consider whether we can merge this with TwoPartyTradeProtocol




        @@ -29,14 +30,28 @@ Fixer -class Fixer<T : FixableDealState> : Secondary<StateRef>

        One side of the fixing protocol for an interest rate swap, but could easily be generalised further.

        +class Fixer : Secondary<StateRef>

        One side of the fixing protocol for an interest rate swap, but could easily be generalised further.

        + + + + +FixingRoleDecider + +class FixingRoleDecider : ProtocolLogic<Unit>

        This protocol looks at the deal and decides whether to be the Fixer or Floater role in agreeing a fixing.

        + + + + +FixingSessionInitiation + +data class FixingSessionInitiation

        Used to set up the session between Floater and Fixer

        Floater -class Floater<T : FixableDealState> : Primary<StateRef>

        One side of the fixing protocol for an interest rate swap, but could easily be generalised furher

        +class Floater : Primary<StateRef>

        One side of the fixing protocol for an interest rate swap, but could easily be generalised furher

        @@ -100,6 +115,13 @@ val DEAL_TOPIC: String + + +FIX_INITIATE_TOPIC + +val FIX_INITIATE_TOPIC: String

        This topic exists purely for FixingSessionInitiation to be sent from FixingRoleDecider to FixingSessionInitiationHandler

        + + diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-buyer/-init-.html b/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-buyer/-init-.html index d5b8dcf697..42f6a1c778 100644 --- a/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-buyer/-init-.html +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-buyer/-init-.html @@ -7,7 +7,7 @@ com.r3corda.protocols / TwoPartyTradeProtocol / Buyer / <init>

        <init>

        -Buyer(otherSide: SingleMessageRecipient, notary: Party, acceptablePrice: Amount<Currency>, typeToBuy: Class<out OwnableState>, sessionID: Long)
        +Buyer(otherSide: Party, notary: Party, acceptablePrice: Amount<Issued<Currency>>, typeToBuy: Class<out OwnableState>, sessionID: Long)


        diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-buyer/acceptable-price.html b/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-buyer/acceptable-price.html index e1a2083a67..7ba69e7380 100644 --- a/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-buyer/acceptable-price.html +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-buyer/acceptable-price.html @@ -8,7 +8,7 @@

        acceptablePrice

        -val acceptablePrice: Amount<Currency>
        +val acceptablePrice: Amount<Issued<Currency>>


        diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-buyer/index.html b/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-buyer/index.html index 9e6e88bf08..05a4e72b6b 100644 --- a/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-buyer/index.html +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-buyer/index.html @@ -46,7 +46,7 @@ <init> -Buyer(otherSide: SingleMessageRecipient, notary: Party, acceptablePrice: Amount<Currency>, typeToBuy: Class<out OwnableState>, sessionID: Long) +Buyer(otherSide: Party, notary: Party, acceptablePrice: Amount<Issued<Currency>>, typeToBuy: Class<out OwnableState>, sessionID: Long) @@ -57,7 +57,7 @@ acceptablePrice -val acceptablePrice: Amount<Currency> +val acceptablePrice: Amount<Issued<Currency>> @@ -69,7 +69,7 @@ otherSide -val otherSide: SingleMessageRecipient +val otherSide: Party @@ -116,7 +116,9 @@ progress.

        serviceHub -val serviceHub: ServiceHub

        Provides access to big, heavy classes that may be reconstructed from time to time, e.g. across restarts

        +val serviceHub: ServiceHub

        Provides access to big, heavy classes that may be reconstructed from time to time, e.g. across restarts. It is +only available once the protocol has started, which means it cannnot be accessed in the constructor. Either +access this lazily or from inside call.

        @@ -147,13 +149,13 @@ progress.

        send -fun send(topic: String, destination: MessageRecipients, sessionID: Long, obj: Any): Unit +fun send(topic: String, destination: Party, sessionID: Long, payload: Any): Unit sendAndReceive -fun <T : Any> sendAndReceive(topic: String, destination: MessageRecipients, sessionIDForSend: Long, sessionIDForReceive: Long, obj: Any): UntrustworthyData<T> +fun <T : Any> sendAndReceive(topic: String, destination: Party, sessionIDForSend: Long, sessionIDForReceive: Long, payload: Any): UntrustworthyData<T> diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-buyer/other-side.html b/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-buyer/other-side.html index 30088a885a..fa91b79a4e 100644 --- a/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-buyer/other-side.html +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-buyer/other-side.html @@ -8,7 +8,7 @@

        otherSide

        -val otherSide: SingleMessageRecipient
        +val otherSide: Party


        diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-seller-trade-info/-init-.html b/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-seller-trade-info/-init-.html index b3cc785c84..689672cbf2 100644 --- a/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-seller-trade-info/-init-.html +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-seller-trade-info/-init-.html @@ -7,7 +7,7 @@ com.r3corda.protocols / TwoPartyTradeProtocol / SellerTradeInfo / <init>

        <init>

        -SellerTradeInfo(assetForSale: StateAndRef<OwnableState>, price: Amount<Currency>, sellerOwnerKey: PublicKey, sessionID: Long)
        +SellerTradeInfo(assetForSale: StateAndRef<OwnableState>, price: Amount<Issued<Currency>>, sellerOwnerKey: PublicKey, sessionID: Long)


        diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-seller-trade-info/index.html b/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-seller-trade-info/index.html index d3d152ecbb..43c71824c3 100644 --- a/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-seller-trade-info/index.html +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-seller-trade-info/index.html @@ -17,7 +17,7 @@ <init> -SellerTradeInfo(assetForSale: StateAndRef<OwnableState>, price: Amount<Currency>, sellerOwnerKey: PublicKey, sessionID: Long) +SellerTradeInfo(assetForSale: StateAndRef<OwnableState>, price: Amount<Issued<Currency>>, sellerOwnerKey: PublicKey, sessionID: Long) @@ -34,7 +34,7 @@ price -val price: Amount<Currency> +val price: Amount<Issued<Currency>> diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-seller-trade-info/price.html b/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-seller-trade-info/price.html index 84ec81d400..9ecd3cdb4b 100644 --- a/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-seller-trade-info/price.html +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-seller-trade-info/price.html @@ -8,7 +8,7 @@

        price

        -val price: Amount<Currency>
        +val price: Amount<Issued<Currency>>


        diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-seller/-init-.html b/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-seller/-init-.html index 4e85346803..d385bb3b43 100644 --- a/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-seller/-init-.html +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-seller/-init-.html @@ -7,7 +7,7 @@ com.r3corda.protocols / TwoPartyTradeProtocol / Seller / <init>

        <init>

        -Seller(otherSide: SingleMessageRecipient, notaryNode: NodeInfo, assetToSell: StateAndRef<OwnableState>, price: Amount<Currency>, myKeyPair: KeyPair, buyerSessionID: Long, progressTracker: ProgressTracker = Seller.tracker())
        +Seller(otherSide: Party, notaryNode: NodeInfo, assetToSell: StateAndRef<OwnableState>, price: Amount<Issued<Currency>>, myKeyPair: KeyPair, buyerSessionID: Long, progressTracker: ProgressTracker = Seller.tracker())


        diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-seller/index.html b/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-seller/index.html index 73f32472d1..5c6f54067d 100644 --- a/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-seller/index.html +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-seller/index.html @@ -52,7 +52,7 @@ <init> -Seller(otherSide: SingleMessageRecipient, notaryNode: NodeInfo, assetToSell: StateAndRef<OwnableState>, price: Amount<Currency>, myKeyPair: KeyPair, buyerSessionID: Long, progressTracker: ProgressTracker = Seller.tracker()) +Seller(otherSide: Party, notaryNode: NodeInfo, assetToSell: StateAndRef<OwnableState>, price: Amount<Issued<Currency>>, myKeyPair: KeyPair, buyerSessionID: Long, progressTracker: ProgressTracker = Seller.tracker()) @@ -87,13 +87,13 @@ otherSide -val otherSide: SingleMessageRecipient +val otherSide: Party price -val price: Amount<Currency> +val price: Amount<Issued<Currency>> @@ -128,7 +128,9 @@ progress.

        serviceHub -val serviceHub: ServiceHub

        Provides access to big, heavy classes that may be reconstructed from time to time, e.g. across restarts

        +val serviceHub: ServiceHub

        Provides access to big, heavy classes that may be reconstructed from time to time, e.g. across restarts. It is +only available once the protocol has started, which means it cannnot be accessed in the constructor. Either +access this lazily or from inside call.

        @@ -165,13 +167,13 @@ progress.

        send -fun send(topic: String, destination: MessageRecipients, sessionID: Long, obj: Any): Unit +fun send(topic: String, destination: Party, sessionID: Long, payload: Any): Unit sendAndReceive -fun <T : Any> sendAndReceive(topic: String, destination: MessageRecipients, sessionIDForSend: Long, sessionIDForReceive: Long, obj: Any): UntrustworthyData<T> +fun <T : Any> sendAndReceive(topic: String, destination: Party, sessionIDForSend: Long, sessionIDForReceive: Long, payload: Any): UntrustworthyData<T> diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-seller/other-side.html b/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-seller/other-side.html index e9ee3bbb75..2888cdfb72 100644 --- a/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-seller/other-side.html +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-seller/other-side.html @@ -8,7 +8,7 @@

        otherSide

        -val otherSide: SingleMessageRecipient
        +val otherSide: Party


        diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-seller/price.html b/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-seller/price.html index b0d265cb45..5e91b02f9b 100644 --- a/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-seller/price.html +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-seller/price.html @@ -8,7 +8,7 @@

        price

        -val price: Amount<Currency>
        +val price: Amount<Issued<Currency>>


        diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-unacceptable-price-exception/-init-.html b/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-unacceptable-price-exception/-init-.html index 1ef7a02902..a091a830a5 100644 --- a/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-unacceptable-price-exception/-init-.html +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-unacceptable-price-exception/-init-.html @@ -7,7 +7,7 @@ com.r3corda.protocols / TwoPartyTradeProtocol / UnacceptablePriceException / <init>

        <init>

        -UnacceptablePriceException(givenPrice: Amount<Currency>)
        +UnacceptablePriceException(givenPrice: Amount<Issued<Currency>>)


        diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-unacceptable-price-exception/given-price.html b/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-unacceptable-price-exception/given-price.html index 8c15078950..9d05c61721 100644 --- a/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-unacceptable-price-exception/given-price.html +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-unacceptable-price-exception/given-price.html @@ -8,7 +8,7 @@

        givenPrice

        -val givenPrice: Amount<Currency>
        +val givenPrice: Amount<Issued<Currency>>


        diff --git a/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-unacceptable-price-exception/index.html b/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-unacceptable-price-exception/index.html index e27ae2f1e3..433ec403d0 100644 --- a/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-unacceptable-price-exception/index.html +++ b/docs/build/html/api/com.r3corda.protocols/-two-party-trade-protocol/-unacceptable-price-exception/index.html @@ -17,7 +17,7 @@ <init> -UnacceptablePriceException(givenPrice: Amount<Currency>) +UnacceptablePriceException(givenPrice: Amount<Issued<Currency>>) @@ -28,7 +28,7 @@ givenPrice -val givenPrice: Amount<Currency> +val givenPrice: Amount<Issued<Currency>> diff --git a/docs/build/html/api/com.r3corda.protocols/-validating-notary-protocol/-init-.html b/docs/build/html/api/com.r3corda.protocols/-validating-notary-protocol/-init-.html index 8d5d76caa4..1f554c88d0 100644 --- a/docs/build/html/api/com.r3corda.protocols/-validating-notary-protocol/-init-.html +++ b/docs/build/html/api/com.r3corda.protocols/-validating-notary-protocol/-init-.html @@ -7,7 +7,7 @@ com.r3corda.protocols / ValidatingNotaryProtocol / <init>

        <init>

        -ValidatingNotaryProtocol(otherSide: SingleMessageRecipient, sessionIdForSend: Long, sessionIdForReceive: Long, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider)
        +ValidatingNotaryProtocol(otherSide: Party, sessionIdForSend: Long, sessionIdForReceive: Long, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider)

        A notary commit protocol that makes sure a given transaction is valid before committing it. This does mean that the calling party has to reveal the whole transaction history; however, we avoid complex conflict resolution logic where a party has its input states "blocked" by a transaction from another party, and needs to establish whether that transaction was diff --git a/docs/build/html/api/com.r3corda.protocols/-validating-notary-protocol/before-commit.html b/docs/build/html/api/com.r3corda.protocols/-validating-notary-protocol/before-commit.html index eb68331e99..91af00cc44 100644 --- a/docs/build/html/api/com.r3corda.protocols/-validating-notary-protocol/before-commit.html +++ b/docs/build/html/api/com.r3corda.protocols/-validating-notary-protocol/before-commit.html @@ -7,8 +7,8 @@ com.r3corda.protocols / ValidatingNotaryProtocol / beforeCommit

        beforeCommit

        - -fun beforeCommit(wtx: WireTransaction, reqIdentity: Party): Unit
        + +fun beforeCommit(stx: SignedTransaction, reqIdentity: Party): Unit
        Overrides Service.beforeCommit

        No pre-commit processing is done. Transaction is not checked for contract-validity, as that would require fully resolving it into a TransactionForVerification, for which the caller would have to reveal the whole transaction diff --git a/docs/build/html/api/com.r3corda.protocols/-validating-notary-protocol/index.html b/docs/build/html/api/com.r3corda.protocols/-validating-notary-protocol/index.html index d9ee826e6b..13e1f6b4ba 100644 --- a/docs/build/html/api/com.r3corda.protocols/-validating-notary-protocol/index.html +++ b/docs/build/html/api/com.r3corda.protocols/-validating-notary-protocol/index.html @@ -21,7 +21,7 @@ indeed valid

        <init> -ValidatingNotaryProtocol(otherSide: SingleMessageRecipient, sessionIdForSend: Long, sessionIdForReceive: Long, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider)

        A notary commit protocol that makes sure a given transaction is valid before committing it. This does mean that the calling +ValidatingNotaryProtocol(otherSide: Party, sessionIdForSend: Long, sessionIdForReceive: Long, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider)

        A notary commit protocol that makes sure a given transaction is valid before committing it. This does mean that the calling party has to reveal the whole transaction history; however, we avoid complex conflict resolution logic where a party has its input states "blocked" by a transaction from another party, and needs to establish whether that transaction was indeed valid

        @@ -36,7 +36,7 @@ indeed valid

        otherSide -val otherSide: SingleMessageRecipient +val otherSide: Party @@ -71,7 +71,7 @@ indeed valid

        beforeCommit -fun beforeCommit(wtx: WireTransaction, reqIdentity: Party): Unit

        No pre-commit processing is done. Transaction is not checked for contract-validity, as that would require fully +fun beforeCommit(stx: SignedTransaction, reqIdentity: Party): Unit

        No pre-commit processing is done. Transaction is not checked for contract-validity, as that would require fully resolving it into a TransactionForVerification, for which the caller would have to reveal the whole transaction history chain. As a result, the Notary will commit invalid transactions as well, but as it also records the identity of diff --git a/docs/build/html/api/com.r3corda.protocols/index.html b/docs/build/html/api/com.r3corda.protocols/index.html index 297b9f4842..d2e75c1af2 100644 --- a/docs/build/html/api/com.r3corda.protocols/index.html +++ b/docs/build/html/api/com.r3corda.protocols/index.html @@ -14,9 +14,7 @@ AbstractRequestMessage -abstract class AbstractRequestMessage

        Abstract superclass for request messages sent to services, which includes common -fields such as replyTo and replyToTopic.

        - +abstract class AbstractRequestMessage : ServiceRequestMessage @@ -73,6 +71,14 @@ all the transactions have been successfully verified and inserted into the local +ServiceRequestMessage + +interface ServiceRequestMessage

        Abstract superclass for request messages sent to services, which includes common +fields such as replyTo and replyToTopic.

        + + + + TwoPartyDealProtocol object TwoPartyDealProtocol

        Classes for manipulating a two party deal or agreement.

        diff --git a/docs/build/html/api/index-outline.html b/docs/build/html/api/index-outline.html index 4abfafadb5..47fae3e3ca 100644 --- a/docs/build/html/api/index-outline.html +++ b/docs/build/html/api/index-outline.html @@ -56,13 +56,14 @@ abstract fun buildTransaction(type: ContractDefRef, steps: List<TransactionBuildStep>): SerializedBytes<WireTransaction>
        abstract fun commitTransaction(tx: SerializedBytes<WireTransaction>, signatures: List<WithKey>): SecureHash
        abstract fun fetchProtocolsRequiringAttention(query: StatesQuery): Map<StateRef, ProtocolRequiringAttention>
        -abstract fun fetchStates(states: List<StateRef>): Map<StateRef, ContractState?>
        +abstract fun fetchStates(states: List<StateRef>): Map<StateRef, TransactionState<ContractState>?>
        abstract fun fetchTransactions(txs: List<SecureHash>): Map<SecureHash, SignedTransaction?>
        abstract fun generateTransactionSignature(tx: SerializedBytes<WireTransaction>): WithKey
        abstract fun invokeProtocolSync(type: ProtocolRef, args: Map<String, Any?>): Any?
        abstract fun provideProtocolResponse(protocol: ProtocolInstanceRef, choice: SecureHash, args: Map<String, Any?>): Unit
        abstract fun queryStates(query: StatesQuery): List<StateRef>
        abstract fun serverTime(): LocalDateTime
        +abstract fun status(): <ERROR CLASS>
      @@ -78,7 +79,7 @@ fun buildTransaction(type: ContractDefRef, steps: List<TransactionBuildStep>): SerializedBytes<WireTransaction>
      fun commitTransaction(tx: SerializedBytes<WireTransaction>, signatures: List<WithKey>): SecureHash
      fun fetchProtocolsRequiringAttention(query: StatesQuery): Map<StateRef, ProtocolRequiringAttention>
      -fun fetchStates(states: List<StateRef>): Map<StateRef, ContractState?>
      +fun fetchStates(states: List<StateRef>): Map<StateRef, TransactionState<ContractState>?>
      fun fetchTransactions(txs: List<SecureHash>): Map<SecureHash, SignedTransaction?>
      fun generateTransactionSignature(tx: SerializedBytes<WireTransaction>): WithKey
      fun invokeProtocolSync(type: ProtocolRef, args: Map<String, Any?>): Any?
      @@ -86,6 +87,7 @@ fun provideProtocolResponse(protocol: ProtocolInstanceRef, choice: SecureHash, args: Map<String, Any?>): Unit
      fun queryStates(query: StatesQuery): List<StateRef>
      fun serverTime(): LocalDateTime
      +fun status(): <ERROR CLASS>
    @@ -106,14 +108,15 @@ lateinit var checkpointStorage: CheckpointStorage
    val configuration: NodeConfiguration
    protected open fun constructStorageService(attachments: NodeAttachmentService, transactionStorage: TransactionStorage, keypair: KeyPair, identity: Party): StorageServiceImpl
    +protected fun createNodeDir(): Unit
    val dir: Path
    open fun findMyLocation(): PhysicalLocation?
    -protected open fun generateKeyPair(): KeyPair
    +protected open fun generateKeyPair(): <ERROR CLASS>
    lateinit var identity: IdentityService
    var inNodeNetworkMapService: NetworkMapService?
    var inNodeNotaryService: NotaryService?
    val info: NodeInfo
    -protected open fun initialiseStorageService(dir: Path): <ERROR CLASS><StorageService, CheckpointStorage>
    +protected open fun initialiseStorageService(dir: Path): <ERROR CLASS><TxWritableStorageService, CheckpointStorage>
    lateinit var interestRatesService: Service
    var isPreviousCheckpointsPresent: Boolean
    lateinit var keyManagement: E2ETestKeyManagementService
    @@ -130,20 +133,22 @@ val networkMapService: NodeInfo?
    protected open fun noNetworkMapConfigured(): <ERROR CLASS><Unit>
    val platformClock: Clock
    +lateinit var scheduler: SchedulerService
    protected abstract val serverThread: AffinityExecutor
    val services: ServiceHubInternal
    val servicesThatAcceptUploads: List<AcceptsFileUpload>
    +open fun setup(): AbstractNode
    lateinit var smm: StateMachineManager
    open fun start(): AbstractNode
    protected abstract fun startMessagingService(): Unit
    var started: Boolean
    open fun stop(): Unit
    -lateinit var storage: StorageService
    +lateinit var storage: TxWritableStorageService
    lateinit var wallet: WalletService
-abstract class AbstractNodeService
+abstract class AbstractNodeService : SingletonSerializeAsToken
-abstract class AbstractRequestMessage
+abstract class AbstractRequestMessage : ServiceRequestMessage
+abstract class AbstractStateReplacementProtocol<T>
+ @@ -181,16 +286,21 @@ AbstractTransactionForTest()
-fun arg(vararg key: PublicKey, c: () -> CommandData): Unit
+fun addCommand(cmd: Command): Unit
+fun arg(vararg keys: PublicKey, c: () -> CommandData): Unit
+fun arg(key: PublicKey, c: CommandData): Unit
fun attachment(attachmentID: SecureHash): Unit
protected val attachments: ArrayList<SecureHash>
protected val commands: ArrayList<Command>
protected fun commandsToAuthenticatedObjects(): List<AuthenticatedObject<CommandData>>
protected val outStates: ArrayList<LabeledOutput>
open fun output(label: String? = null, s: () -> ContractState): <ERROR CLASS>
+open fun output(label: String? = null, s: ContractState): <ERROR CLASS>
+protected val signers: LinkedHashSet<PublicKey>
fun timestamp(time: Instant): Unit
fun timestamp(data: TimestampCommand): Unit
-fun transaction(body: TransactionForTest.() -> Unit): Unit
+fun transaction(body: TransactionForTest.() -> LastLineShouldTestForAcceptOrFailure): Unit
+protected val type: General
@@ -221,6 +331,7 @@ +object Ack : DeserializeAsKotlinObjectDef
enum class AddOrRemove
    @@ -283,6 +394,20 @@
interface AllPossibleRecipients : MessageRecipients
+class AlwaysSucceedContract : Contract
+ data class Amount<T> : Comparable<Amount<T>>
    @@ -306,6 +431,20 @@
+data class AppContext
+ class ArtemisMessagingService : SingletonSerializeAsToken, MessagingService
    @@ -348,19 +487,6 @@
-interface AssetIssuanceDefinition<T> : IssuanceDefinition
- interface Attachment : NamedByHash
@@ -509,7 +636,7 @@ -class Requester<T> : ProtocolLogic<SignedTransaction>
+class Requester : ProtocolLogic<SignedTransaction>
    @@ -544,6 +671,19 @@
+interface BilateralNettableState<T : BilateralNettableState<T>>
+ class BriefLogFormatter : Formatter
    @@ -599,7 +739,7 @@
-class Cash : FungibleAsset<Currency>
+class Cash : FungibleAsset<Currency>
@@ -753,6 +884,107 @@ +sealed class CliParams
+ +object CliParamsSpec
+ data class Command
-fun generateIssue(issuance: PartyAndReference, faceValue: Amount<Currency>, maturityDate: Instant, notary: Party): TransactionBuilder
+fun generateIssue(faceValue: Amount<Issued<Currency>>, maturityDate: Instant, notary: Party): TransactionBuilder
fun generateMove(tx: TransactionBuilder, paper: StateAndRef<State>, newOwner: PublicKey): Unit
-fun generateRedeem(tx: TransactionBuilder, paper: StateAndRef<State>, wallet: List<StateAndRef<State>>): Unit
+fun generateRedeem(tx: TransactionBuilder, paper: StateAndRef<State>, wallet: List<StateAndRef<State>>): Unit
val legalContractReference: SecureHash
-fun verify(tx: TransactionForVerification): Unit
+fun verify(tx: TransactionForContract): Unit
@@ -895,7 +1127,7 @@ abstract val legalContractReference: SecureHash
-abstract fun verify(tx: TransactionForVerification): Unit
+abstract fun verify(tx: TransactionForContract): Unit
@@ -935,7 +1167,7 @@ abstract val contract: Contract
-abstract val notary: Party
+abstract val participants: List<PublicKey>
@@ -974,24 +1206,11 @@ -DataVendingService(net: MessagingService, storage: StorageService)
+DataVendingService(net: MessagingService, storage: StorageService, networkMapCache: NetworkMapCache)
val logger: <ERROR CLASS>
-enum class DateOffset
- enum class DateRollConvention
+interface DeserializeAsKotlinObjectDef
open class DigitalSignature : OpaqueBytes
    @@ -1232,10 +1452,7 @@
- - - -class State : ContractState
+class Move : TypeOnlyCommandData, Commands
+ + + +data class MultiOwnerState : ContractState, State
+ +data class SingleOwnerState : OwnableState, State
+ +interface State : ContractState
+ fun generateInitial(owner: PartyAndReference, magicNumber: Int, notary: Party): TransactionBuilder
val legalContractReference: SecureHash
-fun verify(tx: TransactionForVerification): Unit
+fun verify(tx: TransactionForContract): Unit
+ + + +class DummyLinearState : LinearState
+ @@ -1276,6 +1555,21 @@ +data class DummyState : ContractState
+ class E2ETestKeyManagementService : SingletonSerializeAsToken, KeyManagementService
+object Ed25519PrivateKeySerializer
+ +object Ed25519PublicKeySerializer
+ object Emoji
+object FixingSessionInitiationHandler
+ open class FloatingRate : Rate
    @@ -1755,7 +2090,7 @@
-abstract class FungibleAsset<T> : Contract
+abstract class FungibleAsset<T> : Contract
-interface State<T> : FungibleAssetState<T, AssetIssuanceDefinition<T>>
+interface FungibleAssetState<T, I> : OwnableState
-open fun verify(tx: TransactionForVerification): Unit
- - - -interface FungibleAssetState<T, I : AssetIssuanceDefinition<T>> : OwnableState
+enum class IRSDemoNode
@@ -1858,7 +2195,7 @@ -IRSSimulation(runAsync: Boolean, latencyInjector: LatencyCalculator?)
+IRSSimulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, latencyInjector: LatencyCalculator?)
fun iterate(): MessageTransfer?
val om: <ERROR CLASS>
protected fun startMainSimulation(): <ERROR CLASS><Unit>
@@ -1879,6 +2216,18 @@ +class IllegalProtocolLogicException : IllegalArgumentException
+ class ImmutableClassSerializer<T : Any>
-class InsufficientBalanceException : Exception
+open class InMemoryWalletService : SingletonSerializeAsToken, WalletService
+class InsufficientBalanceException : Exception
+ @@ -2290,11 +2672,11 @@ -FloatingLeg(floatingRatePayer: Party, notional: Amount<Currency>, paymentFrequency: Frequency, effectiveDate: LocalDate, effectiveDateAdjustment: DateRollConvention?, terminationDate: LocalDate, terminationDateAdjustment: DateRollConvention?, dayCountBasisDay: DayCountBasisDay, dayCountBasisYear: DayCountBasisYear, dayInMonth: Int, paymentRule: PaymentRule, paymentDelay: Int, paymentCalendar: BusinessCalendar, interestPeriodAdjustment: AccrualAdjustment, rollConvention: DateRollConvention, fixingRollConvention: DateRollConvention, resetDayInMonth: Int, fixingPeriod: DateOffset, resetRule: PaymentRule, fixingsPerPayment: Frequency, fixingCalendar: BusinessCalendar, index: String, indexSource: String, indexTenor: Tenor)
-fun copy(floatingRatePayer: Party = this.floatingRatePayer, notional: Amount<Currency> = this.notional, paymentFrequency: Frequency = this.paymentFrequency, effectiveDate: LocalDate = this.effectiveDate, effectiveDateAdjustment: DateRollConvention? = this.effectiveDateAdjustment, terminationDate: LocalDate = this.terminationDate, terminationDateAdjustment: DateRollConvention? = this.terminationDateAdjustment, dayCountBasisDay: DayCountBasisDay = this.dayCountBasisDay, dayCountBasisYear: DayCountBasisYear = this.dayCountBasisYear, dayInMonth: Int = this.dayInMonth, paymentRule: PaymentRule = this.paymentRule, paymentDelay: Int = this.paymentDelay, paymentCalendar: BusinessCalendar = this.paymentCalendar, interestPeriodAdjustment: AccrualAdjustment = this.interestPeriodAdjustment, rollConvention: DateRollConvention = this.rollConvention, fixingRollConvention: DateRollConvention = this.fixingRollConvention, resetDayInMonth: Int = this.resetDayInMonth, fixingPeriod: DateOffset = this.fixingPeriod, resetRule: PaymentRule = this.resetRule, fixingsPerPayment: Frequency = this.fixingsPerPayment, fixingCalendar: BusinessCalendar = this.fixingCalendar, index: String = this.index, indexSource: String = this.indexSource, indexTenor: Tenor = this.indexTenor): FloatingLeg
+FloatingLeg(floatingRatePayer: Party, notional: Amount<Currency>, paymentFrequency: Frequency, effectiveDate: LocalDate, effectiveDateAdjustment: DateRollConvention?, terminationDate: LocalDate, terminationDateAdjustment: DateRollConvention?, dayCountBasisDay: DayCountBasisDay, dayCountBasisYear: DayCountBasisYear, dayInMonth: Int, paymentRule: PaymentRule, paymentDelay: Int, paymentCalendar: BusinessCalendar, interestPeriodAdjustment: AccrualAdjustment, rollConvention: DateRollConvention, fixingRollConvention: DateRollConvention, resetDayInMonth: Int, fixingPeriodOffset: Int, resetRule: PaymentRule, fixingsPerPayment: Frequency, fixingCalendar: BusinessCalendar, index: String, indexSource: String, indexTenor: Tenor)
+fun copy(floatingRatePayer: Party = this.floatingRatePayer, notional: Amount<Currency> = this.notional, paymentFrequency: Frequency = this.paymentFrequency, effectiveDate: LocalDate = this.effectiveDate, effectiveDateAdjustment: DateRollConvention? = this.effectiveDateAdjustment, terminationDate: LocalDate = this.terminationDate, terminationDateAdjustment: DateRollConvention? = this.terminationDateAdjustment, dayCountBasisDay: DayCountBasisDay = this.dayCountBasisDay, dayCountBasisYear: DayCountBasisYear = this.dayCountBasisYear, dayInMonth: Int = this.dayInMonth, paymentRule: PaymentRule = this.paymentRule, paymentDelay: Int = this.paymentDelay, paymentCalendar: BusinessCalendar = this.paymentCalendar, interestPeriodAdjustment: AccrualAdjustment = this.interestPeriodAdjustment, rollConvention: DateRollConvention = this.rollConvention, fixingRollConvention: DateRollConvention = this.fixingRollConvention, resetDayInMonth: Int = this.resetDayInMonth, fixingPeriod: Int = this.fixingPeriodOffset, resetRule: PaymentRule = this.resetRule, fixingsPerPayment: Frequency = this.fixingsPerPayment, fixingCalendar: BusinessCalendar = this.fixingCalendar, index: String = this.index, indexSource: String = this.indexSource, indexTenor: Tenor = this.indexTenor): FloatingLeg
open fun equals(other: Any?): Boolean
var fixingCalendar: BusinessCalendar
-var fixingPeriod: DateOffset
+var fixingPeriodOffset: Int
var fixingRollConvention: DateRollConvention
var fixingsPerPayment: Frequency
var floatingRatePayer: Party
@@ -2309,7 +2691,7 @@ -data class State : FixableDealState
+data class State : FixableDealState, SchedulableState
@@ -2393,6 +2776,115 @@ interface IssuanceDefinition
+interface IssueCommand : CommandData
+ +data class Issued<P>
+ +object JavaTestHelpers
+ +object JavaTestHelpers
+ +object JavaTestHelpers
+ object JsonSupport
    @@ -2461,6 +2953,30 @@
+object PublicKeyDeserializer
+ +object PublicKeySerializer
+ class SecureHashDeserializer<T : SecureHash>
    @@ -2530,6 +3046,19 @@
+object KotlinObjectSerializer
+ class LabeledOutput
+sealed class LastLineShouldTestForAcceptOrFailure
data class LedgerTransaction : NamedByHash
@@ -2707,7 +3239,7 @@ -MockNetwork(threadPerNode: Boolean = false, defaultFactory: Factory = MockNetwork.DefaultFactory)
+MockNetwork(networkSendManuallyPumped: Boolean = false, threadPerNode: Boolean = false, defaultFactory: Factory = MockNetwork.DefaultFactory)
object DefaultFactory : Factory
    @@ -2799,7 +3331,7 @@
-class MockStorageService : SingletonSerializeAsToken, StorageService
+class MockStorageService : SingletonSerializeAsToken, TxWritableStorageService
    @@ -2842,6 +3374,18 @@
+interface MoveCommand : CommandData
+ abstract class MutableClock : Clock
    @@ -2869,6 +3413,19 @@
+enum class NetType
+ sealed class NetworkCacheError : Exception
val REGISTER_PROTOCOL_TOPIC: String
-class RegistrationRequest : AbstractRequestMessage
+class RegistrationRequest : NetworkMapRequestMessage
val SUBSCRIPTION_PROTOCOL_TOPIC: String
-class SubscribeRequest : AbstractRequestMessage
+class SubscribeRequest : NetworkMapRequestMessage
@@ -3258,10 +3835,11 @@ -Oracle(identity: Party, signingKey: KeyPair)
+Oracle(identity: Party, signingKey: KeyPair, clock: Clock)
+val clock: Clock
val identity: Party
var knownFixes: FixContainer
-fun query(queries: List<FixOf>): List<Fix>
+fun query(queries: List<FixOf>, deadline: Instant): List<Fix>
fun sign(wtx: WireTransaction): LegallyIdentifiable
@@ -3284,7 +3862,7 @@ object Type : ServiceType
-class UnknownFix : Exception
+class UnknownFix : RetryableException
@@ -3369,7 +3946,7 @@ -class NodeWalletService : SingletonSerializeAsToken, WalletService
+class NodeSchedulerService : SchedulerService, SingletonSerializeAsToken
+class NodeWalletService : InMemoryWalletService
+ @@ -3394,7 +3980,7 @@ -NonEmptySet(initial: T, set: MutableSet<T> = mutableSetOf())
+NonEmptySet(initial: T)
inner class Iterator<T, T> : MutableIterator<T>
    @@ -3428,6 +4014,89 @@
+object NonEmptySetSerializer
+ +object NotaryChangeProtocol : AbstractStateReplacementProtocol<Party>
+ +class NotaryChangeService : AbstractNodeService
+ sealed class NotaryError
    @@ -3475,6 +4144,19 @@
+class SignaturesMissing : NotaryError
+ class TimestampInvalid : NotaryError
@@ -3562,7 +4244,7 @@ -abstract fun create(otherSide: SingleMessageRecipient, sendSessionID: Long, receiveSessionID: Long, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider): Service
+abstract fun create(otherSide: Party, sendSessionID: Long, receiveSessionID: Long, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider): Service
@@ -3574,8 +4256,9 @@ -Handshake(replyTo: SingleMessageRecipient, sendSessionID: Long, sessionID: Long)
+Handshake(replyTo: Party, sendSessionID: Long, sessionID: Long)
val sendSessionID: Long
+val sessionID: Long
@@ -3602,10 +4285,10 @@ -Service(otherSide: SingleMessageRecipient, sendSessionID: Long, receiveSessionID: Long, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider)
-open fun beforeCommit(wtx: WireTransaction, reqIdentity: Party): Unit
+Service(otherSide: Party, sendSessionID: Long, receiveSessionID: Long, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider)
+open fun beforeCommit(stx: SignedTransaction, reqIdentity: Party): Unit
open fun call(): Unit
-val otherSide: SingleMessageRecipient
+val otherSide: Party
val receiveSessionID: Long
val sendSessionID: Long
val timestampChecker: TimestampChecker
@@ -3621,9 +4304,9 @@ -SignRequest(txBits: SerializedBytes<WireTransaction>, callerIdentity: Party)
+SignRequest(tx: SignedTransaction, callerIdentity: Party)
val callerIdentity: Party
-val txBits: SerializedBytes<WireTransaction>
+val tx: SignedTransaction
@@ -3640,7 +4323,7 @@ -NotaryService(smm: StateMachineManager, net: MessagingService, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider)
+NotaryService(smm: StateMachineManager, net: MessagingService, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider, networkMapCache: NetworkMapCache)
object Type : ServiceType
abstract val logger: <ERROR CLASS>
abstract val protocolFactory: Factory
@@ -3666,6 +4349,251 @@ +class Obligation<P> : Contract
+ open class OpaqueBytes
+data class ProtocolLogicRef
+ +class ProtocolLogicRefFactory : SingletonSerializeAsToken
+ interface ProtocolRef
data class ProtocolRequiringAttention
+interface ReadOnlyTransactionStorage
+ class RecordingMap<K, V> : MutableMap<K, V>
@@ -4567,7 +5637,7 @@ -SimpleNotaryService(smm: StateMachineManager, net: MessagingService, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider)
+SimpleNotaryService(smm: StateMachineManager, net: MessagingService, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider, networkMapCache: NetworkMapCache)
object Type : ServiceType
val logger: <ERROR CLASS>
val protocolFactory: DefaultFactory
@@ -4582,7 +5652,7 @@ -Simulation(runAsync: Boolean, latencyInjector: LatencyCalculator?)
+Simulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, latencyInjector: LatencyCalculator?)
inner class BankFactory : Factory
@@ -4770,7 +5842,7 @@ -FiberRequest(topic: String, destination: MessageRecipients?, sessionIDForSend: Long, sessionIDForReceive: Long, payload: Any?)
+FiberRequest(topic: String, destination: Party?, sessionIDForSend: Long, sessionIDForReceive: Long, payload: Any?)
class ExpectingResponse<R : Any> : FiberRequest
-val destination: MessageRecipients?
+val destination: Party?
val payload: Any?
val sessionIDForReceive: Long
val sessionIDForSend: Long
@@ -4844,6 +5916,35 @@ +class StateReplacementException : Exception
+ +class StateReplacementRefused
+ interface StatesQuery
-open class StorageServiceImpl : SingletonSerializeAsToken, StorageService
+open class StorageServiceImpl : SingletonSerializeAsToken, TxWritableStorageService
    @@ -4958,7 +6059,7 @@
-class TestClock : MutableClock
+class TestClock : MutableClock, SerializeAsToken
@@ -4982,9 +6085,9 @@ -val keypair: KeyPair
-val keypair2: KeyPair
-val keypair3: KeyPair
+val keypair: <ERROR CLASS>
+val keypair2: <ERROR CLASS>
+val keypair3: <ERROR CLASS>
@@ -4996,13 +6099,29 @@ -ThreadBox(content: T, lock: Lock = ReentrantLock())
+ThreadBox(content: T, lock: ReentrantLock = ReentrantLock())
+inline fun <R> alreadyLocked(body: T.() -> R): R
val content: T
-val lock: Lock
+val lock: ReentrantLock
inline fun <R> locked(body: T.() -> R): R
+data class TimeWindow
+ class TimestampChecker
    @@ -5059,56 +6178,6 @@
-class TraderDemoProtocolBuyer : ProtocolLogic<Unit>
- -class TraderDemoProtocolSeller : ProtocolLogic<Unit>
- data class TransactionBuildStep
    @@ -5123,7 +6192,7 @@
-class TransactionBuilder
+abstract class TransactionBuilder
+data class TransactionForContract
+ open class TransactionForTest : AbstractTransactionForTest
@@ -5200,34 +6322,17 @@ -TransactionForVerification(inStates: List<ContractState>, outStates: List<ContractState>, attachments: List<Attachment>, commands: List<AuthenticatedObject<CommandData>>, origHash: SecureHash)
-data class InOutGroup<T : ContractState, K : Any>
- +TransactionForVerification(inputs: List<TransactionState<ContractState>>, outputs: List<TransactionState<ContractState>>, attachments: List<Attachment>, commands: List<AuthenticatedObject<CommandData>>, origHash: SecureHash, signers: List<PublicKey>, type: TransactionType)
val attachments: List<Attachment>
val commands: List<AuthenticatedObject<CommandData>>
fun equals(other: Any?): Boolean
-fun getTimestampBy(timestampingAuthority: Party): TimestampCommand?
-fun getTimestampByName(vararg authorityName: String): TimestampCommand?
-fun <T : ContractState, K : Any> groupStates(ofType: Class<T>, selector: (T) -> K): List<InOutGroup<T, K>>
-inline fun <reified T : ContractState, K : Any> groupStates(selector: (T) -> K): List<InOutGroup<T, K>>
-fun <T : ContractState, K : Any> groupStatesInternal(inGroups: Map<K, List<T>>, outGroups: Map<K, List<T>>): List<InOutGroup<T, K>>
fun hashCode(): Int
-val inStates: List<ContractState>
+val inputs: List<TransactionState<ContractState>>
val origHash: SecureHash
-val outStates: List<ContractState>
+val outputs: List<TransactionState<ContractState>>
+val signers: List<PublicKey>
+fun toTransactionForContract(): TransactionForContract
+val type: TransactionType
fun verify(): Unit
@@ -5240,7 +6345,7 @@ -TransactionGraphSearch(transactions: TransactionStorage, startPoints: List<WireTransaction>)
+TransactionGraphSearch(transactions: ReadOnlyTransactionStorage, startPoints: List<WireTransaction>)
class Query
@@ -5308,7 +6413,7 @@ Roots()
fun roots(body: Roots<T>.() -> Unit): Unit
-fun transaction(vararg outputStates: LabeledOutput): Unit
+fun transaction(vararg outputStates: LabeledOutput): Roots<T>
fun transaction(body: WireTransactionDSL<T>.() -> Unit): Unit
@@ -5328,11 +6433,11 @@ fun expectFailureOfTx(index: Int, message: String): Exception
-fun labelForState(state: T): String?
+fun labelForState(output: TransactionState<*>): String?
fun labelForTransaction(tx: WireTransaction): String?
fun labelForTransaction(tx: LedgerTransaction): String?
fun <C : ContractState> lookup(label: String): StateAndRef<C>
-val String.output: T
+val String.output: TransactionState<T>
val String.outputRef: StateRef
fun roots(body: Roots<T>.() -> Unit): <ERROR CLASS>
fun signAll(txnsToSign: List<WireTransaction> = txns, vararg extraKeys: KeyPair): List<SignedTransaction>
@@ -5357,7 +6462,22 @@ -interface TransactionStorage
+data class TransactionState<out T : ContractState>
+ +interface TransactionStorage : ReadOnlyTransactionStorage
+sealed class TransactionType
+ @@ -5391,6 +6580,18 @@ +class InvalidNotaryChange : TransactionVerificationException
+ class MoreThanOneNotary : TransactionVerificationException
    @@ -5403,6 +6604,18 @@
+class SignersMissing : TransactionVerificationException
+ val tx: TransactionForVerification
@@ -5436,10 +6649,13 @@ -Acceptor(otherSide: SingleMessageRecipient, notary: Party, dealToBuy: T, sessionID: Long, progressTracker: ProgressTracker = Secondary.tracker())
+Acceptor(otherSide: Party, notary: Party, dealToBuy: T, sessionID: Long, progressTracker: ProgressTracker = Secondary.tracker())
protected open fun assembleSharedTX(handshake: Handshake<T>): <ERROR CLASS><TransactionBuilder, List<PublicKey>>
val dealToBuy: T
+val notary: Party
+open val otherSide: Party
open val progressTracker: ProgressTracker
+open val sessionID: Long
protected open fun validateHandshake(handshake: Handshake<T>): Handshake<T>
@@ -5475,7 +6691,8 @@ -class Fixer<T : FixableDealState> : Secondary<StateRef>
+val FIX_INITIATE_TOPIC: String
+class Fixer : Secondary<StateRef>
-class Floater<T : FixableDealState> : Primary<StateRef>
+class FixingRoleDecider : ProtocolLogic<Unit>
+data class FixingSessionInitiation
+ +class Floater : Primary<StateRef>
+ @@ -5530,7 +6796,13 @@ -Instigator(otherSide: SingleMessageRecipient, notaryNode: NodeInfo, dealBeingOffered: T, myKeyPair: KeyPair, buyerSessionID: Long, progressTracker: ProgressTracker = Primary.tracker())
+Instigator(otherSide: Party, notary: Party, payload: T, myKeyPair: KeyPair, otherSessionID: Long, progressTracker: ProgressTracker = Primary.tracker())
+open val myKeyPair: KeyPair
+val notary: Party
+open val notaryNode: NodeInfo
+open val otherSessionID: Long
+open val otherSide: Party
+open val payload: T
open val progressTracker: ProgressTracker
@@ -5543,7 +6815,7 @@ -Primary(payload: U, otherSide: SingleMessageRecipient, otherSessionID: Long, myKeyPair: KeyPair, notaryNode: NodeInfo, progressTracker: ProgressTracker = Primary.tracker())
+Primary(progressTracker: ProgressTracker = Primary.tracker())
object AWAITING_PROPOSAL : Step
object COPYING_TO_REGULATOR : Step
object NOTARY : Step
@@ -5553,11 +6825,11 @@ object VERIFYING : Step
open fun call(): SignedTransaction
fun getPartialTransaction(): UntrustworthyData<SignedTransaction>
-val myKeyPair: KeyPair
-val notaryNode: NodeInfo
-val otherSessionID: Long
-val otherSide: SingleMessageRecipient
-val payload: U
+abstract val myKeyPair: KeyPair
+abstract val notaryNode: NodeInfo
+abstract val otherSessionID: Long
+abstract val otherSide: Party
+abstract val payload: U
open val progressTracker: ProgressTracker
open fun signWithOurKey(partialTX: SignedTransaction): WithKey
fun tracker(): ProgressTracker
@@ -5573,7 +6845,7 @@ -Secondary(otherSide: SingleMessageRecipient, notary: Party, sessionID: Long, progressTracker: ProgressTracker = Secondary.tracker())
+Secondary(progressTracker: ProgressTracker = Secondary.tracker())
object RECEIVING : Step
object RECORDING : Step
object SIGNING : Step
@@ -5581,10 +6853,9 @@ object VERIFYING : Step
protected abstract fun assembleSharedTX(handshake: Handshake<U>): <ERROR CLASS><TransactionBuilder, List<PublicKey>>
open fun call(): SignedTransaction
-val notary: Party
-val otherSide: SingleMessageRecipient
+abstract val otherSide: Party
open val progressTracker: ProgressTracker
-val sessionID: Long
+abstract val sessionID: Long
fun tracker(): ProgressTracker
protected abstract fun validateHandshake(handshake: Handshake<U>): Handshake<U>
@@ -5638,15 +6909,15 @@ -Buyer(otherSide: SingleMessageRecipient, notary: Party, acceptablePrice: Amount<Currency>, typeToBuy: Class<out OwnableState>, sessionID: Long)
+Buyer(otherSide: Party, notary: Party, acceptablePrice: Amount<Issued<Currency>>, typeToBuy: Class<out OwnableState>, sessionID: Long)
object RECEIVING : Step
object SIGNING : Step
object SWAPPING_SIGNATURES : Step
object VERIFYING : Step
-val acceptablePrice: Amount<Currency>
+val acceptablePrice: Amount<Issued<Currency>>
open fun call(): SignedTransaction
val notary: Party
-val otherSide: SingleMessageRecipient
+val otherSide: Party
open val progressTracker: ProgressTracker
val sessionID: Long
val typeToBuy: Class<out OwnableState>
@@ -5661,7 +6932,7 @@ -Seller(otherSide: SingleMessageRecipient, notaryNode: NodeInfo, assetToSell: StateAndRef<OwnableState>, price: Amount<Currency>, myKeyPair: KeyPair, buyerSessionID: Long, progressTracker: ProgressTracker = Seller.tracker())
+Seller(otherSide: Party, notaryNode: NodeInfo, assetToSell: StateAndRef<OwnableState>, price: Amount<Issued<Currency>>, myKeyPair: KeyPair, buyerSessionID: Long, progressTracker: ProgressTracker = Seller.tracker())
object AWAITING_PROPOSAL : Step
object NOTARY : Step
object SENDING_SIGS : Step
@@ -5672,8 +6943,8 @@ open fun call(): SignedTransaction
val myKeyPair: KeyPair
val notaryNode: NodeInfo
-val otherSide: SingleMessageRecipient
-val price: Amount<Currency>
+val otherSide: Party
+val price: Amount<Issued<Currency>>
open val progressTracker: ProgressTracker
open fun signWithOurKey(partialTX: SignedTransaction): WithKey
fun tracker(): ProgressTracker
@@ -5688,9 +6959,9 @@ -SellerTradeInfo(assetForSale: StateAndRef<OwnableState>, price: Amount<Currency>, sellerOwnerKey: PublicKey, sessionID: Long)
+SellerTradeInfo(assetForSale: StateAndRef<OwnableState>, price: Amount<Issued<Currency>>, sellerOwnerKey: PublicKey, sessionID: Long)
val assetForSale: StateAndRef<OwnableState>
-val price: Amount<Currency>
+val price: Amount<Issued<Currency>>
val sellerOwnerKey: PublicKey
val sessionID: Long
@@ -5719,14 +6990,26 @@ -UnacceptablePriceException(givenPrice: Amount<Currency>)
-val givenPrice: Amount<Currency>
+UnacceptablePriceException(givenPrice: Amount<Issued<Currency>>)
+val givenPrice: Amount<Issued<Currency>>
+interface TxWritableStorageService : StorageService
+ abstract class TypeOnlyCommandData : CommandData
    @@ -5790,7 +7073,7 @@
-abstract fun commit(tx: WireTransaction, callerIdentity: Party): Unit
+abstract fun commit(states: List<StateRef>, txId: SecureHash, callerIdentity: Party): Unit
@@ -5830,7 +7113,7 @@ -class Broadcast : ProtocolLogic<Boolean>
+class Broadcast : ProtocolLogic<Unit>
-class Updater : ProtocolLogic<Boolean>
- @@ -5921,8 +7167,8 @@ -ValidatingNotaryProtocol(otherSide: SingleMessageRecipient, sessionIdForSend: Long, sessionIdForReceive: Long, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider)
-fun beforeCommit(wtx: WireTransaction, reqIdentity: Party): Unit
+ValidatingNotaryProtocol(otherSide: Party, sessionIdForSend: Long, sessionIdForReceive: Long, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider)
+fun beforeCommit(stx: SignedTransaction, reqIdentity: Party): Unit
@@ -5934,14 +7180,14 @@ -ValidatingNotaryService(smm: StateMachineManager, net: MessagingService, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider)
+ValidatingNotaryService(smm: StateMachineManager, net: MessagingService, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider, networkMapCache: NetworkMapCache)
object Type : ServiceType
val logger: <ERROR CLASS>
val protocolFactory: Factory
-abstract class Wallet
+class Wallet
-object WalletFiller
- -class WalletImpl : Wallet
- interface WalletService
@@ -6038,7 +7257,7 @@ -WireTransaction(inputs: List<StateRef>, attachments: List<SecureHash>, outputs: List<ContractState>, commands: List<Command>)
+WireTransaction(inputs: List<StateRef>, attachments: List<SecureHash>, outputs: List<TransactionState<ContractState>>, commands: List<Command>, signers: List<PublicKey>, type: TransactionType)
val attachments: List<SecureHash>
val commands: List<Command>
fun deserialize(bits: SerializedBytes<WireTransaction>, kryo: <ERROR CLASS> = THREAD_LOCAL_KRYO.get()): WireTransaction
@@ -6046,9 +7265,11 @@ val inputs: List<StateRef>
fun <T : ContractState> outRef(index: Int): StateAndRef<T>
fun <T : ContractState> outRef(state: ContractState): StateAndRef<T>
-val outputs: List<ContractState>
+val outputs: List<TransactionState<ContractState>>
val serialized: SerializedBytes<WireTransaction>
+val signers: List<PublicKey>
fun toString(): String
+val type: TransactionType
@@ -6171,6 +7392,18 @@ +java.util.Currency
+ kotlin.ByteArray
    @@ -6328,7 +7561,7 @@
-kotlin.collections.Iterable
+kotlin.collections.Iterable
+kotlin.collections.Iterable
+ @@ -6452,15 +7700,15 @@ -State(issuance: PartyAndReference, owner: PublicKey, faceValue: Amount<Currency>, maturityDate: Instant, notary: Party)
+State(issuance: PartyAndReference, owner: PublicKey, faceValue: Amount<Issued<Currency>>, maturityDate: Instant)
val contract: CommercialPaper
-val faceValue: Amount<Currency>
+val faceValue: Amount<Issued<Currency>>
val issuance: PartyAndReference
val maturityDate: Instant
-val notary: Party
val owner: PublicKey
+val participants: List<PublicKey>
fun toString(): String
-fun withFaceValue(newFaceValue: Amount<Currency>): <ERROR CLASS>
+fun withFaceValue(newFaceValue: Amount<Issued<Currency>>): <ERROR CLASS>
fun withIssuance(newIssuance: PartyAndReference): <ERROR CLASS>
fun withMaturityDate(newMaturityDate: Instant): <ERROR CLASS>
fun withNewOwner(newOwner: PublicKey): <ERROR CLASS>
@@ -6469,11 +7717,11 @@ -fun generateIssue(issuance: PartyAndReference, faceValue: Amount<Currency>, maturityDate: Instant, notary: Party): TransactionBuilder
+fun generateIssue(faceValue: Amount<Issued<Currency>>, maturityDate: Instant, notary: Party): TransactionBuilder
fun generateMove(tx: TransactionBuilder, paper: StateAndRef<State>, newOwner: PublicKey): Unit
-fun generateRedeem(tx: TransactionBuilder, paper: StateAndRef<State>, wallet: List<StateAndRef<State>>): Unit
+fun generateRedeem(tx: TransactionBuilder, paper: StateAndRef<State>, wallet: List<StateAndRef<State>>): Unit
val legalContractReference: SecureHash
-fun verify(tx: TransactionForVerification): Unit
+fun verify(tx: TransactionForContract): Unit
@@ -6728,11 +7976,11 @@ -FloatingLeg(floatingRatePayer: Party, notional: Amount<Currency>, paymentFrequency: Frequency, effectiveDate: LocalDate, effectiveDateAdjustment: DateRollConvention?, terminationDate: LocalDate, terminationDateAdjustment: DateRollConvention?, dayCountBasisDay: DayCountBasisDay, dayCountBasisYear: DayCountBasisYear, dayInMonth: Int, paymentRule: PaymentRule, paymentDelay: Int, paymentCalendar: BusinessCalendar, interestPeriodAdjustment: AccrualAdjustment, rollConvention: DateRollConvention, fixingRollConvention: DateRollConvention, resetDayInMonth: Int, fixingPeriod: DateOffset, resetRule: PaymentRule, fixingsPerPayment: Frequency, fixingCalendar: BusinessCalendar, index: String, indexSource: String, indexTenor: Tenor)
-fun copy(floatingRatePayer: Party = this.floatingRatePayer, notional: Amount<Currency> = this.notional, paymentFrequency: Frequency = this.paymentFrequency, effectiveDate: LocalDate = this.effectiveDate, effectiveDateAdjustment: DateRollConvention? = this.effectiveDateAdjustment, terminationDate: LocalDate = this.terminationDate, terminationDateAdjustment: DateRollConvention? = this.terminationDateAdjustment, dayCountBasisDay: DayCountBasisDay = this.dayCountBasisDay, dayCountBasisYear: DayCountBasisYear = this.dayCountBasisYear, dayInMonth: Int = this.dayInMonth, paymentRule: PaymentRule = this.paymentRule, paymentDelay: Int = this.paymentDelay, paymentCalendar: BusinessCalendar = this.paymentCalendar, interestPeriodAdjustment: AccrualAdjustment = this.interestPeriodAdjustment, rollConvention: DateRollConvention = this.rollConvention, fixingRollConvention: DateRollConvention = this.fixingRollConvention, resetDayInMonth: Int = this.resetDayInMonth, fixingPeriod: DateOffset = this.fixingPeriod, resetRule: PaymentRule = this.resetRule, fixingsPerPayment: Frequency = this.fixingsPerPayment, fixingCalendar: BusinessCalendar = this.fixingCalendar, index: String = this.index, indexSource: String = this.indexSource, indexTenor: Tenor = this.indexTenor): FloatingLeg
+FloatingLeg(floatingRatePayer: Party, notional: Amount<Currency>, paymentFrequency: Frequency, effectiveDate: LocalDate, effectiveDateAdjustment: DateRollConvention?, terminationDate: LocalDate, terminationDateAdjustment: DateRollConvention?, dayCountBasisDay: DayCountBasisDay, dayCountBasisYear: DayCountBasisYear, dayInMonth: Int, paymentRule: PaymentRule, paymentDelay: Int, paymentCalendar: BusinessCalendar, interestPeriodAdjustment: AccrualAdjustment, rollConvention: DateRollConvention, fixingRollConvention: DateRollConvention, resetDayInMonth: Int, fixingPeriodOffset: Int, resetRule: PaymentRule, fixingsPerPayment: Frequency, fixingCalendar: BusinessCalendar, index: String, indexSource: String, indexTenor: Tenor)
+fun copy(floatingRatePayer: Party = this.floatingRatePayer, notional: Amount<Currency> = this.notional, paymentFrequency: Frequency = this.paymentFrequency, effectiveDate: LocalDate = this.effectiveDate, effectiveDateAdjustment: DateRollConvention? = this.effectiveDateAdjustment, terminationDate: LocalDate = this.terminationDate, terminationDateAdjustment: DateRollConvention? = this.terminationDateAdjustment, dayCountBasisDay: DayCountBasisDay = this.dayCountBasisDay, dayCountBasisYear: DayCountBasisYear = this.dayCountBasisYear, dayInMonth: Int = this.dayInMonth, paymentRule: PaymentRule = this.paymentRule, paymentDelay: Int = this.paymentDelay, paymentCalendar: BusinessCalendar = this.paymentCalendar, interestPeriodAdjustment: AccrualAdjustment = this.interestPeriodAdjustment, rollConvention: DateRollConvention = this.rollConvention, fixingRollConvention: DateRollConvention = this.fixingRollConvention, resetDayInMonth: Int = this.resetDayInMonth, fixingPeriod: Int = this.fixingPeriodOffset, resetRule: PaymentRule = this.resetRule, fixingsPerPayment: Frequency = this.fixingsPerPayment, fixingCalendar: BusinessCalendar = this.fixingCalendar, index: String = this.index, indexSource: String = this.indexSource, indexTenor: Tenor = this.indexTenor): FloatingLeg
open fun equals(other: Any?): Boolean
var fixingCalendar: BusinessCalendar
-var fixingPeriod: DateOffset
+var fixingPeriodOffset: Int
var fixingRollConvention: DateRollConvention
var fixingsPerPayment: Frequency
var floatingRatePayer: Party
@@ -6747,7 +7995,7 @@ -data class State : FixableDealState
+data class State : FixableDealState, SchedulableState
@@ -6930,7 +8179,7 @@ -package com.r3corda.contracts.cash
+package com.r3corda.contracts.asset
-interface State<T> : FungibleAssetState<T, AssetIssuanceDefinition<T>>
+class InsufficientBalanceException : Exception
-open fun verify(tx: TransactionForVerification): Unit
- - - -interface FungibleAssetState<T, I : AssetIssuanceDefinition<T>> : OwnableState
+val OBLIGATION_PROGRAM_ID: Obligation<Currency>
+class Obligation<P> : Contract
-class InsufficientBalanceException : Exception
+Obligation()
+data class BilateralNetState<P> : NetState<P>
-kotlin.collections.Iterable
+interface Commands : CommandData
+interface IssuanceCommands<P> : CommandData
+ +data class IssuanceDefinition<P>
+ +enum class Lifecycle
+ +data class MultilateralNetState<P> : NetState<P>
+ +interface NetState<P>
+ +data class State<P> : FungibleAssetState<P, IssuanceDefinition<P>>, BilateralNettableState<State<P>>
+ +data class StateTemplate<P>
+ +fun generateCloseOutNetting(tx: TransactionBuilder, signer: PublicKey, vararg states: State<P>): Unit
+fun generateIssue(tx: TransactionBuilder, obligor: Party, issuanceDef: StateTemplate<P>, pennies: Long, beneficiary: PublicKey, notary: Party): Unit
+fun generatePaymentNetting(tx: TransactionBuilder, issued: Issued<P>, notary: Party, vararg states: State<P>): Unit
+fun generateSetLifecycle(tx: TransactionBuilder, statesAndRefs: List<StateAndRef<State<P>>>, lifecycle: Lifecycle, notary: Party): Unit
+fun generateSettle(tx: TransactionBuilder, statesAndRefs: Iterable<StateAndRef<State<P>>>, assetStatesAndRefs: Iterable<StateAndRef<FungibleAssetState<P, *>>>, moveCommand: MoveCommand, notary: Party): Unit
+val legalContractReference: SecureHash
+fun verify(tx: TransactionForContract): Unit
+protected fun verifyIssueCommand(inputs: List<State<P>>, outputs: List<State<P>>, issueCommand: AuthenticatedObject<Issue<P>>, issued: Issued<P>, obligor: Party): Unit
+protected fun verifyNetCommand(inputs: Iterable<State<P>>, outputs: Iterable<State<P>>, command: AuthenticatedObject<Net>, netState: NetState<P>): Unit
+protected fun verifySetLifecycleCommand(inputs: List<State<P>>, outputs: List<State<P>>, tx: TransactionForContract, setLifecycleCommand: AuthenticatedObject<SetLifecycle<P>>): Unit
+ + + +val Wallet.cashBalances: Map<Currency, Amount<Currency>>
+fun <P> extractAmountsDue(product: P, states: Iterable<State<P>>): Map<<ERROR CLASS><PublicKey, PublicKey>, Amount<P>>
+kotlin.collections.Iterable
+ +fun <P> netAmountsDue(balances: Map<<ERROR CLASS><PublicKey, PublicKey>, Amount<P>>): Map<<ERROR CLASS><PublicKey, PublicKey>, Amount<P>>
+fun <P> sumAmountsDue(balances: Map<<ERROR CLASS><PublicKey, PublicKey>, Amount<P>>): Map<PublicKey, Long>
@@ -7172,13 +8640,58 @@ -val Amount<Currency>.CASH: State
+val Amount<Currency>.CASH: State
+val DUMMY_CASH_ISSUER: PartyAndReference
+val DUMMY_CASH_ISSUER_KEY: <ERROR CLASS>
+object JavaTestHelpers
+ +val Amount<Issued<Currency>>.OBLIGATION: State<Currency>
+val Issued<Currency>.OBLIGATION_DEF: StateTemplate<Currency>
+val Amount<Issued<Currency>>.STATE: State
val TEST_PROGRAM_MAP: Map<Contract, Class<out Contract>>
-fun generateState(notary: Party = DUMMY_NOTARY): State
-infix fun State.issued by(party: Party): State
-infix fun State.owned by(owner: PublicKey): State
-infix fun State.owned by(owner: PublicKey): State
+infix fun <T> State<T>.at(dueBefore: Instant): State<T>
+infix fun <T> IssuanceDefinition<T>.at(dueBefore: Instant): IssuanceDefinition<T>
+infix fun <T> State<T>.between(parties: <ERROR CLASS><Party, PublicKey>): State<T>
+fun ServiceHub.fillWithSomeTestCash(howMuch: Amount<Currency>, notary: Party = DUMMY_NOTARY, atLeastThisManyStates: Int = 3, atMostThisManyStates: Int = 10, rng: Random = Random(), ref: OpaqueBytes = OpaqueBytes(ByteArray(1, { 0 }))): Wallet
+fun generateState(): DummyState
+infix fun State.issued by(party: Party): State
+infix fun State.issued by(deposit: PartyAndReference): State
+infix fun <T> State<T>.issued by(party: Party): State<T>
+infix fun State.owned by(owner: PublicKey): <ERROR CLASS>
+infix fun <T> State<T>.owned by(owner: PublicKey): <ERROR CLASS>
+infix fun State.owned by(owner: PublicKey): <ERROR CLASS>
infix fun <ERROR CLASS>.owned by(new_owner: PublicKey): <ERROR CLASS>
+infix fun State.with deposit(deposit: PartyAndReference): State
+infix fun State.with notary(notary: Party): TransactionState<State>
+infix fun State.with notary(notary: Party): TransactionState<State>
+infix fun ContractState.with notary(notary: Party): TransactionState<ContractState>
@@ -7211,9 +8724,10 @@ -ThreadBox(content: T, lock: Lock = ReentrantLock())
+ThreadBox(content: T, lock: ReentrantLock = ReentrantLock())
+inline fun <R> alreadyLocked(body: T.() -> R): R
val content: T
-val lock: Lock
+val lock: ReentrantLock
inline fun <R> locked(body: T.() -> R): R
@@ -7419,6 +8933,19 @@ +interface BilateralNettableState<T : BilateralNettableState<T>>
+ open class BusinessCalendar
@@ -7495,24 +9022,11 @@ abstract val contract: Contract
-abstract val notary: Party
+abstract val participants: List<PublicKey>
val DUMMY_PROGRAM_ID: DummyContract
-enum class DateOffset
- enum class DateRollConvention
- - - -class State : ContractState
+class Move : TypeOnlyCommandData, Commands
+ + + +data class MultiOwnerState : ContractState, State
+ +data class SingleOwnerState : OwnableState, State
+ +interface State : ContractState
+ fun generateInitial(owner: PartyAndReference, magicNumber: Int, notary: Party): TransactionBuilder
val legalContractReference: SecureHash
-fun verify(tx: TransactionForVerification): Unit
+fun verify(tx: TransactionForContract): Unit
+ + + +data class DummyState : ContractState
+ @@ -7793,7 +9364,7 @@ -abstract fun generateFix(ptx: TransactionBuilder, oldStateRef: StateRef, fix: Fix): Unit
+abstract fun generateFix(ptx: TransactionBuilder, oldState: StateAndRef<*>, fix: Fix): Unit
abstract fun nextFixingOf(): FixOf?
@@ -7897,6 +9468,52 @@ val GBP: Currency
interface IssuanceDefinition
+interface IssueCommand : CommandData
+ +data class Issued<P>
+ +object JavaTestHelpers
+ data class LedgerTransaction : NamedByHash
@@ -7928,6 +9547,18 @@ +interface MoveCommand : CommandData
+ interface NamedByHash
    @@ -7940,6 +9571,19 @@
+enum class NetType
+ interface OwnableState : ContractState
    @@ -7995,6 +9639,58 @@
+interface SchedulableState : ContractState
+ +interface Scheduled
+ +data class ScheduledActivity : Scheduled
+ +data class ScheduledStateRef : Scheduled
+ data class SignedTransaction : NamedByHash
@@ -8024,9 +9722,9 @@ -StateAndRef(state: T, ref: StateRef)
+StateAndRef(state: TransactionState<T>, ref: StateRef)
val ref: StateRef
-val state: T
+val state: TransactionState<T>
@@ -8092,7 +9790,7 @@ -class TransactionBuilder
+abstract class TransactionBuilder
+data class TransactionForContract
+ data class TransactionForVerification
+data class TransactionState<out T : ContractState>
+ +sealed class TransactionType
+ sealed class TransactionVerificationException : Exception
    @@ -8256,6 +10074,18 @@
+class InvalidNotaryChange : TransactionVerificationException
+ class MoreThanOneNotary : TransactionVerificationException
    @@ -8268,6 +10098,18 @@
+class SignersMissing : TransactionVerificationException
+ val tx: TransactionForVerification
@@ -8295,7 +10137,7 @@ -WireTransaction(inputs: List<StateRef>, attachments: List<SecureHash>, outputs: List<ContractState>, commands: List<Command>)
+WireTransaction(inputs: List<StateRef>, attachments: List<SecureHash>, outputs: List<TransactionState<ContractState>>, commands: List<Command>, signers: List<PublicKey>, type: TransactionType)
val attachments: List<SecureHash>
val commands: List<Command>
fun deserialize(bits: SerializedBytes<WireTransaction>, kryo: <ERROR CLASS> = THREAD_LOCAL_KRYO.get()): WireTransaction
@@ -8303,15 +10145,18 @@ val inputs: List<StateRef>
fun <T : ContractState> outRef(index: Int): StateAndRef<T>
fun <T : ContractState> outRef(state: ContractState): StateAndRef<T>
-val outputs: List<ContractState>
+val outputs: List<TransactionState<ContractState>>
val serialized: SerializedBytes<WireTransaction>
+val signers: List<PublicKey>
fun toString(): String
+val type: TransactionType
fun calculateDaysBetween(startDate: LocalDate, endDate: LocalDate, dcbYear: DayCountBasisYear, dcbDay: DayCountBasisDay): Int
fun currency(code: String): Currency
fun ContractState.hash(): SecureHash
+infix fun Amount<Currency>.issued by(deposit: PartyAndReference): Amount<Issued<Currency>>
java.time.LocalDate
    @@ -8324,6 +10169,18 @@
+java.util.Currency
+ kotlin.Double
    @@ -8383,7 +10240,8 @@
inline fun <R> requireThat(body: Requirements.() -> R): R
fun WireTransaction.toLedgerTransaction(identityService: IdentityService, attachmentStorage: AttachmentStorage): LedgerTransaction
-inline fun <reified T : CommandData> verifyMoveCommands(inputs: List<OwnableState>, tx: TransactionForVerification): Unit
+inline fun <reified T : CommandData> verifyMoveCommand(inputs: List<OwnableState>, tx: TransactionForContract): Unit
+inline fun <reified T : CommandData> verifyMoveCommand(inputs: List<OwnableState>, commands: List<AuthenticatedObject<CommandData>>): Unit
fun SignedTransaction.verifyToLedgerTransaction(identityService: IdentityService, attachmentStorage: AttachmentStorage): LedgerTransaction
@@ -8538,7 +10396,7 @@ -fun generateKeyPair(): KeyPair
+fun generateKeyPair(): <ERROR CLASS>
java.security.KeyPair
    @@ -8594,6 +10452,7 @@
+fun newSecureRandom(): SecureRandom
fun OpaqueBytes.sha256(): SHA256
@@ -8695,6 +10554,7 @@ +object Ack : DeserializeAsKotlinObjectDef
interface AllPossibleRecipients : MessageRecipients
interface Message
+interface ReadOnlyTransactionStorage
+ +interface SchedulerService
+ abstract class ServiceType
@@ -9027,7 +10914,7 @@ -interface TransactionStorage
+interface TransactionStorage : ReadOnlyTransactionStorage
+interface TxWritableStorageService : StorageService
+ @@ -9089,11 +10987,11 @@ -abstract fun commit(tx: WireTransaction, callerIdentity: Party): Unit
+abstract fun commit(states: List<StateRef>, txId: SecureHash, callerIdentity: Party): Unit
-abstract class Wallet
+class Wallet
@@ -9201,7 +11098,7 @@ -class MockStorageService : SingletonSerializeAsToken, StorageService
+class MockStorageService : SingletonSerializeAsToken, TxWritableStorageService
@@ -9604,17 +11701,18 @@ TransactionForTest()
-fun accepts(time: Instant = TEST_TX_TIME): Unit
-fun chain(vararg outputLabels: String, body: TransactionForTest.() -> Unit): TransactionForTest
+fun accepts(time: Instant = TEST_TX_TIME): LastLineShouldTestForAcceptOrFailure
+fun chain(vararg outputLabels: String, body: TransactionForTest.() -> LastLineShouldTestForAcceptOrFailure): TransactionForTest
open fun equals(other: Any?): Boolean
-infix fun fails requirement(msg: String): Unit
-fun fails_requirement(msg: String): Unit
+infix fun fails requirement(msg: String): LastLineShouldTestForAcceptOrFailure
+fun failsRequirement(msg: String): LastLineShouldTestForAcceptOrFailure
open fun hashCode(): Int
-fun input(s: () -> ContractState): <ERROR CLASS>
-fun rejects(withMessage: String? = null, time: Instant = TEST_TX_TIME): Unit
+fun input(s: () -> ContractState): Unit
+fun input(s: ContractState): Unit
+fun rejects(withMessage: String? = null, time: Instant = TEST_TX_TIME): LastLineShouldTestForAcceptOrFailure
protected fun runCommandsAndVerify(time: Instant): Unit
open fun toString(): String
-fun tweak(body: TransactionForTest.() -> Unit): TransactionForTest
+fun tweak(body: TransactionForTest.() -> LastLineShouldTestForAcceptOrFailure): LastLineShouldTestForAcceptOrFailure
@@ -9650,7 +11748,7 @@ Roots()
fun roots(body: Roots<T>.() -> Unit): Unit
-fun transaction(vararg outputStates: LabeledOutput): Unit
+fun transaction(vararg outputStates: LabeledOutput): Roots<T>
fun transaction(body: WireTransactionDSL<T>.() -> Unit): Unit
@@ -9670,11 +11768,11 @@ fun expectFailureOfTx(index: Int, message: String): Exception
-fun labelForState(state: T): String?
+fun labelForState(output: TransactionState<*>): String?
fun labelForTransaction(tx: WireTransaction): String?
fun labelForTransaction(tx: LedgerTransaction): String?
fun <C : ContractState> lookup(label: String): StateAndRef<C>
-val String.output: T
+val String.output: TransactionState<T>
val String.outputRef: StateRef
fun roots(body: Roots<T>.() -> Unit): <ERROR CLASS>
fun signAll(txnsToSign: List<WireTransaction> = txns, vararg extraKeys: KeyPair): List<SignedTransaction>
@@ -9688,9 +11786,9 @@ fun freeLocalHostAndPort(): <ERROR CLASS>
fun generateStateRef(): StateRef
-infix fun ContractState.label(label: String): LabeledOutput
+infix fun TransactionState<*>.label(label: String): LabeledOutput
inline fun <R> rootCauseExceptions(body: () -> R): R
-fun transaction(body: TransactionForTest.() -> Unit): <ERROR CLASS>
+fun transaction(body: TransactionForTest.() -> LastLineShouldTestForAcceptOrFailure): LastLineShouldTestForAcceptOrFailure
fun transactionGroup(body: TransactionGroupDSL<ContractState>.() -> Unit): <ERROR CLASS>
inline fun <reified T : ContractState> transactionGroupFor(body: TransactionGroupDSL<T>.() -> Unit): <ERROR CLASS>
@@ -9757,7 +11855,7 @@ -NonEmptySet(initial: T, set: MutableSet<T> = mutableSetOf())
+NonEmptySet(initial: T)
inner class Iterator<T, T> : MutableIterator<T>
    @@ -9791,6 +11889,19 @@
+object NonEmptySetSerializer
+ class ProgressTracker
    @@ -9970,6 +12081,21 @@
+data class TimeWindow
+ class UntrustworthyData<T>
    @@ -9986,6 +12112,7 @@
inline fun <reified T : Any> loggerFor(): <ERROR CLASS>
fun <T> nonEmptySetOf(initial: T, vararg elements: T): NonEmptySet<T>
+fun suggestInterestRateAnnouncementTimeWindow(index: String, source: String, date: LocalDate): TimeWindow
inline fun <ERROR CLASS>.trace(msg: () -> String): Unit
@@ -9998,8 +12125,109 @@ +sealed class CliParams
+ +object CliParamsSpec
+ +val DEFAULT_BASE_DIRECTORY: String
val DEMO_TOPIC: String
-val DIRNAME: String
class DemoClock : MutableClock, SerializeAsToken
    @@ -10017,6 +12245,20 @@
+enum class IRSDemoNode
+ enum class IRSDemoRole
    @@ -10047,63 +12289,11 @@
-class TraderDemoProtocolBuyer : ProtocolLogic<Unit>
- -class TraderDemoProtocolSeller : ProtocolLogic<Unit>
- fun main(args: Array<String>): Unit
fun main(args: Array<String>): Unit
fun main(args: Array<String>): Unit
-fun parseOptions(args: Array<String>, parser: <ERROR CLASS>): <ERROR CLASS>
-fun runBuyer(node: Node): Unit
-fun runSeller(myNetAddr: <ERROR CLASS>, node: Node, theirNetAddr: <ERROR CLASS>): Unit
-fun setupDirectory(mode: Role): Path
+fun runIRSDemo(args: Array<String>): Int
+fun runTraderDemo(args: Array<String>): Int
@@ -10161,10 +12351,11 @@ -AutoOfferMessage(otherSide: SingleMessageRecipient, otherSessionID: Long, dealBeingOffered: DealState)
+AutoOfferMessage(otherSide: Party, notary: Party, otherSessionID: Long, dealBeingOffered: DealState)
val dealBeingOffered: DealState
+val notary: Party
val otherSessionID: Long
-val otherSide: SingleMessageRecipient
+val otherSide: Party
@@ -10209,7 +12400,7 @@ -class Requester<T> : ProtocolLogic<SignedTransaction>
+class Requester : ProtocolLogic<SignedTransaction>
@@ -10579,7 +12734,7 @@ fun buildTransaction(type: ContractDefRef, steps: List<TransactionBuildStep>): SerializedBytes<WireTransaction>
fun commitTransaction(tx: SerializedBytes<WireTransaction>, signatures: List<WithKey>): SecureHash
fun fetchProtocolsRequiringAttention(query: StatesQuery): Map<StateRef, ProtocolRequiringAttention>
-fun fetchStates(states: List<StateRef>): Map<StateRef, ContractState?>
+fun fetchStates(states: List<StateRef>): Map<StateRef, TransactionState<ContractState>?>
fun fetchTransactions(txs: List<SecureHash>): Map<SecureHash, SignedTransaction?>
fun generateTransactionSignature(tx: SerializedBytes<WireTransaction>): WithKey
fun invokeProtocolSync(type: ProtocolRef, args: Map<String, Any?>): Any?
@@ -10587,6 +12742,7 @@ fun provideProtocolResponse(protocol: ProtocolInstanceRef, choice: SecureHash, args: Map<String, Any?>): Unit
fun queryStates(query: StatesQuery): List<StateRef>
fun serverTime(): LocalDateTime
+fun status(): <ERROR CLASS>
@@ -10607,14 +12763,15 @@ lateinit var checkpointStorage: CheckpointStorage
val configuration: NodeConfiguration
protected open fun constructStorageService(attachments: NodeAttachmentService, transactionStorage: TransactionStorage, keypair: KeyPair, identity: Party): StorageServiceImpl
+protected fun createNodeDir(): Unit
val dir: Path
open fun findMyLocation(): PhysicalLocation?
-protected open fun generateKeyPair(): KeyPair
+protected open fun generateKeyPair(): <ERROR CLASS>
lateinit var identity: IdentityService
var inNodeNetworkMapService: NetworkMapService?
var inNodeNotaryService: NotaryService?
val info: NodeInfo
-protected open fun initialiseStorageService(dir: Path): <ERROR CLASS><StorageService, CheckpointStorage>
+protected open fun initialiseStorageService(dir: Path): <ERROR CLASS><TxWritableStorageService, CheckpointStorage>
lateinit var interestRatesService: Service
var isPreviousCheckpointsPresent: Boolean
lateinit var keyManagement: E2ETestKeyManagementService
@@ -10631,15 +12788,17 @@ val networkMapService: NodeInfo?
protected open fun noNetworkMapConfigured(): <ERROR CLASS><Unit>
val platformClock: Clock
+lateinit var scheduler: SchedulerService
protected abstract val serverThread: AffinityExecutor
val services: ServiceHubInternal
val servicesThatAcceptUploads: List<AcceptsFileUpload>
+open fun setup(): AbstractNode
lateinit var smm: StateMachineManager
open fun start(): AbstractNode
protected abstract fun startMessagingService(): Unit
var started: Boolean
open fun stop(): Unit
-lateinit var storage: StorageService
+lateinit var storage: TxWritableStorageService
lateinit var wallet: WalletService
@@ -10664,17 +12823,19 @@ -Node(dir: Path, p2pAddr: <ERROR CLASS>, configuration: NodeConfiguration, networkMapAddress: NodeInfo?, advertisedServices: Set<ServiceType>, clock: Clock = NodeClock(), clientAPIs: List<Class<*>> = listOf())
+Node(dir: Path, p2pAddr: <ERROR CLASS>, webServerAddr: <ERROR CLASS>, configuration: NodeConfiguration, networkMapAddress: NodeInfo?, advertisedServices: Set<ServiceType>, clock: Clock = NodeClock(), clientAPIs: List<Class<*>> = listOf())
val DEFAULT_PORT: Int
val clientAPIs: List<Class<*>>
protected val log: <ERROR CLASS>
protected fun makeMessagingService(): MessagingService
val p2pAddr: <ERROR CLASS>
protected val serverThread: ServiceAffinityExecutor
+fun setup(): Node
fun start(): Node
protected fun startMessagingService(): Unit
fun stop(): Unit
lateinit var webServer: <ERROR CLASS>
+val webServerAddr: <ERROR CLASS>
@@ -10697,7 +12858,7 @@ -IRSSimulation(runAsync: Boolean, latencyInjector: LatencyCalculator?)
+IRSSimulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, latencyInjector: LatencyCalculator?)
fun iterate(): MessageTransfer?
val om: <ERROR CLASS>
protected fun startMainSimulation(): <ERROR CLASS><Unit>
@@ -10712,7 +12873,7 @@ -MockNetwork(threadPerNode: Boolean = false, defaultFactory: Factory = MockNetwork.DefaultFactory)
+MockNetwork(networkSendManuallyPumped: Boolean = false, threadPerNode: Boolean = false, defaultFactory: Factory = MockNetwork.DefaultFactory)
object DefaultFactory : Factory
-object WalletFiller
+fun issueInvalidState(node: AbstractNode, notary: Party = DUMMY_NOTARY): StateAndRef<*>
+fun issueMultiPartyState(nodeA: AbstractNode, nodeB: AbstractNode): StateAndRef<MultiOwnerState>
+fun issueState(node: AbstractNode): StateAndRef<*>
+kotlin.collections.Iterable
-fun issueInvalidState(node: AbstractNode, notary: Party = DUMMY_NOTARY): StateRef
-fun issueState(node: AbstractNode, notary: Party = DUMMY_NOTARY): StateRef
@@ -10962,6 +13128,42 @@ +package com.r3corda.node.services
+ package com.r3corda.node.services.api
-interface ServiceHubInternal : ServiceHub
+abstract class ServiceHubInternal : ServiceHub
@@ -11127,10 +13333,11 @@ -Oracle(identity: Party, signingKey: KeyPair)
+Oracle(identity: Party, signingKey: KeyPair, clock: Clock)
+val clock: Clock
val identity: Party
var knownFixes: FixContainer
-fun query(queries: List<FixOf>): List<Fix>
+fun query(queries: List<FixOf>, deadline: Instant): List<Fix>
fun sign(wtx: WireTransaction): LegallyIdentifiable
@@ -11153,7 +13360,7 @@ object Type : ServiceType
-class UnknownFix : Exception
+class UnknownFix : RetryableException
@@ -11218,6 +13424,44 @@ +package com.r3corda.node.services.events
+ package com.r3corda.node.services.identity
val REGISTER_PROTOCOL_TOPIC: String
-class RegistrationRequest : AbstractRequestMessage
+class RegistrationRequest : NetworkMapRequestMessage
val SUBSCRIPTION_PROTOCOL_TOPIC: String
-class SubscribeRequest : AbstractRequestMessage
+class SubscribeRequest : NetworkMapRequestMessage
-open class StorageServiceImpl : SingletonSerializeAsToken, StorageService
+open class StorageServiceImpl : SingletonSerializeAsToken, TxWritableStorageService
@@ -12032,7 +14297,7 @@ -NotaryService(smm: StateMachineManager, net: MessagingService, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider)
+NotaryService(smm: StateMachineManager, net: MessagingService, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider, networkMapCache: NetworkMapCache)
object Type : ServiceType
abstract val logger: <ERROR CLASS>
abstract val protocolFactory: Factory
@@ -12050,7 +14315,7 @@ -SimpleNotaryService(smm: StateMachineManager, net: MessagingService, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider)
+SimpleNotaryService(smm: StateMachineManager, net: MessagingService, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider, networkMapCache: NetworkMapCache)
object Type : ServiceType
val logger: <ERROR CLASS>
val protocolFactory: DefaultFactory
@@ -12065,7 +14330,7 @@ -ValidatingNotaryService(smm: StateMachineManager, net: MessagingService, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider)
+ValidatingNotaryService(smm: StateMachineManager, net: MessagingService, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider, networkMapCache: NetworkMapCache)
object Type : ServiceType
val logger: <ERROR CLASS>
val protocolFactory: Factory
@@ -12096,7 +14361,7 @@ -class NodeWalletService : SingletonSerializeAsToken, WalletService
+class NodeWalletService : InMemoryWalletService
-class WalletImpl : Wallet
- @@ -12372,6 +14618,30 @@ +object PublicKeyDeserializer
+ +object PublicKeySerializer
+ class SecureHashDeserializer<T : SecureHash>
+class SignaturesMissing : NotaryError
+ class TimestampInvalid : NotaryError
@@ -12729,7 +15013,7 @@ -abstract fun create(otherSide: SingleMessageRecipient, sendSessionID: Long, receiveSessionID: Long, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider): Service
+abstract fun create(otherSide: Party, sendSessionID: Long, receiveSessionID: Long, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider): Service
@@ -12741,8 +15025,9 @@ -Handshake(replyTo: SingleMessageRecipient, sendSessionID: Long, sessionID: Long)
+Handshake(replyTo: Party, sendSessionID: Long, sessionID: Long)
val sendSessionID: Long
+val sessionID: Long
@@ -12769,10 +15054,10 @@ -Service(otherSide: SingleMessageRecipient, sendSessionID: Long, receiveSessionID: Long, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider)
-open fun beforeCommit(wtx: WireTransaction, reqIdentity: Party): Unit
+Service(otherSide: Party, sendSessionID: Long, receiveSessionID: Long, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider)
+open fun beforeCommit(stx: SignedTransaction, reqIdentity: Party): Unit
open fun call(): Unit
-val otherSide: SingleMessageRecipient
+val otherSide: Party
val receiveSessionID: Long
val sendSessionID: Long
val timestampChecker: TimestampChecker
@@ -12788,9 +15073,9 @@ -SignRequest(txBits: SerializedBytes<WireTransaction>, callerIdentity: Party)
+SignRequest(tx: SignedTransaction, callerIdentity: Party)
val callerIdentity: Party
-val txBits: SerializedBytes<WireTransaction>
+val tx: SignedTransaction
@@ -12807,7 +15092,7 @@ -RatesFixProtocol(tx: TransactionBuilder, oracle: NodeInfo, fixOf: FixOf, expectedRate: BigDecimal, rateTolerance: BigDecimal, progressTracker: ProgressTracker = RatesFixProtocol.tracker(fixOf.name))
+RatesFixProtocol(tx: TransactionBuilder, oracle: Party, fixOf: FixOf, expectedRate: BigDecimal, rateTolerance: BigDecimal, timeOut: Duration, progressTracker: ProgressTracker = RatesFixProtocol.tracker(fixOf.name))
class FixOutOfRange : Exception
@@ -12856,7 +15143,8 @@ -SignRequest(tx: WireTransaction, replyTo: SingleMessageRecipient, sessionID: Long)
+SignRequest(tx: WireTransaction, replyTo: Party, sessionID: Long)
+val sessionID: Long
val tx: WireTransaction
@@ -12883,9 +15171,9 @@ -ResolveTransactionsProtocol(stx: SignedTransaction, otherSide: SingleMessageRecipient)
-ResolveTransactionsProtocol(wtx: WireTransaction, otherSide: SingleMessageRecipient)
-ResolveTransactionsProtocol(txHashes: Set<SecureHash>, otherSide: SingleMessageRecipient)
+ResolveTransactionsProtocol(stx: SignedTransaction, otherSide: Party)
+ResolveTransactionsProtocol(wtx: WireTransaction, otherSide: Party)
+ResolveTransactionsProtocol(txHashes: Set<SecureHash>, otherSide: Party)
class ExcessivelyLargeTransactionGraph : Exception
    @@ -12902,6 +15190,19 @@
+interface ServiceRequestMessage
+ object TwoPartyDealProtocol
-class Fixer<T : FixableDealState> : Secondary<StateRef>
+val FIX_INITIATE_TOPIC: String
+class Fixer : Secondary<StateRef>
-class Floater<T : FixableDealState> : Primary<StateRef>
+class FixingRoleDecider : ProtocolLogic<Unit>
+data class FixingSessionInitiation
+ +class Floater : Primary<StateRef>
+ @@ -13012,7 +15366,13 @@ -Instigator(otherSide: SingleMessageRecipient, notaryNode: NodeInfo, dealBeingOffered: T, myKeyPair: KeyPair, buyerSessionID: Long, progressTracker: ProgressTracker = Primary.tracker())
+Instigator(otherSide: Party, notary: Party, payload: T, myKeyPair: KeyPair, otherSessionID: Long, progressTracker: ProgressTracker = Primary.tracker())
+open val myKeyPair: KeyPair
+val notary: Party
+open val notaryNode: NodeInfo
+open val otherSessionID: Long
+open val otherSide: Party
+open val payload: T
open val progressTracker: ProgressTracker
@@ -13025,7 +15385,7 @@ -Primary(payload: U, otherSide: SingleMessageRecipient, otherSessionID: Long, myKeyPair: KeyPair, notaryNode: NodeInfo, progressTracker: ProgressTracker = Primary.tracker())
+Primary(progressTracker: ProgressTracker = Primary.tracker())
object AWAITING_PROPOSAL : Step
object COPYING_TO_REGULATOR : Step
object NOTARY : Step
@@ -13035,11 +15395,11 @@ object VERIFYING : Step
open fun call(): SignedTransaction
fun getPartialTransaction(): UntrustworthyData<SignedTransaction>
-val myKeyPair: KeyPair
-val notaryNode: NodeInfo
-val otherSessionID: Long
-val otherSide: SingleMessageRecipient
-val payload: U
+abstract val myKeyPair: KeyPair
+abstract val notaryNode: NodeInfo
+abstract val otherSessionID: Long
+abstract val otherSide: Party
+abstract val payload: U
open val progressTracker: ProgressTracker
open fun signWithOurKey(partialTX: SignedTransaction): WithKey
fun tracker(): ProgressTracker
@@ -13055,7 +15415,7 @@ -Secondary(otherSide: SingleMessageRecipient, notary: Party, sessionID: Long, progressTracker: ProgressTracker = Secondary.tracker())
+Secondary(progressTracker: ProgressTracker = Secondary.tracker())
object RECEIVING : Step
object RECORDING : Step
object SIGNING : Step
@@ -13063,10 +15423,9 @@ object VERIFYING : Step
protected abstract fun assembleSharedTX(handshake: Handshake<U>): <ERROR CLASS><TransactionBuilder, List<PublicKey>>
open fun call(): SignedTransaction
-val notary: Party
-val otherSide: SingleMessageRecipient
+abstract val otherSide: Party
open val progressTracker: ProgressTracker
-val sessionID: Long
+abstract val sessionID: Long
fun tracker(): ProgressTracker
protected abstract fun validateHandshake(handshake: Handshake<U>): Handshake<U>
@@ -13120,15 +15479,15 @@ -Buyer(otherSide: SingleMessageRecipient, notary: Party, acceptablePrice: Amount<Currency>, typeToBuy: Class<out OwnableState>, sessionID: Long)
+Buyer(otherSide: Party, notary: Party, acceptablePrice: Amount<Issued<Currency>>, typeToBuy: Class<out OwnableState>, sessionID: Long)
object RECEIVING : Step
object SIGNING : Step
object SWAPPING_SIGNATURES : Step
object VERIFYING : Step
-val acceptablePrice: Amount<Currency>
+val acceptablePrice: Amount<Issued<Currency>>
open fun call(): SignedTransaction
val notary: Party
-val otherSide: SingleMessageRecipient
+val otherSide: Party
open val progressTracker: ProgressTracker
val sessionID: Long
val typeToBuy: Class<out OwnableState>
@@ -13143,7 +15502,7 @@ -Seller(otherSide: SingleMessageRecipient, notaryNode: NodeInfo, assetToSell: StateAndRef<OwnableState>, price: Amount<Currency>, myKeyPair: KeyPair, buyerSessionID: Long, progressTracker: ProgressTracker = Seller.tracker())
+Seller(otherSide: Party, notaryNode: NodeInfo, assetToSell: StateAndRef<OwnableState>, price: Amount<Issued<Currency>>, myKeyPair: KeyPair, buyerSessionID: Long, progressTracker: ProgressTracker = Seller.tracker())
object AWAITING_PROPOSAL : Step
object NOTARY : Step
object SENDING_SIGS : Step
@@ -13154,8 +15513,8 @@ open fun call(): SignedTransaction
val myKeyPair: KeyPair
val notaryNode: NodeInfo
-val otherSide: SingleMessageRecipient
-val price: Amount<Currency>
+val otherSide: Party
+val price: Amount<Issued<Currency>>
open val progressTracker: ProgressTracker
open fun signWithOurKey(partialTX: SignedTransaction): WithKey
fun tracker(): ProgressTracker
@@ -13170,9 +15529,9 @@ -SellerTradeInfo(assetForSale: StateAndRef<OwnableState>, price: Amount<Currency>, sellerOwnerKey: PublicKey, sessionID: Long)
+SellerTradeInfo(assetForSale: StateAndRef<OwnableState>, price: Amount<Issued<Currency>>, sellerOwnerKey: PublicKey, sessionID: Long)
val assetForSale: StateAndRef<OwnableState>
-val price: Amount<Currency>
+val price: Amount<Issued<Currency>>
val sellerOwnerKey: PublicKey
val sessionID: Long
@@ -13201,8 +15560,8 @@ -UnacceptablePriceException(givenPrice: Amount<Currency>)
-val givenPrice: Amount<Currency>
+UnacceptablePriceException(givenPrice: Amount<Issued<Currency>>)
+val givenPrice: Amount<Issued<Currency>>
@@ -13217,8 +15576,204 @@ -ValidatingNotaryProtocol(otherSide: SingleMessageRecipient, sessionIdForSend: Long, sessionIdForReceive: Long, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider)
-fun beforeCommit(wtx: WireTransaction, reqIdentity: Party): Unit
+ValidatingNotaryProtocol(otherSide: Party, sessionIdForSend: Long, sessionIdForReceive: Long, timestampChecker: TimestampChecker, uniquenessProvider: UniquenessProvider)
+fun beforeCommit(stx: SignedTransaction, reqIdentity: Party): Unit
+ + + + + + +package protocols
+
    + + +Module Contents + + + +abstract class AbstractStateReplacementProtocol<T>
    + +object NotaryChangeProtocol : AbstractStateReplacementProtocol<Party>
    + +class StateReplacementException : Exception
    + +class StateReplacementRefused
    + diff --git a/docs/build/html/api/index.html b/docs/build/html/api/index.html index b1fd259ca0..0718d4e57a 100644 --- a/docs/build/html/api/index.html +++ b/docs/build/html/api/index.html @@ -17,7 +17,7 @@ -com.r3corda.contracts.asset +com.r3corda.contracts.asset @@ -143,6 +143,12 @@ +com.r3corda.node.services + + + + + com.r3corda.node.services.api @@ -161,6 +167,12 @@ +com.r3corda.node.services.events + + + + + com.r3corda.node.services.identity @@ -225,6 +237,12 @@ + + +protocols + + +

    Index

    diff --git a/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/-a-p-p-r-o-v-i-n-g.html b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/-a-p-p-r-o-v-i-n-g.html new file mode 100644 index 0000000000..8ad48ddddf --- /dev/null +++ b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/-a-p-p-r-o-v-i-n-g.html @@ -0,0 +1,42 @@ + + +AbstractStateReplacementProtocol.Acceptor.APPROVING - + + + +protocols / AbstractStateReplacementProtocol / Acceptor / APPROVING
    +
    +

    APPROVING

    +object APPROVING : Step
    +
    +
    +

    Inherited Properties

    + + + + + + + + + + + +
    +changes +open val changes: <ERROR CLASS><Change>
    +label +open val label: String
    +

    Inherited Functions

    + + + + + + + +
    +childProgressTracker +open fun childProgressTracker(): ProgressTracker?
    + + diff --git a/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/-init-.html b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/-init-.html new file mode 100644 index 0000000000..c31c8dce5b --- /dev/null +++ b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/-init-.html @@ -0,0 +1,14 @@ + + +AbstractStateReplacementProtocol.Acceptor.<init> - + + + +protocols / AbstractStateReplacementProtocol / Acceptor / <init>
    +
    +

    <init>

    +Acceptor(otherSide: Party, sessionIdForSend: Long, sessionIdForReceive: Long, progressTracker: ProgressTracker = tracker())
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/-r-e-j-e-c-t-i-n-g.html b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/-r-e-j-e-c-t-i-n-g.html new file mode 100644 index 0000000000..dbe5439a2e --- /dev/null +++ b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/-r-e-j-e-c-t-i-n-g.html @@ -0,0 +1,42 @@ + + +AbstractStateReplacementProtocol.Acceptor.REJECTING - + + + +protocols / AbstractStateReplacementProtocol / Acceptor / REJECTING
    +
    +

    REJECTING

    +object REJECTING : Step
    +
    +
    +

    Inherited Properties

    + + + + + + + + + + + +
    +changes +open val changes: <ERROR CLASS><Change>
    +label +open val label: String
    +

    Inherited Functions

    + + + + + + + +
    +childProgressTracker +open fun childProgressTracker(): ProgressTracker?
    + + diff --git a/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/-t-o-p-i-c_-c-h-a-n-g-e.html b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/-t-o-p-i-c_-c-h-a-n-g-e.html new file mode 100644 index 0000000000..9291d36264 --- /dev/null +++ b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/-t-o-p-i-c_-c-h-a-n-g-e.html @@ -0,0 +1,15 @@ + + +AbstractStateReplacementProtocol.Acceptor.TOPIC_CHANGE - + + + +protocols / AbstractStateReplacementProtocol / Acceptor / TOPIC_CHANGE
    +
    +

    TOPIC_CHANGE

    + +abstract val TOPIC_CHANGE: String
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/-t-o-p-i-c_-i-n-i-t-i-a-t-e.html b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/-t-o-p-i-c_-i-n-i-t-i-a-t-e.html new file mode 100644 index 0000000000..2ee61da22f --- /dev/null +++ b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/-t-o-p-i-c_-i-n-i-t-i-a-t-e.html @@ -0,0 +1,15 @@ + + +AbstractStateReplacementProtocol.Acceptor.TOPIC_INITIATE - + + + +protocols / AbstractStateReplacementProtocol / Acceptor / TOPIC_INITIATE
    +
    +

    TOPIC_INITIATE

    + +abstract val TOPIC_INITIATE: String
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/-v-e-r-i-f-y-i-n-g.html b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/-v-e-r-i-f-y-i-n-g.html new file mode 100644 index 0000000000..1449acfb2a --- /dev/null +++ b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/-v-e-r-i-f-y-i-n-g.html @@ -0,0 +1,42 @@ + + +AbstractStateReplacementProtocol.Acceptor.VERIFYING - + + + +protocols / AbstractStateReplacementProtocol / Acceptor / VERIFYING
    +
    +

    VERIFYING

    +object VERIFYING : Step
    +
    +
    +

    Inherited Properties

    + + + + + + + + + + + +
    +changes +open val changes: <ERROR CLASS><Change>
    +label +open val label: String
    +

    Inherited Functions

    + + + + + + + +
    +childProgressTracker +open fun childProgressTracker(): ProgressTracker?
    + + diff --git a/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/call.html b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/call.html new file mode 100644 index 0000000000..a3d1d47f1d --- /dev/null +++ b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/call.html @@ -0,0 +1,17 @@ + + +AbstractStateReplacementProtocol.Acceptor.call - + + + +protocols / AbstractStateReplacementProtocol / Acceptor / call
    +
    +

    call

    + +open fun call(): Unit
    +Overrides ProtocolLogic.call
    +

    This is where you fill out your business logic.

    +
    +
    + + diff --git a/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/index.html b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/index.html new file mode 100644 index 0000000000..a95fea183c --- /dev/null +++ b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/index.html @@ -0,0 +1,187 @@ + + +AbstractStateReplacementProtocol.Acceptor - + + + +protocols / AbstractStateReplacementProtocol / Acceptor
    +
    +

    Acceptor

    +abstract class Acceptor<T> : ProtocolLogic<Unit>
    +
    +
    +

    Types

    + + + + + + + + + + + + + + + +
    +APPROVING +object APPROVING : Step
    +REJECTING +object REJECTING : Step
    +VERIFYING +object VERIFYING : Step
    +

    Constructors

    + + + + + + + +
    +<init> +Acceptor(otherSide: Party, sessionIdForSend: Long, sessionIdForReceive: Long, progressTracker: ProgressTracker = tracker())
    +

    Properties

    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +TOPIC_CHANGE +abstract val TOPIC_CHANGE: String
    +TOPIC_INITIATE +abstract val TOPIC_INITIATE: String
    +otherSide +val otherSide: Party
    +progressTracker +open val progressTracker: ProgressTracker

    Override this to provide a ProgressTracker. If one is provided and stepped, the framework will do something +helpful with the progress reports. If this protocol is invoked as a sub-protocol of another, then the +tracker will be made a child of the current step in the parent. If its null, this protocol doesnt track +progress.

    +
    +sessionIdForReceive +val sessionIdForReceive: Long
    +sessionIdForSend +val sessionIdForSend: Long
    +

    Inherited Properties

    + + + + + + + + + + + + + + + +
    +logger +val logger: <ERROR CLASS>

    This is where you should log things to.

    +
    +psm +lateinit var psm: ProtocolStateMachine<*>

    Reference to the Fiber instance that is the top level controller for the entire flow.

    +
    +serviceHub +val serviceHub: ServiceHub

    Provides access to big, heavy classes that may be reconstructed from time to time, e.g. across restarts. It is +only available once the protocol has started, which means it cannnot be accessed in the constructor. Either +access this lazily or from inside call.

    +
    +

    Functions

    + + + + + + + +
    +call +open fun call(): Unit

    This is where you fill out your business logic.

    +
    +

    Inherited Functions

    + + + + + + + + + + + + + + + + + + + +
    +receive +fun <T : Any> receive(topic: String, sessionIDForReceive: Long, clazz: Class<T>): UntrustworthyData<T>
    +fun <T : Any> receive(topic: String, sessionIDForReceive: Long): UntrustworthyData<T>
    +send +fun send(topic: String, destination: Party, sessionID: Long, payload: Any): Unit
    +sendAndReceive +fun <T : Any> sendAndReceive(topic: String, destination: Party, sessionIDForSend: Long, sessionIDForReceive: Long, payload: Any): UntrustworthyData<T>
    +subProtocol +fun <R> subProtocol(subLogic: ProtocolLogic<R>): R

    Invokes the given subprotocol by simply passing through this ProtocolLogics reference to the +ProtocolStateMachine and then calling the call method.

    +
    +

    Companion Object Functions

    + + + + + + + +
    +tracker +fun tracker(): ProgressTracker
    +

    Inheritors

    + + + + + + + +
    +Acceptor +class Acceptor : Acceptor<Party>
    + + diff --git a/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/other-side.html b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/other-side.html new file mode 100644 index 0000000000..df32738e21 --- /dev/null +++ b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/other-side.html @@ -0,0 +1,15 @@ + + +AbstractStateReplacementProtocol.Acceptor.otherSide - + + + +protocols / AbstractStateReplacementProtocol / Acceptor / otherSide
    +
    +

    otherSide

    + +val otherSide: Party
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/progress-tracker.html b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/progress-tracker.html new file mode 100644 index 0000000000..03ebffb4a1 --- /dev/null +++ b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/progress-tracker.html @@ -0,0 +1,24 @@ + + +AbstractStateReplacementProtocol.Acceptor.progressTracker - + + + +protocols / AbstractStateReplacementProtocol / Acceptor / progressTracker
    +
    +

    progressTracker

    + +open val progressTracker: ProgressTracker
    +Overrides ProtocolLogic.progressTracker
    +

    Override this to provide a ProgressTracker. If one is provided and stepped, the framework will do something +helpful with the progress reports. If this protocol is invoked as a sub-protocol of another, then the +tracker will be made a child of the current step in the parent. If its null, this protocol doesnt track +progress.

    +

    Note that this has to return a tracker before the protocol is invoked. You cant change your mind half way +through.

    +
    +
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/session-id-for-receive.html b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/session-id-for-receive.html new file mode 100644 index 0000000000..d226ee0006 --- /dev/null +++ b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/session-id-for-receive.html @@ -0,0 +1,15 @@ + + +AbstractStateReplacementProtocol.Acceptor.sessionIdForReceive - + + + +protocols / AbstractStateReplacementProtocol / Acceptor / sessionIdForReceive
    +
    +

    sessionIdForReceive

    + +val sessionIdForReceive: Long
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/session-id-for-send.html b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/session-id-for-send.html new file mode 100644 index 0000000000..e0acb9df94 --- /dev/null +++ b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/session-id-for-send.html @@ -0,0 +1,15 @@ + + +AbstractStateReplacementProtocol.Acceptor.sessionIdForSend - + + + +protocols / AbstractStateReplacementProtocol / Acceptor / sessionIdForSend
    +
    +

    sessionIdForSend

    + +val sessionIdForSend: Long
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/tracker.html b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/tracker.html new file mode 100644 index 0000000000..6f7226bd5d --- /dev/null +++ b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-acceptor/tracker.html @@ -0,0 +1,15 @@ + + +AbstractStateReplacementProtocol.Acceptor.tracker - + + + +protocols / AbstractStateReplacementProtocol / Acceptor / tracker
    +
    +

    tracker

    + +fun tracker(): ProgressTracker
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-handshake/-init-.html b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-handshake/-init-.html new file mode 100644 index 0000000000..8e0a0e34a9 --- /dev/null +++ b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-handshake/-init-.html @@ -0,0 +1,14 @@ + + +AbstractStateReplacementProtocol.Handshake.<init> - + + + +protocols / AbstractStateReplacementProtocol / Handshake / <init>
    +
    +

    <init>

    +Handshake(sessionIdForSend: Long, replyTo: Party, sessionID: Long)
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-handshake/index.html b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-handshake/index.html new file mode 100644 index 0000000000..ff3bd5511f --- /dev/null +++ b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-handshake/index.html @@ -0,0 +1,64 @@ + + +AbstractStateReplacementProtocol.Handshake - + + + +protocols / AbstractStateReplacementProtocol / Handshake
    +
    +

    Handshake

    +class Handshake : AbstractRequestMessage
    +
    +
    +

    Constructors

    + + + + + + + +
    +<init> +Handshake(sessionIdForSend: Long, replyTo: Party, sessionID: Long)
    +

    Properties

    + + + + + + + + + + + +
    +sessionID +val sessionID: Long
    +sessionIdForSend +val sessionIdForSend: Long
    +

    Inherited Properties

    + + + + + + + +
    +replyToParty +val replyToParty: Party
    +

    Inherited Functions

    + + + + + + + +
    +getReplyTo +open fun getReplyTo(networkMapCache: NetworkMapCache): MessageRecipients
    + + diff --git a/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-handshake/session-i-d.html b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-handshake/session-i-d.html new file mode 100644 index 0000000000..5562ba3381 --- /dev/null +++ b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-handshake/session-i-d.html @@ -0,0 +1,16 @@ + + +AbstractStateReplacementProtocol.Handshake.sessionID - + + + +protocols / AbstractStateReplacementProtocol / Handshake / sessionID
    +
    +

    sessionID

    + +val sessionID: Long
    +Overrides ServiceRequestMessage.sessionID
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-handshake/session-id-for-send.html b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-handshake/session-id-for-send.html new file mode 100644 index 0000000000..00903d6f7f --- /dev/null +++ b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-handshake/session-id-for-send.html @@ -0,0 +1,15 @@ + + +AbstractStateReplacementProtocol.Handshake.sessionIdForSend - + + + +protocols / AbstractStateReplacementProtocol / Handshake / sessionIdForSend
    +
    +

    sessionIdForSend

    + +val sessionIdForSend: Long
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-init-.html b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-init-.html new file mode 100644 index 0000000000..3c1d4ac94d --- /dev/null +++ b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-init-.html @@ -0,0 +1,23 @@ + + +AbstractStateReplacementProtocol.<init> - + + + +protocols / AbstractStateReplacementProtocol / <init>
    +
    +

    <init>

    +AbstractStateReplacementProtocol()
    +

    Abstract protocol to be used for replacing one state with another, for example when changing the notary of a state. +Notably this requires a one to one replacement of states, states cannot be split, merged or issued as part of these +protocols.

    +

    The Instigator assembles the transaction for state replacement and sends out change proposals to all participants +(Acceptor) of that state. If participants agree to the proposed change, they each sign the transaction. +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.

    +
    +
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/-init-.html b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/-init-.html new file mode 100644 index 0000000000..4e44255124 --- /dev/null +++ b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/-init-.html @@ -0,0 +1,14 @@ + + +AbstractStateReplacementProtocol.Instigator.<init> - + + + +protocols / AbstractStateReplacementProtocol / Instigator / <init>
    +
    +

    <init>

    +Instigator(originalState: StateAndRef<S>, modification: T, progressTracker: ProgressTracker = tracker())
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/-n-o-t-a-r-y.html b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/-n-o-t-a-r-y.html new file mode 100644 index 0000000000..156fb15244 --- /dev/null +++ b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/-n-o-t-a-r-y.html @@ -0,0 +1,42 @@ + + +AbstractStateReplacementProtocol.Instigator.NOTARY - + + + +protocols / AbstractStateReplacementProtocol / Instigator / NOTARY
    +
    +

    NOTARY

    +object NOTARY : Step
    +
    +
    +

    Inherited Properties

    + + + + + + + + + + + +
    +changes +open val changes: <ERROR CLASS><Change>
    +label +open val label: String
    +

    Inherited Functions

    + + + + + + + +
    +childProgressTracker +open fun childProgressTracker(): ProgressTracker?
    + + diff --git a/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/-s-i-g-n-i-n-g.html b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/-s-i-g-n-i-n-g.html new file mode 100644 index 0000000000..03ef9a7d34 --- /dev/null +++ b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/-s-i-g-n-i-n-g.html @@ -0,0 +1,42 @@ + + +AbstractStateReplacementProtocol.Instigator.SIGNING - + + + +protocols / AbstractStateReplacementProtocol / Instigator / SIGNING
    +
    +

    SIGNING

    +object SIGNING : Step
    +
    +
    +

    Inherited Properties

    + + + + + + + + + + + +
    +changes +open val changes: <ERROR CLASS><Change>
    +label +open val label: String
    +

    Inherited Functions

    + + + + + + + +
    +childProgressTracker +open fun childProgressTracker(): ProgressTracker?
    + + diff --git a/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/-t-o-p-i-c_-c-h-a-n-g-e.html b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/-t-o-p-i-c_-c-h-a-n-g-e.html new file mode 100644 index 0000000000..c36e7d3f97 --- /dev/null +++ b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/-t-o-p-i-c_-c-h-a-n-g-e.html @@ -0,0 +1,15 @@ + + +AbstractStateReplacementProtocol.Instigator.TOPIC_CHANGE - + + + +protocols / AbstractStateReplacementProtocol / Instigator / TOPIC_CHANGE
    +
    +

    TOPIC_CHANGE

    + +abstract val TOPIC_CHANGE: String
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/-t-o-p-i-c_-i-n-i-t-i-a-t-e.html b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/-t-o-p-i-c_-i-n-i-t-i-a-t-e.html new file mode 100644 index 0000000000..7466a341a8 --- /dev/null +++ b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/-t-o-p-i-c_-i-n-i-t-i-a-t-e.html @@ -0,0 +1,15 @@ + + +AbstractStateReplacementProtocol.Instigator.TOPIC_INITIATE - + + + +protocols / AbstractStateReplacementProtocol / Instigator / TOPIC_INITIATE
    +
    +

    TOPIC_INITIATE

    + +abstract val TOPIC_INITIATE: String
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/call.html b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/call.html new file mode 100644 index 0000000000..1a592d2eff --- /dev/null +++ b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/call.html @@ -0,0 +1,17 @@ + + +AbstractStateReplacementProtocol.Instigator.call - + + + +protocols / AbstractStateReplacementProtocol / Instigator / call
    +
    +

    call

    + +open fun call(): StateAndRef<S>
    +Overrides ProtocolLogic.call
    +

    This is where you fill out your business logic.

    +
    +
    + + diff --git a/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/index.html b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/index.html new file mode 100644 index 0000000000..a06b1246d5 --- /dev/null +++ b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/index.html @@ -0,0 +1,175 @@ + + +AbstractStateReplacementProtocol.Instigator - + + + +protocols / AbstractStateReplacementProtocol / Instigator
    +
    +

    Instigator

    +abstract class Instigator<S : ContractState, T> : ProtocolLogic<StateAndRef<S>>
    +
    +
    +

    Types

    + + + + + + + + + + + +
    +NOTARY +object NOTARY : Step
    +SIGNING +object SIGNING : Step
    +

    Constructors

    + + + + + + + +
    +<init> +Instigator(originalState: StateAndRef<S>, modification: T, progressTracker: ProgressTracker = tracker())
    +

    Properties

    + + + + + + + + + + + + + + + + + + + + + + + +
    +TOPIC_CHANGE +abstract val TOPIC_CHANGE: String
    +TOPIC_INITIATE +abstract val TOPIC_INITIATE: String
    +modification +val modification: T
    +originalState +val originalState: StateAndRef<S>
    +progressTracker +open val progressTracker: ProgressTracker

    Override this to provide a ProgressTracker. If one is provided and stepped, the framework will do something +helpful with the progress reports. If this protocol is invoked as a sub-protocol of another, then the +tracker will be made a child of the current step in the parent. If its null, this protocol doesnt track +progress.

    +
    +

    Inherited Properties

    + + + + + + + + + + + + + + + +
    +logger +val logger: <ERROR CLASS>

    This is where you should log things to.

    +
    +psm +lateinit var psm: ProtocolStateMachine<*>

    Reference to the Fiber instance that is the top level controller for the entire flow.

    +
    +serviceHub +val serviceHub: ServiceHub

    Provides access to big, heavy classes that may be reconstructed from time to time, e.g. across restarts. It is +only available once the protocol has started, which means it cannnot be accessed in the constructor. Either +access this lazily or from inside call.

    +
    +

    Functions

    + + + + + + + +
    +call +open fun call(): StateAndRef<S>

    This is where you fill out your business logic.

    +
    +

    Inherited Functions

    + + + + + + + + + + + + + + + + + + + +
    +receive +fun <T : Any> receive(topic: String, sessionIDForReceive: Long): UntrustworthyData<T>
    +fun <T : Any> receive(topic: String, sessionIDForReceive: Long, clazz: Class<T>): UntrustworthyData<T>
    +send +fun send(topic: String, destination: Party, sessionID: Long, payload: Any): Unit
    +sendAndReceive +fun <T : Any> sendAndReceive(topic: String, destination: Party, sessionIDForSend: Long, sessionIDForReceive: Long, payload: Any): UntrustworthyData<T>
    +subProtocol +fun <R> subProtocol(subLogic: ProtocolLogic<R>): R

    Invokes the given subprotocol by simply passing through this ProtocolLogics reference to the +ProtocolStateMachine and then calling the call method.

    +
    +

    Companion Object Functions

    + + + + + + + +
    +tracker +fun tracker(): ProgressTracker
    +

    Inheritors

    + + + + + + + +
    +Instigator +class Instigator<T : ContractState> : Instigator<T, Party>
    + + diff --git a/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/modification.html b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/modification.html new file mode 100644 index 0000000000..43a88f397c --- /dev/null +++ b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/modification.html @@ -0,0 +1,15 @@ + + +AbstractStateReplacementProtocol.Instigator.modification - + + + +protocols / AbstractStateReplacementProtocol / Instigator / modification
    +
    +

    modification

    + +val modification: T
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/original-state.html b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/original-state.html new file mode 100644 index 0000000000..1fdc2258a1 --- /dev/null +++ b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/original-state.html @@ -0,0 +1,15 @@ + + +AbstractStateReplacementProtocol.Instigator.originalState - + + + +protocols / AbstractStateReplacementProtocol / Instigator / originalState
    +
    +

    originalState

    + +val originalState: StateAndRef<S>
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/progress-tracker.html b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/progress-tracker.html new file mode 100644 index 0000000000..ebf7ba287d --- /dev/null +++ b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/progress-tracker.html @@ -0,0 +1,24 @@ + + +AbstractStateReplacementProtocol.Instigator.progressTracker - + + + +protocols / AbstractStateReplacementProtocol / Instigator / progressTracker
    +
    +

    progressTracker

    + +open val progressTracker: ProgressTracker
    +Overrides ProtocolLogic.progressTracker
    +

    Override this to provide a ProgressTracker. If one is provided and stepped, the framework will do something +helpful with the progress reports. If this protocol is invoked as a sub-protocol of another, then the +tracker will be made a child of the current step in the parent. If its null, this protocol doesnt track +progress.

    +

    Note that this has to return a tracker before the protocol is invoked. You cant change your mind half way +through.

    +
    +
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/tracker.html b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/tracker.html new file mode 100644 index 0000000000..df3e81ee67 --- /dev/null +++ b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-instigator/tracker.html @@ -0,0 +1,15 @@ + + +AbstractStateReplacementProtocol.Instigator.tracker - + + + +protocols / AbstractStateReplacementProtocol / Instigator / tracker
    +
    +

    tracker

    + +fun tracker(): ProgressTracker
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-proposal/index.html b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-proposal/index.html new file mode 100644 index 0000000000..21b3a0f1bc --- /dev/null +++ b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-proposal/index.html @@ -0,0 +1,48 @@ + + +AbstractStateReplacementProtocol.Proposal - + + + +protocols / AbstractStateReplacementProtocol / Proposal
    +
    +

    Proposal

    +interface Proposal<T>
    +
    +
    +

    Properties

    + + + + + + + + + + + + + + + +
    +modification +abstract val modification: T
    +stateRef +abstract val stateRef: StateRef
    +stx +abstract val stx: SignedTransaction
    +

    Inheritors

    + + + + + + + +
    +Proposal +data class Proposal : Proposal<Party>
    + + diff --git a/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-proposal/modification.html b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-proposal/modification.html new file mode 100644 index 0000000000..cd6b3b51eb --- /dev/null +++ b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-proposal/modification.html @@ -0,0 +1,15 @@ + + +AbstractStateReplacementProtocol.Proposal.modification - + + + +protocols / AbstractStateReplacementProtocol / Proposal / modification
    +
    +

    modification

    + +abstract val modification: T
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-proposal/state-ref.html b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-proposal/state-ref.html new file mode 100644 index 0000000000..06d89d95b5 --- /dev/null +++ b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-proposal/state-ref.html @@ -0,0 +1,15 @@ + + +AbstractStateReplacementProtocol.Proposal.stateRef - + + + +protocols / AbstractStateReplacementProtocol / Proposal / stateRef
    +
    +

    stateRef

    + +abstract val stateRef: StateRef
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-proposal/stx.html b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-proposal/stx.html new file mode 100644 index 0000000000..6288eece27 --- /dev/null +++ b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-proposal/stx.html @@ -0,0 +1,15 @@ + + +AbstractStateReplacementProtocol.Proposal.stx - + + + +protocols / AbstractStateReplacementProtocol / Proposal / stx
    +
    +

    stx

    + +abstract val stx: SignedTransaction
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-result/error.html b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-result/error.html new file mode 100644 index 0000000000..9f7df323a0 --- /dev/null +++ b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-result/error.html @@ -0,0 +1,15 @@ + + +AbstractStateReplacementProtocol.Result.error - + + + +protocols / AbstractStateReplacementProtocol / Result / error
    +
    +

    error

    + +val error: StateReplacementRefused?
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-result/index.html b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-result/index.html new file mode 100644 index 0000000000..de49d73a84 --- /dev/null +++ b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-result/index.html @@ -0,0 +1,48 @@ + + +AbstractStateReplacementProtocol.Result - + + + +protocols / AbstractStateReplacementProtocol / Result
    +
    +

    Result

    +data class Result
    +
    +
    +

    Properties

    + + + + + + + + + + + +
    +error +val error: StateReplacementRefused?
    +sig +val sig: WithKey?
    +

    Companion Object Functions

    + + + + + + + + + + + +
    +noError +fun noError(sig: WithKey): Result
    +withError +fun withError(error: StateReplacementRefused): Result
    + + diff --git a/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-result/no-error.html b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-result/no-error.html new file mode 100644 index 0000000000..48aa0b8412 --- /dev/null +++ b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-result/no-error.html @@ -0,0 +1,15 @@ + + +AbstractStateReplacementProtocol.Result.noError - + + + +protocols / AbstractStateReplacementProtocol / Result / noError
    +
    +

    noError

    + +fun noError(sig: WithKey): Result
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-result/sig.html b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-result/sig.html new file mode 100644 index 0000000000..3565005869 --- /dev/null +++ b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-result/sig.html @@ -0,0 +1,15 @@ + + +AbstractStateReplacementProtocol.Result.sig - + + + +protocols / AbstractStateReplacementProtocol / Result / sig
    +
    +

    sig

    + +val sig: WithKey?
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-result/with-error.html b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-result/with-error.html new file mode 100644 index 0000000000..c32249c9cd --- /dev/null +++ b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/-result/with-error.html @@ -0,0 +1,15 @@ + + +AbstractStateReplacementProtocol.Result.withError - + + + +protocols / AbstractStateReplacementProtocol / Result / withError
    +
    +

    withError

    + +fun withError(error: StateReplacementRefused): Result
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-abstract-state-replacement-protocol/index.html b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/index.html new file mode 100644 index 0000000000..91099a6f50 --- /dev/null +++ b/docs/build/html/api/protocols/-abstract-state-replacement-protocol/index.html @@ -0,0 +1,85 @@ + + +AbstractStateReplacementProtocol - + + + +protocols / AbstractStateReplacementProtocol
    +
    +

    AbstractStateReplacementProtocol

    +abstract class AbstractStateReplacementProtocol<T>
    +

    Abstract protocol to be used for replacing one state with another, for example when changing the notary of a state. +Notably this requires a one to one replacement of states, states cannot be split, merged or issued as part of these +protocols.

    +

    The Instigator assembles the transaction for state replacement and sends out change proposals to all participants +(Acceptor) of that state. If participants agree to the proposed change, they each sign the transaction. +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.

    +
    +
    +
    +
    +

    Types

    + + + + + + + + + + + + + + + + + + + + + + + +
    +Acceptor +abstract class Acceptor<T> : ProtocolLogic<Unit>
    +Handshake +class Handshake : AbstractRequestMessage
    +Instigator +abstract class Instigator<S : ContractState, T> : ProtocolLogic<StateAndRef<S>>
    +Proposal +interface Proposal<T>
    +Result +data class Result
    +

    Constructors

    + + + + + + + +
    +<init> +AbstractStateReplacementProtocol()

    Abstract protocol to be used for replacing one state with another, for example when changing the notary of a state. +Notably this requires a one to one replacement of states, states cannot be split, merged or issued as part of these +protocols.

    +
    +

    Inheritors

    + + + + + + + +
    +NotaryChangeProtocol +object NotaryChangeProtocol : AbstractStateReplacementProtocol<Party>

    A protocol to be used for changing a states Notary. This is required since all input states to a transaction +must point to the same notary.

    +
    + + diff --git a/docs/build/html/api/protocols/-notary-change-protocol/-acceptor/-init-.html b/docs/build/html/api/protocols/-notary-change-protocol/-acceptor/-init-.html new file mode 100644 index 0000000000..7db93d79cf --- /dev/null +++ b/docs/build/html/api/protocols/-notary-change-protocol/-acceptor/-init-.html @@ -0,0 +1,14 @@ + + +NotaryChangeProtocol.Acceptor.<init> - + + + +protocols / NotaryChangeProtocol / Acceptor / <init>
    +
    +

    <init>

    +Acceptor(otherSide: Party, sessionIdForSend: Long, sessionIdForReceive: Long, progressTracker: ProgressTracker = tracker())
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-notary-change-protocol/-acceptor/-t-o-p-i-c_-c-h-a-n-g-e.html b/docs/build/html/api/protocols/-notary-change-protocol/-acceptor/-t-o-p-i-c_-c-h-a-n-g-e.html new file mode 100644 index 0000000000..168f35ce8d --- /dev/null +++ b/docs/build/html/api/protocols/-notary-change-protocol/-acceptor/-t-o-p-i-c_-c-h-a-n-g-e.html @@ -0,0 +1,16 @@ + + +NotaryChangeProtocol.Acceptor.TOPIC_CHANGE - + + + +protocols / NotaryChangeProtocol / Acceptor / TOPIC_CHANGE
    +
    +

    TOPIC_CHANGE

    + +val TOPIC_CHANGE: String
    +Overrides Acceptor.TOPIC_CHANGE
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-notary-change-protocol/-acceptor/-t-o-p-i-c_-i-n-i-t-i-a-t-e.html b/docs/build/html/api/protocols/-notary-change-protocol/-acceptor/-t-o-p-i-c_-i-n-i-t-i-a-t-e.html new file mode 100644 index 0000000000..978bcfb00b --- /dev/null +++ b/docs/build/html/api/protocols/-notary-change-protocol/-acceptor/-t-o-p-i-c_-i-n-i-t-i-a-t-e.html @@ -0,0 +1,16 @@ + + +NotaryChangeProtocol.Acceptor.TOPIC_INITIATE - + + + +protocols / NotaryChangeProtocol / Acceptor / TOPIC_INITIATE
    +
    +

    TOPIC_INITIATE

    + +val TOPIC_INITIATE: String
    +Overrides Acceptor.TOPIC_INITIATE
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-notary-change-protocol/-acceptor/index.html b/docs/build/html/api/protocols/-notary-change-protocol/-acceptor/index.html new file mode 100644 index 0000000000..c70e850134 --- /dev/null +++ b/docs/build/html/api/protocols/-notary-change-protocol/-acceptor/index.html @@ -0,0 +1,87 @@ + + +NotaryChangeProtocol.Acceptor - + + + +protocols / NotaryChangeProtocol / Acceptor
    +
    +

    Acceptor

    +class Acceptor : Acceptor<Party>
    +
    +
    +

    Constructors

    + + + + + + + +
    +<init> +Acceptor(otherSide: Party, sessionIdForSend: Long, sessionIdForReceive: Long, progressTracker: ProgressTracker = tracker())
    +

    Properties

    + + + + + + + + + + + + + + + +
    +TOPIC_CHANGE +val TOPIC_CHANGE: String
    +TOPIC_INITIATE +val TOPIC_INITIATE: String
    +progressTracker +val progressTracker: ProgressTracker

    Override this to provide a ProgressTracker. If one is provided and stepped, the framework will do something +helpful with the progress reports. If this protocol is invoked as a sub-protocol of another, then the +tracker will be made a child of the current step in the parent. If its null, this protocol doesnt track +progress.

    +
    +

    Inherited Properties

    + + + + + + + + + + + + + + + +
    +otherSide +val otherSide: Party
    +sessionIdForReceive +val sessionIdForReceive: Long
    +sessionIdForSend +val sessionIdForSend: Long
    +

    Inherited Functions

    + + + + + + + +
    +call +open fun call(): Unit

    This is where you fill out your business logic.

    +
    + + diff --git a/docs/build/html/api/protocols/-notary-change-protocol/-acceptor/progress-tracker.html b/docs/build/html/api/protocols/-notary-change-protocol/-acceptor/progress-tracker.html new file mode 100644 index 0000000000..e47486f61f --- /dev/null +++ b/docs/build/html/api/protocols/-notary-change-protocol/-acceptor/progress-tracker.html @@ -0,0 +1,24 @@ + + +NotaryChangeProtocol.Acceptor.progressTracker - + + + +protocols / NotaryChangeProtocol / Acceptor / progressTracker
    +
    +

    progressTracker

    + +val progressTracker: ProgressTracker
    +Overrides Acceptor.progressTracker
    +

    Override this to provide a ProgressTracker. If one is provided and stepped, the framework will do something +helpful with the progress reports. If this protocol is invoked as a sub-protocol of another, then the +tracker will be made a child of the current step in the parent. If its null, this protocol doesnt track +progress.

    +

    Note that this has to return a tracker before the protocol is invoked. You cant change your mind half way +through.

    +
    +
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-notary-change-protocol/-instigator/-init-.html b/docs/build/html/api/protocols/-notary-change-protocol/-instigator/-init-.html new file mode 100644 index 0000000000..b1481fc359 --- /dev/null +++ b/docs/build/html/api/protocols/-notary-change-protocol/-instigator/-init-.html @@ -0,0 +1,14 @@ + + +NotaryChangeProtocol.Instigator.<init> - + + + +protocols / NotaryChangeProtocol / Instigator / <init>
    +
    +

    <init>

    +Instigator(originalState: StateAndRef<T>, newNotary: Party, progressTracker: ProgressTracker = tracker())
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-notary-change-protocol/-instigator/-t-o-p-i-c_-c-h-a-n-g-e.html b/docs/build/html/api/protocols/-notary-change-protocol/-instigator/-t-o-p-i-c_-c-h-a-n-g-e.html new file mode 100644 index 0000000000..332f5fe996 --- /dev/null +++ b/docs/build/html/api/protocols/-notary-change-protocol/-instigator/-t-o-p-i-c_-c-h-a-n-g-e.html @@ -0,0 +1,16 @@ + + +NotaryChangeProtocol.Instigator.TOPIC_CHANGE - + + + +protocols / NotaryChangeProtocol / Instigator / TOPIC_CHANGE
    +
    +

    TOPIC_CHANGE

    + +val TOPIC_CHANGE: String
    +Overrides Instigator.TOPIC_CHANGE
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-notary-change-protocol/-instigator/-t-o-p-i-c_-i-n-i-t-i-a-t-e.html b/docs/build/html/api/protocols/-notary-change-protocol/-instigator/-t-o-p-i-c_-i-n-i-t-i-a-t-e.html new file mode 100644 index 0000000000..cdb13aae53 --- /dev/null +++ b/docs/build/html/api/protocols/-notary-change-protocol/-instigator/-t-o-p-i-c_-i-n-i-t-i-a-t-e.html @@ -0,0 +1,16 @@ + + +NotaryChangeProtocol.Instigator.TOPIC_INITIATE - + + + +protocols / NotaryChangeProtocol / Instigator / TOPIC_INITIATE
    +
    +

    TOPIC_INITIATE

    + +val TOPIC_INITIATE: String
    +Overrides Instigator.TOPIC_INITIATE
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-notary-change-protocol/-instigator/index.html b/docs/build/html/api/protocols/-notary-change-protocol/-instigator/index.html new file mode 100644 index 0000000000..2bb5b8f35c --- /dev/null +++ b/docs/build/html/api/protocols/-notary-change-protocol/-instigator/index.html @@ -0,0 +1,81 @@ + + +NotaryChangeProtocol.Instigator - + + + +protocols / NotaryChangeProtocol / Instigator
    +
    +

    Instigator

    +class Instigator<T : ContractState> : Instigator<T, Party>
    +
    +
    +

    Constructors

    + + + + + + + +
    +<init> +Instigator(originalState: StateAndRef<T>, newNotary: Party, progressTracker: ProgressTracker = tracker())
    +

    Properties

    + + + + + + + + + + + +
    +TOPIC_CHANGE +val TOPIC_CHANGE: String
    +TOPIC_INITIATE +val TOPIC_INITIATE: String
    +

    Inherited Properties

    + + + + + + + + + + + + + + + +
    +modification +val modification: T
    +originalState +val originalState: StateAndRef<S>
    +progressTracker +open val progressTracker: ProgressTracker

    Override this to provide a ProgressTracker. If one is provided and stepped, the framework will do something +helpful with the progress reports. If this protocol is invoked as a sub-protocol of another, then the +tracker will be made a child of the current step in the parent. If its null, this protocol doesnt track +progress.

    +
    +

    Inherited Functions

    + + + + + + + +
    +call +open fun call(): StateAndRef<S>

    This is where you fill out your business logic.

    +
    + + diff --git a/docs/build/html/api/protocols/-notary-change-protocol/-proposal/-init-.html b/docs/build/html/api/protocols/-notary-change-protocol/-proposal/-init-.html new file mode 100644 index 0000000000..864c7a3abc --- /dev/null +++ b/docs/build/html/api/protocols/-notary-change-protocol/-proposal/-init-.html @@ -0,0 +1,14 @@ + + +NotaryChangeProtocol.Proposal.<init> - + + + +protocols / NotaryChangeProtocol / Proposal / <init>
    +
    +

    <init>

    +Proposal(stateRef: StateRef, modification: Party, stx: SignedTransaction)
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-notary-change-protocol/-proposal/index.html b/docs/build/html/api/protocols/-notary-change-protocol/-proposal/index.html new file mode 100644 index 0000000000..da2c656f97 --- /dev/null +++ b/docs/build/html/api/protocols/-notary-change-protocol/-proposal/index.html @@ -0,0 +1,48 @@ + + +NotaryChangeProtocol.Proposal - + + + +protocols / NotaryChangeProtocol / Proposal
    +
    +

    Proposal

    +data class Proposal : Proposal<Party>
    +
    +
    +

    Constructors

    + + + + + + + +
    +<init> +Proposal(stateRef: StateRef, modification: Party, stx: SignedTransaction)
    +

    Properties

    + + + + + + + + + + + + + + + +
    +modification +val modification: Party
    +stateRef +val stateRef: StateRef
    +stx +val stx: SignedTransaction
    + + diff --git a/docs/build/html/api/protocols/-notary-change-protocol/-proposal/modification.html b/docs/build/html/api/protocols/-notary-change-protocol/-proposal/modification.html new file mode 100644 index 0000000000..0aba201dd3 --- /dev/null +++ b/docs/build/html/api/protocols/-notary-change-protocol/-proposal/modification.html @@ -0,0 +1,16 @@ + + +NotaryChangeProtocol.Proposal.modification - + + + +protocols / NotaryChangeProtocol / Proposal / modification
    +
    +

    modification

    + +val modification: Party
    +Overrides Proposal.modification
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-notary-change-protocol/-proposal/state-ref.html b/docs/build/html/api/protocols/-notary-change-protocol/-proposal/state-ref.html new file mode 100644 index 0000000000..937188b054 --- /dev/null +++ b/docs/build/html/api/protocols/-notary-change-protocol/-proposal/state-ref.html @@ -0,0 +1,16 @@ + + +NotaryChangeProtocol.Proposal.stateRef - + + + +protocols / NotaryChangeProtocol / Proposal / stateRef
    +
    +

    stateRef

    + +val stateRef: StateRef
    +Overrides Proposal.stateRef
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-notary-change-protocol/-proposal/stx.html b/docs/build/html/api/protocols/-notary-change-protocol/-proposal/stx.html new file mode 100644 index 0000000000..78c8426e42 --- /dev/null +++ b/docs/build/html/api/protocols/-notary-change-protocol/-proposal/stx.html @@ -0,0 +1,16 @@ + + +NotaryChangeProtocol.Proposal.stx - + + + +protocols / NotaryChangeProtocol / Proposal / stx
    +
    +

    stx

    + +val stx: SignedTransaction
    +Overrides Proposal.stx
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-notary-change-protocol/-t-o-p-i-c_-c-h-a-n-g-e.html b/docs/build/html/api/protocols/-notary-change-protocol/-t-o-p-i-c_-c-h-a-n-g-e.html new file mode 100644 index 0000000000..0c16622f62 --- /dev/null +++ b/docs/build/html/api/protocols/-notary-change-protocol/-t-o-p-i-c_-c-h-a-n-g-e.html @@ -0,0 +1,15 @@ + + +NotaryChangeProtocol.TOPIC_CHANGE - + + + +protocols / NotaryChangeProtocol / TOPIC_CHANGE
    +
    +

    TOPIC_CHANGE

    + +val TOPIC_CHANGE: String
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-notary-change-protocol/-t-o-p-i-c_-i-n-i-t-i-a-t-e.html b/docs/build/html/api/protocols/-notary-change-protocol/-t-o-p-i-c_-i-n-i-t-i-a-t-e.html new file mode 100644 index 0000000000..3831614b96 --- /dev/null +++ b/docs/build/html/api/protocols/-notary-change-protocol/-t-o-p-i-c_-i-n-i-t-i-a-t-e.html @@ -0,0 +1,15 @@ + + +NotaryChangeProtocol.TOPIC_INITIATE - + + + +protocols / NotaryChangeProtocol / TOPIC_INITIATE
    +
    +

    TOPIC_INITIATE

    + +val TOPIC_INITIATE: String
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-notary-change-protocol/index.html b/docs/build/html/api/protocols/-notary-change-protocol/index.html new file mode 100644 index 0000000000..33875bba49 --- /dev/null +++ b/docs/build/html/api/protocols/-notary-change-protocol/index.html @@ -0,0 +1,62 @@ + + +NotaryChangeProtocol - + + + +protocols / NotaryChangeProtocol
    +
    +

    NotaryChangeProtocol

    +object NotaryChangeProtocol : AbstractStateReplacementProtocol<Party>
    +

    A protocol to be used for changing a states Notary. This is required since all input states to a transaction +must point to the same notary.

    +

    The Instigator assembles the transaction for notary replacement and sends out change proposals to all participants +(Acceptor) of that state. If participants agree to the proposed change, they each sign the transaction. +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.

    +
    +
    +
    +
    +

    Types

    + + + + + + + + + + + + + + + +
    +Acceptor +class Acceptor : Acceptor<Party>
    +Instigator +class Instigator<T : ContractState> : Instigator<T, Party>
    +Proposal +data class Proposal : Proposal<Party>
    +

    Properties

    + + + + + + + + + + + +
    +TOPIC_CHANGE +val TOPIC_CHANGE: String
    +TOPIC_INITIATE +val TOPIC_INITIATE: String
    + + diff --git a/docs/build/html/api/protocols/-state-replacement-exception/-init-.html b/docs/build/html/api/protocols/-state-replacement-exception/-init-.html new file mode 100644 index 0000000000..57ccd3b864 --- /dev/null +++ b/docs/build/html/api/protocols/-state-replacement-exception/-init-.html @@ -0,0 +1,14 @@ + + +StateReplacementException.<init> - + + + +protocols / StateReplacementException / <init>
    +
    +

    <init>

    +StateReplacementException(error: StateReplacementRefused)
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-state-replacement-exception/error.html b/docs/build/html/api/protocols/-state-replacement-exception/error.html new file mode 100644 index 0000000000..c05da6c0e1 --- /dev/null +++ b/docs/build/html/api/protocols/-state-replacement-exception/error.html @@ -0,0 +1,15 @@ + + +StateReplacementException.error - + + + +protocols / StateReplacementException / error
    +
    +

    error

    + +val error: StateReplacementRefused
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-state-replacement-exception/index.html b/docs/build/html/api/protocols/-state-replacement-exception/index.html new file mode 100644 index 0000000000..7f51731f0c --- /dev/null +++ b/docs/build/html/api/protocols/-state-replacement-exception/index.html @@ -0,0 +1,36 @@ + + +StateReplacementException - + + + +protocols / StateReplacementException
    +
    +

    StateReplacementException

    +class StateReplacementException : Exception
    +
    +
    +

    Constructors

    + + + + + + + +
    +<init> +StateReplacementException(error: StateReplacementRefused)
    +

    Properties

    + + + + + + + +
    +error +val error: StateReplacementRefused
    + + diff --git a/docs/build/html/api/protocols/-state-replacement-refused/-init-.html b/docs/build/html/api/protocols/-state-replacement-refused/-init-.html new file mode 100644 index 0000000000..f9451cb809 --- /dev/null +++ b/docs/build/html/api/protocols/-state-replacement-refused/-init-.html @@ -0,0 +1,15 @@ + + +StateReplacementRefused.<init> - + + + +protocols / StateReplacementRefused / <init>
    +
    +

    <init>

    +StateReplacementRefused(identity: Party, state: StateRef, detail: String?)
    +

    Thrown when a participant refuses proposed the state replacement

    +
    +
    + + diff --git a/docs/build/html/api/protocols/-state-replacement-refused/detail.html b/docs/build/html/api/protocols/-state-replacement-refused/detail.html new file mode 100644 index 0000000000..8d7304e88c --- /dev/null +++ b/docs/build/html/api/protocols/-state-replacement-refused/detail.html @@ -0,0 +1,15 @@ + + +StateReplacementRefused.detail - + + + +protocols / StateReplacementRefused / detail
    +
    +

    detail

    + +val detail: String?
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-state-replacement-refused/identity.html b/docs/build/html/api/protocols/-state-replacement-refused/identity.html new file mode 100644 index 0000000000..50be129ce5 --- /dev/null +++ b/docs/build/html/api/protocols/-state-replacement-refused/identity.html @@ -0,0 +1,15 @@ + + +StateReplacementRefused.identity - + + + +protocols / StateReplacementRefused / identity
    +
    +

    identity

    + +val identity: Party
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-state-replacement-refused/index.html b/docs/build/html/api/protocols/-state-replacement-refused/index.html new file mode 100644 index 0000000000..f924b5a88e --- /dev/null +++ b/docs/build/html/api/protocols/-state-replacement-refused/index.html @@ -0,0 +1,61 @@ + + +StateReplacementRefused - + + + +protocols / StateReplacementRefused
    +
    +

    StateReplacementRefused

    +class StateReplacementRefused
    +

    Thrown when a participant refuses proposed the state replacement

    +
    +
    +

    Constructors

    + + + + + + + +
    +<init> +StateReplacementRefused(identity: Party, state: StateRef, detail: String?)

    Thrown when a participant refuses proposed the state replacement

    +
    +

    Properties

    + + + + + + + + + + + + + + + +
    +detail +val detail: String?
    +identity +val identity: Party
    +state +val state: StateRef
    +

    Functions

    + + + + + + + +
    +toString +fun toString(): String
    + + diff --git a/docs/build/html/api/protocols/-state-replacement-refused/state.html b/docs/build/html/api/protocols/-state-replacement-refused/state.html new file mode 100644 index 0000000000..c0e3915d45 --- /dev/null +++ b/docs/build/html/api/protocols/-state-replacement-refused/state.html @@ -0,0 +1,15 @@ + + +StateReplacementRefused.state - + + + +protocols / StateReplacementRefused / state
    +
    +

    state

    + +val state: StateRef
    +
    +
    + + diff --git a/docs/build/html/api/protocols/-state-replacement-refused/to-string.html b/docs/build/html/api/protocols/-state-replacement-refused/to-string.html new file mode 100644 index 0000000000..928400ff58 --- /dev/null +++ b/docs/build/html/api/protocols/-state-replacement-refused/to-string.html @@ -0,0 +1,15 @@ + + +StateReplacementRefused.toString - + + + +protocols / StateReplacementRefused / toString
    +
    +

    toString

    + +fun toString(): String
    +
    +
    + + diff --git a/docs/build/html/api/protocols/index.html b/docs/build/html/api/protocols/index.html new file mode 100644 index 0000000000..b4414f9f07 --- /dev/null +++ b/docs/build/html/api/protocols/index.html @@ -0,0 +1,51 @@ + + +protocols - + + + +protocols
    +
    +

    Package protocols

    +

    Types

    + + + + + + + + + + + + + + + +
    +AbstractStateReplacementProtocol +abstract class AbstractStateReplacementProtocol<T>

    Abstract protocol to be used for replacing one state with another, for example when changing the notary of a state. +Notably this requires a one to one replacement of states, states cannot be split, merged or issued as part of these +protocols.

    +
    +NotaryChangeProtocol +object NotaryChangeProtocol : AbstractStateReplacementProtocol<Party>

    A protocol to be used for changing a states Notary. This is required since all input states to a transaction +must point to the same notary.

    +
    +StateReplacementRefused +class StateReplacementRefused

    Thrown when a participant refuses proposed the state replacement

    +
    +

    Exceptions

    + + + + + + + +
    +StateReplacementException +class StateReplacementException : Exception
    + + diff --git a/docs/build/html/building-the-docs.html b/docs/build/html/building-the-docs.html index 45e63161ed..ec6da11f84 100644 --- a/docs/build/html/building-the-docs.html +++ b/docs/build/html/building-the-docs.html @@ -89,8 +89,8 @@
  • What’s included?
  • Getting set up
  • Data model
  • -
  • Transaction Data Types
  • -
  • Consensus Model
  • +
  • Data types
  • +
  • Consensus model
  • Networking and messaging
  • Running the demos
  • Node administration
  • @@ -102,6 +102,7 @@
  • Writing a contract
  • Protocol state machines
  • Writing oracle services
  • +
  • Event scheduling

Appendix

Appendix

  • Building the documentation
  • @@ -325,6 +328,38 @@ really necessary. In other words, don’t do this:

    The latter is easier to catch and handle if later necessary, and the type name should explain what went wrong.

    Note that Kotlin does not require exception types to be declared in method prototypes like Java does.

    +
    +

    5. Properties

    +

    Where we want a public property to have one super-type in public and another sub-type in private (or internal), perhaps +to expose additional methods with a greater level of access to the code within the enclosing class, the style should be:

    +
    class PrivateFoo : PublicFoo
    +
    +private val _foo = PrivateFoo()
    +val foo: PublicFoo get() = _foo
    +
    +
    +

    Notably:

    +
      +
    • The public property should have an explicit and more restrictive type, most likely a super class or interface.
    • +
    • The private, backed property should begin with underscore but otherwise have the same name as the public property. +The underscore resolves a potential property name clash, and avoids naming such as “privateFoo”. If the type or use +of the private property is different enough that there is no naming collision, prefer the distinct names without +an underscore.
    • +
    • The underscore prefix is not a general pattern for private properties.
    • +
    • The public property should not have an additional backing field but use “get()” to return an appropriate copy of the +private field.
    • +
    • The public property should optionally wrap the returned value in an immutable wrapper, such as Guava’s immutable +collection wrappers, if that is appropriate.
    • +
    • If the code following “get()” is succinct, prefer a one-liner formatting of the public property as above, otherwise +put the “get()” on the line below, indented.
    • +
    +
    +
    +

    6. Compiler warnings

    +

    We do not allow compiler warnings, except in the experimental module where the usual standards do not apply and warnings +are suppressed. If a warning exists it should be either fixed or suppressed using @SuppressWarnings and if suppressed +there must be an accompanying explanation in the code for why the warning is a false positive.

    +
    diff --git a/docs/build/html/consensus.html b/docs/build/html/consensus.html index e573477af5..580dc8a601 100644 --- a/docs/build/html/consensus.html +++ b/docs/build/html/consensus.html @@ -8,7 +8,7 @@ - Consensus Model — R3 Corda latest documentation + Consensus model — R3 Corda latest documentation @@ -32,7 +32,7 @@ - + @@ -90,13 +90,15 @@
  • What’s included?
  • Getting set up
  • Data model
  • -
  • Transaction Data Types
  • -
  • Consensus Model

    Appendix

      @@ -149,7 +152,7 @@
      • Docs »
      • -
      • Consensus Model
      • +
      • Consensus model
      • @@ -164,11 +167,11 @@
        -

        Consensus Model

        +

        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 data model)
        2. -
        3. Consensus over state uniqueness – parties can reach certainty the 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 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.

        @@ -178,75 +181,97 @@

        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:

        -
        interface ContractState {
        -    /** Contract by which the state belongs */
        -    val contract: Contract
        -
        -    /** Identity of the notary that ensures this state is not used as an input to a transaction more than once */
        -    val notary: Party
        +The data model is extended so that 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
        + */
        +data class TransactionState<out T : ContractState>(
        +        /** 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).

        +

        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

        +

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

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

        -
        -

        Validation

        -

        The Notary does not validate transaction integrity (i.e. does not run contracts or check signatures) to minimise the exposed data. -Validation would require the caller to reveal the whole transaction history chain, resulting in a privacy leak.

        -

        However, this makes it open to “denial of state” attacks, where a party could submit any invalid transaction to the Notary and thus “block” someone else’s states. -That 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 the Notary can see the entire 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).

        -
        -
        -

        Multiple Notaries

        -

        More than one Notary can exist in the network. This gives the following benefits:

        +

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

        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)

        +
        +

        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.

        +

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

        -
        -

        Implementation & Usage

        -

        At present we have single basic implementation of a Notary that uses a UniquenessProvider storing committed input states in memory:

        -
        class InMemoryUniquenessProvider() : UniquenessProvider {
        -    /** For each input state store the consuming transaction information */
        -    private val committedStates = HashMap<StateRef, ConsumingTx>()
        -
        -    override fun commit(tx: WireTransaction, callerIdentity: Party) {
        -        ...
        -    }
        +
        +

        Running a Notary Service

        +

        At present we have two basic implementations that store committed input states in memory:

        +
          +
        • SimpleNotaryService – commits the provided transaction without any validation
        • +
        • ValidatingNotaryService – retrieves and validates the whole transaction history (including the given transaction) before committing
        • +
        +

        To run one of these services the node has to simply specify either SimpleNotaryService.Type or ValidatingNotaryService.Type in its advertisedServices set, and the correct type will be initialised.

        +
        +
        +

        Obtaining a signature

        +

        To obtain a signature from a notary use NotaryProtocol.Client, passing in a WireTransaction. +The protocol will work out which notary needs to be called based on the input states and the timestamp command. +For example, the following snippet can be used when writing a custom protocol:

        +
        fun getNotarySignature(wtx: WireTransaction): DigitalSignature.LegallyIdentifiable {
        +    return subProtocol(NotaryProtocol.Client(wtx))
         }
        -...
        +
        +
        +

        On conflict the NotaryProtocol with throw a NotaryException containing the conflict details:

        +
        /** Specifies the consuming transaction for the conflicting input state */
        +data class Conflict(val stateHistory: Map<StateRef, ConsumingTx>)
        +
         /**
          * Specifies the transaction id, the position of the consumed state in the inputs, and
          * the caller identity requesting the commit
        @@ -254,20 +279,25 @@ or perform timestamping and notarisation at the same time, which is the
         data class ConsumingTx(val id: SecureHash, val inputIndex: Int, val requestingParty: Party)
         
        -

        To obtain a signature from a Notary use NotaryProtocol, passing in a WireTransaction. -The protocol will work out which Notary needs to be called based on the input states and the timestamp command. -For example, the following snippet can be used when writing a custom protocol:

        -
        private fun getNotarySignature(wtx: WireTransaction): DigitalSignature.LegallyIdentifiable {
        -    return subProtocol(NotaryProtocol(wtx))
        +

        Conflict handling and resolution is currently the responsibility of the protocol author.

        +
        +
        +

        Changing notaries

        +

        To change the notary for an input state, use the NotaryChangeProtocol. For example:

        +
        fun changeNotary(originalState: StateAndRef<ContractState>,
        +                 newNotary: Party): StateAndRef<ContractState> {
        +    val protocol = NotaryChangeProtocol.Instigator(originalState, newNotary)
        +    return subProtocol(protocol)
         }
         
        -

        On conflict the NotaryProtocol with throw a NotaryException containing the conflict details:

        -
        /** Specifies the consuming transaction for the conflicting input state */
        -data class Conflict(val stateHistory: Map<StateRef, ConsumingTx>)
        -
        -
        -

        Conflict handling and resolution is currently the responsibility of the protocol author.

        +

        The protocol will:

        +
          +
        1. Construct a transaction with the old state as the input and the new state as the output
        2. +
        3. 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)
        4. +
        5. Obtain the old notary signature
        6. +
        7. Record and distribute the final transaction to the participants so that everyone possesses the new state
        8. +
        @@ -281,7 +311,7 @@ For example, the following snippet can be used when writing a custom protocol:Next - Previous + Previous
        diff --git a/docs/build/html/data-model.html b/docs/build/html/data-model.html index 6301b9affb..5ee70359cb 100644 --- a/docs/build/html/data-model.html +++ b/docs/build/html/data-model.html @@ -31,7 +31,7 @@ - + @@ -99,8 +99,8 @@
      • Cons
      -
    • Transaction Data Types
    • -
    • Consensus Model
    • +
    • Data types
    • +
    • Consensus model
    • Networking and messaging
    • Running the demos
    • Node administration
    • @@ -112,6 +112,7 @@
    • Writing a contract
    • Protocol state machines
    • Writing oracle services
    • +
    • Event scheduling

    Appendix

      @@ -404,7 +405,7 @@ something that can be trivially fixed with data model changes.

    Appendix

      diff --git a/docs/build/html/getting-set-up.html b/docs/build/html/getting-set-up.html index ef1ba8531f..b517ec5d6c 100644 --- a/docs/build/html/getting-set-up.html +++ b/docs/build/html/getting-set-up.html @@ -94,8 +94,8 @@
  • Data model
  • -
  • Transaction Data Types
  • -
  • Consensus Model
  • +
  • Data types
  • +
  • Consensus model
  • Networking and messaging
  • Running the demos
  • Node administration
  • @@ -107,6 +107,7 @@
  • Writing a contract
  • Protocol state machines
  • Writing oracle services
  • +
  • Event scheduling
  • Appendix

    Appendix

      @@ -194,21 +195,23 @@ following hypothesis:

    • Cons
    -
  • Transaction Data Types
  • Building the documentation

    Appendix

      @@ -162,44 +163,58 @@

      What’s included?

      -

      The current prototype consists of a small amount of code that defines:

      -
        -
      • Key data structures.
      • -
      • Algorithms that work with them, such as serialising, hashing, signing, and verification of the signatures.
      • -
      • Two smart contracts that implement a notion of a cash claim and basic commercial paper (implemented twice, in two -different programming languages). These are simplified versions of the real things.
      • -
      • Unit tests that check the algorithms do what is expected, and which verify the behaviour of the smart contracts.
      • -
      • API documentation and tutorials (what you’re reading)
      • -
      • A simple standalone node that uses an embedded message queue broker as its P2P messaging layer.
      • -
      • A trading demo that runs the node in either a listening/buying mode, or a connecting/selling mode, and swaps some -fake commercial paper assets for some self-issued IOU cash, using a generic protocol framework.
      • -
      • It also includes two oracles: one for precise timestamping and another for interest rate swaps.
      • +

        The Corda prototype currently includes:

        +
          +
        • A peer to peer network with message persistence and delivery retries.

          +
        • +
        • Key data structures for defining contracts and states.

          +
        • +
        • +
          Smart contracts:
          +
            +
          • Cash
          • +
          • Cash obligations
          • +
          • Interest rate swaps
          • +
          • Commercial paper (implemented in both Java and Kotlin for comparison)
          • +
          +
          +
          +
        • +
        • Algorithms that work with them, such as serialising, hashing, signing, and verification of the signatures.

          +
        • +
        • API documentation and tutorials (what you’re reading).

          +
        • +
        • A business process orchestration framework.

          +
        • +
        • Notary infrastructure for precise timestamping, and elimination of double spending without a blockchain.

          +
        • +
        • A simple REST API.

          +

        Some things it does not currently include but should gain later are:

        • Sandboxing, distribution or publication of smart contract code
        • -
        • A peer to peer network
        • Database persistence
        • -
        • An API for integrating external software
        • A user interface for administration
        • Many other things
        -

        You can browse the JIRA bug tracker.

        The prototype’s goal is rapid exploration of ideas. Therefore in places it takes shortcuts that a production system would not in order to boost productivity:

        • It uses an object graph serialization framework instead of a well specified, vendor neutral protocol.
        • -
        • It uses secp256r1, an obsolete elliptic curve.
        • It uses the default, out of the box Apache Artemis MQ protocol instead of AMQP/1.0 (although switching should be easy)
        • +
        • There is no inter-node SSL or other encryption yet.

        Contracts

        The primary goal of this prototype is to implement various kinds of contracts and verify that useful business logic can be expressed with the data model, developing and refining an API along the way. To that end there are currently -two contracts in the repository:

        +four contracts in the repository:

        1. Cash
        2. Commercial paper
        3. +
        4. Nettable obligations
        5. +
        6. Interest rate swaps

        Cash implements the idea of a claim on some quantity of deposits at some institutional party, denominated in some currency, identified by some deposit reference. A deposit reference is an opaque byte array which is usable by @@ -212,11 +227,12 @@ at which they may be redeemed. The contract allows the paper to be issued, trade contract is implemented twice, once in Java and once in a language called Kotlin.

        InterestRateSwap implements a vanilla OTC same currency bilateral fixed / floating leg swap. For further details, see The Interest Rate Swap Contract

        +

        Obligation implements a bilaterally or multi-laterally nettable, fungible obligation that can default.

        Each contract comes with unit tests.

        Kotlin

        -

        The prototype is written in a language called Kotlin. Kotlin is a language that targets the JVM +

        Corda is written in a language called Kotlin. Kotlin is a language that targets the JVM and can be thought of as a simpler Scala, with much better Java interop. It is developed by and has commercial support from JetBrains, the makers of the IntelliJ IDE and other popular developer tools.

        As Kotlin is very new, without a doubt you have not encountered it before. Don’t worry: it is designed as a better @@ -224,13 +240,6 @@ Java for industrial use and as such, the syntax was carefully designed to be rea the language, after only a few minutes of introduction.

        Due to the seamless Java interop the use of Kotlin to extend the platform is not required and the tutorial shows how to write contracts in both Kotlin and Java. You can read more about why Kotlin is a potentially strong successor to Java here.

        -

        Kotlin programs use the regular Java standard library and ordinary Java frameworks. Frameworks used at this time are:

        -
          -
        • JUnit for unit testing
        • -
        • Kryo for serialisation (this is not intended to be permanent)
        • -
        • Gradle for the build
        • -
        • Guava for a few utility functions
        • -
      diff --git a/docs/build/html/irs.html b/docs/build/html/irs.html index 9eef4f819f..948ac804e7 100644 --- a/docs/build/html/irs.html +++ b/docs/build/html/irs.html @@ -90,8 +90,8 @@
    • What’s included?
    • Getting set up
    • Data model
    • -
    • Transaction Data Types
    • -
    • Consensus Model
    • +
    • Data types
    • +
    • Consensus model
    • Networking and messaging
    • Running the demos
    • Node administration
    • @@ -107,6 +107,7 @@
    • Writing a contract
    • Protocol state machines
    • Writing oracle services
    • +
    • Event scheduling

    Appendix

    Appendix

    Appendix

      @@ -110,6 +111,7 @@
    • Steps to cut a release
    • Release notes
    • @@ -165,12 +167,96 @@

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

      Unreleased

      -

      Here are changes in git master that haven’t yet made it to a snapshot release:

      +

      There are currently no unreleased changes.

      +
      +
      +

      Milestone 1

      +

      Highlights of this release:

      +
        +
      • Event scheduling. States in the ledger can now request protocols to be invoked at particular times, for states +considered relevant by the wallet.

        +
      • +
      • Upgrades to the notary/consensus service support:

        +
        +
          +
        • There is now a way to change the notary controlling a state.
        • +
        • You can pick between validating and non-validating notaries, these let you select your privacy/robustness tradeoff.
        • +
        +
        +
      • +
      • A new obligation contract that supports bilateral and multilateral netting of obligations, default tracking and +more.

        +
      • +
      • Improvements to the financial type system, with core classes and contracts made more generic.

        +
      • +
      • Switch to a better digital signature algorithm: ed25519 instead of the previous JDK default of secp256r1.

        +
      • +
      • A new integration test suite.

        +
      • +
      • A new Java unit testing DSL for contracts, similar in spirit to the one already developed for Kotlin users (which +depended on Kotlin specific features).

        +
      • +
      • An experimental module, where developers who want to work with the latest Corda code can check in contracts/cordapp +code before it’s been fully reviewed. Code in this module has compiler warnings suppressed but we will still make +sure it compiles across refactorings.

        +
      • +
      • Persistence improvements: transaction data is now stored to disk and automatic protocol resume is now implemented.

        +
      • +
      • Many smaller bug fixes, cleanups and improvements.

        +
      • +
      +

      We have new documentation on:

        -
      • The cash contract has moved from com.r3corda.contracts to com.r3corda.contracts.cash.
      • -
      • Amount class is now generic, to support non-currency types (such as assets, or currency with additional information).
      • -
      • Refactored the Cash contract to have a new FungibleAsset superclass, to model all countable assets that can be merged -and split (currency, barrels of oil, etc.)
      • +
      • Event scheduling
      • +
      • Data types
      • +
      • Consensus model
      • +
      +

      Summary of API changes (not exhaustive):

      +
        +
      • Notary/consensus service:

        +
        +
          +
        • NotaryService is now extensible.
        • +
        • Every ContractState now has to specify a participants field, which is a list of parties that are able to +consume this state in a valid transaction. This is used for e.g. making sure all relevant parties obtain the updated +state when changing a notary.
        • +
        • Introduced TransactionState, which wraps ContractState, and is used when defining a transaction output. +The notary field is moved from ContractState into TransactionState.
        • +
        • Every transaction now has a type field, which specifies custom build & validation rules for that transaction type. +Currently two types are supported: General (runs the default build and validation logic) and NotaryChange ( +contract code is not run during validation, checks that the notary field is the only difference between the +inputs and outputs). +TransactionBuilder() is now abstract, you should use TransactionType.General.Builder() for building transactions.
        • +
        +
        +
      • +
      • The cash contract has moved from com.r3corda.contracts to com.r3corda.contracts.cash

        +
      • +
      • Amount class is now generic, to support non-currency types such as physical assets. Where you previously had just +Amount, you should now use Amount<Currency>.

        +
      • +
      • Refactored the Cash contract to have a new FungibleAsset superclass, to model all countable assets that can be merged +and split (currency, barrels of oil, etc.)

        +
      • +
      • Messaging:

        +
        +
          +
        • addMessageHandler now has a different signature as part of error handling changes.
        • +
        • If you want to return nothing to a protocol, use Ack instead of Unit from now on.
        • +
        +
        +
      • +
      • In the IRS contract, dateOffset is now an integer instead of an enum.

        +
      • +
      • In contracts, you now use tx.getInputs and tx.getOutputs instead of getInStates and getOutStates. This is +just a renaming.

        +
      • +
      • A new NonEmptySet type has been added for cases where you wish to express that you have a collection of unique +objects which cannot be empty.

        +
      • +
      • Please use the global newSecureRandom() function rather than instantiating your own SecureRandom’s from now on, as +the custom function forces the use of non-blocking random drivers on Linux.

        +
      diff --git a/docs/build/html/release-process.html b/docs/build/html/release-process.html index 96de61e5fe..ae657bc878 100644 --- a/docs/build/html/release-process.html +++ b/docs/build/html/release-process.html @@ -32,7 +32,7 @@ - + @@ -90,8 +90,8 @@
    • What’s included?
    • Getting set up
    • Data model
    • -
    • Transaction Data Types
    • -
    • Consensus Model
    • +
    • Data types
    • +
    • Consensus model
    • Networking and messaging
    • Running the demos
    • Node administration
    • @@ -103,6 +103,7 @@
    • Writing a contract
    • Protocol state machines
    • Writing oracle services
    • +
    • Event scheduling

    Appendix

      @@ -206,7 +207,7 @@ Minor changes to the branch don’t have to be announced unless it’d b Next - Previous + Previous diff --git a/docs/build/html/robots.txt b/docs/build/html/robots.txt new file mode 100644 index 0000000000..1f53798bb4 --- /dev/null +++ b/docs/build/html/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: / diff --git a/docs/build/html/running-the-demos.html b/docs/build/html/running-the-demos.html index 4f5080aea5..2273488cb4 100644 --- a/docs/build/html/running-the-demos.html +++ b/docs/build/html/running-the-demos.html @@ -90,8 +90,8 @@
    • What’s included?
    • Getting set up
    • Data model
    • -
    • Transaction Data Types
    • -
    • Consensus Model
    • +
    • Data types
    • +
    • Consensus model
    • Networking and messaging
    • Running the demos

      Appendix

      Appendix

        diff --git a/docs/build/html/searchindex.js b/docs/build/html/searchindex.js index b6ba315656..784423c143 100644 --- a/docs/build/html/searchindex.js +++ b/docs/build/html/searchindex.js @@ -1 +1 @@ -Search.setIndex({envversion:47,filenames:["building-the-docs","codestyle","consensus","data-model","getting-set-up","index","inthebox","irs","messaging","node-administration","oracles","protocol-state-machines","release-notes","release-process","running-the-demos","transaction-data-types","tutorial-contract","visualiser","where-to-start"],objects:{},objnames:{},objtypes:{},terms:{"0_xx":4,"1mb":11,"8u45":4,"_before_":11,"_do_":11,"_is_":11,"_mbeans_":9,"abstract":[3,11],"boolean":[3,16],"break":[10,13,16],"byte":[1,3,6,11],"case":[1,2,3,8,10,11,15,16],"catch":[1,4,11],"class":[1,2,5,7,8,10,11,12,15],"default":[1,4,6,11,14,16],"export":[9,11,18],"final":[2,3,4,7,8,11,16],"float":[6,7],"function":[1,3,5,6,7,8,10,11,14,15],"import":[1,3,4,8,11,13,16,18],"instanceof":16,"int":[1,2,16],"long":[1,3,8,11,16],"new":[1,3,4,5,6,7,8,9,11,12,13,16,18],"null":[10,16],"public":[1,3,6,8,9,10,11,15,16],"return":[1,2,7,8,9,10,11,16,18],"short":[8,13,16],"static":[3,10,11,16,18],"switch":[6,11,16],"throw":[1,2,10,11,16],"transient":11,"true":[3,8,10,16,17],"try":[1,3,11,14,16,17,18],"var":16,"void":16,"while":15,abil:[3,8],abl:[3,8,10],abort:2,about:[1,2,3],abov:[3,7,8,11,16],absolut:3,abstractnod:10,accept:[1,2,3,8,11,16],acceptablepric:11,access:[3,4,8,9,10,11,16],accid:11,accident:1,accord:18,accordingli:8,account:[3,15],accrual:7,accur:10,accuraci:3,achiev:[2,3,8],acknowledg:11,across:[3,11],act:[2,3,8,10,11],action:[16,18],activ:[7,14],actor:[1,3,11],actual:[4,7,8,10,11,16],adapt:[1,10,11],add:[1,8,9,11,15,16],addarg:16,addcommand:11,addinputst:[11,16],addit:[1,3,12,15,16],addition:[10,11,13],addmessagehandl:8,addoutputst:[11,16],address:[2,3,8,11,16],adjust:[1,7,18],admin:4,administr:[5,6],advanc:[5,7],advantag:3,adventur:18,advertis:10,advic:13,affect:[4,10],affection:16,affinityexecutor:1,afraid:1,after:[2,3,4,6,7,10,11,16,17],again:[3,7,8,10,11,14,16],against:[3,7,11,16],agent:9,aggreg:[3,16],agre:[7,11],agreement:[3,7,15],ahead:11,aim:[1,3],algorithm:[3,6,16,17],alic:[16,17],aliceaddr:8,alicegetsback:[16,17],alicenod:8,aliv:11,all:[0,1,2,3,4,7,8,9,10,11,12,13,14,16,18],allevi:2,allow:[1,2,3,6,7,10,11,15,16,18],allpossiblerecipi:8,almost:[11,16],along:[2,6,8,10,11,16],alreadi:[1,10,11,16],alright:11,also:[1,2,3,4,6,7,8,9,11,14,15,16,18],alt:16,alter:[11,16],altern:[0,1,9],although:[3,6,7,8,16,18],alwai:[1,3,9,11,16],amounnt:11,amount:[3,5,6,7,11,12],amqp:6,analysi:3,andresen:3,ani:[1,2,3,7,8,9,10,11,13,15,16,18],annot:[1,11,16],announc:13,anonym:3,anoth:[2,4,6,9,10,11,16],answer:[1,10],anticip:1,anybodi:3,anyon:16,anyth:[2,3,8,10,11,16],anywher:[8,10,16],apach:[6,8],apart:2,api:[0,1,5,6,9,10,11,13,14],app:[9,13,18],appear:16,append:9,appendix:5,appli:[1,3,7,16],applic:[3,10,18],applyfix:7,appoint:2,approach:[3,5],appropri:8,approv:[3,11],arbitrari:[1,3,10,11,16],arbitrarili:6,architectur:[5,10],area:[8,15],aren:[11,16,18],arg:[16,17],arguabl:10,argument:[1,3,8,11,16],aris:3,around:[3,8,10,11,13,15,16,17],arrai:[3,6,11],arrang:11,arriv:[10,11],arrow:[4,7],artemi:6,articl:[2,3,8,10,11,18],artifact:16,ask:[1,11,16],aspect:[11,18],assembl:3,assemblesharedtx:11,asset:[5,6,11,12,15],assetforsal:11,assetmismatchexcept:11,assettosel:11,assettypenam:11,assign:10,assist:[11,16,17],associ:[2,3,8,15,16],assum:[3,10,11,16],assumpt:11,atom:[3,10,11,14,16],attach:[3,5],attack:2,attempt:[3,4,5,8,11],attent:11,attest:[2,10],attribut:1,audit:[3,11],authent:2,authenticatedobject:[15,16],author:[1,2,3,8,11,13,18],authoris:11,auto:[1,16],autom:[3,16,18],automat:[0,8,11,16,18],avail:[0,7,8,9,10,13,16],avoid:[1,3,11],awai:[3,11,14],awar:[1,11],awg:13,awkward:[1,11],axi:7,back:[3,10,11,15,16],backend:8,background:[1,3,8],backport:13,backtick:16,backward:[11,13],bad:[1,11,16],balanc:[2,3,16],band:11,bandwidth:1,bank:[3,7,15,18],bankrupt:16,bankruptci:[3,10],barrel:12,base:[1,2,3,5,7,8,15],basi:[7,9],basic:[1,2,3,5,6,8],bat:14,bear:[11,16],beauti:17,becaus:[1,3,4,8,9,10,11,16],becom:[1,3,7,11,13],been:[2,3,4,7,10,11,13,16],befor:[2,3,6,7,10,11,13,15,16],beforehand:14,begin:[3,14,16,18],behav:16,behaviour:[2,6,9],behind:[11,16],belong:2,below:[3,7,11,18],benefit:[2,11,16],best:[1,14,18],bet:10,better:[1,5,6,16,17],between:[1,3,7,8,10,11,12,13,14,15,16],beyond:[3,16],big:[1,3,11,16],bigdecim:10,bilater:[6,7],bill:16,bin:14,binari:[3,10],bind:[2,3,10],bip:3,bit:[11,16,17,18],bitbucket:4,bitcoinj:11,blah:1,blank:[1,16],block:[1,2,3,5,8,10,11,16],blockchain:[3,11],bloom:1,bloomfilt:1,blow:14,blue:[7,17],bob:16,bobaddr:8,bobnod:8,bodi:1,boil:3,bond:16,bookkeep:[6,16],boost:6,borrow:17,both:[2,3,6,7,8,10,11,14,16],bottom:11,bound:[10,11],box:[6,18],branch:13,breach:3,bread:18,breadth:11,brief:12,briefli:[8,17],bring:3,broadcast:[3,8],broke:1,broker:6,brows:6,bug:[1,6,13],bugfix:13,bui:[6,11,18],builder:16,built:[11,16],bulk:3,bullet:1,bunch:[14,16],bundl:3,busi:[3,6,8,10,11,15,16,18],businesscalendar:15,butter:18,buyer:5,buyersessionid:11,bytearrai:8,bytecod:[3,11,16],cach:8,calcul:[7,11,15,16],calendar:[7,10,15],calibr:3,call:[1,2,3,6,7,8,9,11,13,16],callback:[1,8,11],caller:[2,16],callerident:2,came:11,camel:1,can:[0,1,2,3,4,6,7,8,9,10,11,12,14,15,16,17,18],cannot:[2,3,4,10,16],capabl:16,capit:1,capitan:0,care:[1,3,8,10,11],carefulli:6,cash:[3,5,6,7,10,11,12,14],cashkt:16,cashsigningpubkei:11,cashstat:11,caus:[1,16],center:16,certain:[1,6,16],certainti:2,cev:4,chain:[2,3,10,11,16],challeng:3,chanc:[1,11],chang:[0,1,2,3,7,8,10,11,12,13,15,16,17,18],channel:11,charact:1,charg:10,check:[1,2,4,5,6,10,11],checkabl:10,checkdepend:11,checksufficientsignatur:11,chf:15,child:11,children:11,childrenfor:11,choic:[1,2,3],choos:[2,4,16],chosen:[2,3],chunk:18,circl:17,claim:[3,6,16],clean:11,clear:[11,15],clearer:[8,11],clearli:1,click:[4,17],client:[9,10],clock:[10,14],clone:[1,4],close:10,closer:2,closur:1,cloud:9,cluster:2,cmd:16,coars:3,code:0,codebas:[1,16],cognit:3,coin:3,colleagu:1,collect:[1,9],collector:[1,9,11],colour:14,column:9,com:[0,4,12],combin:[3,5,16],come:[3,6,11,13],command:[0,2,3,4,5,7,9,10,11,14,15],commanddata:10,commerci:[5,6,10,11,12,14],commercial_pap:16,commercialpap:[6,16,17],commercialpapertest:[16,17],commit:[2,11,13],committedst:2,commod:15,common:[3,7,11,15,16],commonleg:7,commonli:16,commun:4,compani:10,companion:[11,16],compar:[3,8],compat:13,compel:2,compil:[14,16],complet:[3,8,11,14,16],complex:[1,3,15,16],complic:[11,16],compon:8,compos:[11,15,16],compris:7,comput:[7,10,11],concept:[2,3,10,11,16],conceptu:11,concern:[3,11,16],conclus:[3,10],concurrenthashmap:1,condit:[2,10,11],config:9,configur:[4,9,11,14],confirm:[2,4,8],conflict:[2,3,5],confus:11,connect:[6,9,16],consid:[1,3,7,10,13,16],consist:[3,6,7,11],constant:[1,16],constantli:10,constraint:10,construct:[1,8,10,11,16,18],constructor:[10,16],consult:10,consum:[2,3],consumingtx:2,consumpt:10,contact:[4,11],contain:[2,3,7,8,9,10,11,13,14,15,16,18],content:[1,3,4,8,9,10,16],context:[1,3,9,10,15],continu:[5,7],contract:[2,3,5],contractst:[2,15,16,17],contractstateref:16,contrast:[3,10,11],control:[1,2,3,4,9,11,16,18],conveni:[1,3,16],convent:[7,11],convers:15,convert:[7,15,16],convinc:11,copi:[1,3,8,11,16,18],copyonwritearraylist:1,copyright:1,corda:[2,3,4],core:[8,15,16],corner:4,correct:[3,13,16],correctli:[3,10,16],correspond:16,correspondingli:1,cost:[10,16],could:[1,2,3,10,11,15,16],count:7,countabl:12,counter:[1,11],counterparti:7,countri:[10,15],coupl:[10,11],cours:[9,10,16,18],cover:[2,3,10,11,15,16,18],cp_program_id:16,creat:[1,2,3,5],createdummyir:7,createmessag:8,creation:[3,5,7,16],creator:10,crisp:16,critic:[3,13],crop:3,curl:9,currenc:[6,7,12,15,16],current:[1,2,3,6,7,8,10,11,13,15,16,17],currentwallet:11,curv:[6,7],custom:[2,9,14],customis:18,cut:5,cycl:1,dai:[7,9,10,13,15,16,17],dashboard:9,data:[0,1,2],databas:[3,6,11],dataset:7,date:[5,7,9,10,13,14],daterollconvent:15,deadlin:15,deal:[1,10,14,15],dealstat:15,debug:11,decd098666b9657314870e192ced0c3519c2c9d395507a238338f8d003929de9:9,decd:9,decentralis:10,decid:[4,10,16],decis:3,declar:[1,8,16],dedic:1,defin:[1,2,3,6,8,9,10,11,15,16,17,18],definit:[11,15,16],delai:[7,10],delet:[1,3,11,16],deliber:3,deliv:[8,15],deliveri:[8,11,14,16],demand:[3,15],demo:[5,6,13],demonstr:[14,18],denial:2,denomin:6,dens:1,depend:[1,3,4,10,11,16],dependencytxid:11,deposit:[6,16],depth:16,deregist:8,deriv:[7,11,16],describ:[1,2,3,5,11,15,16],descript:1,deserv:13,design:[1,3,5,6,10,16,18],desir:[11,15,16],desktop:9,despit:[11,16],destin:8,destroi:[3,16],destroypaperatredempt:[16,17],destructur:16,detail:[1,2,3,5,6],detect:1,determin:7,develop:[1,3,6,8,11,13,14,16],devic:3,devis:3,diagram:[7,17],diamond:17,didn:[1,11,13,14,16],differ:[1,3,6,7,10,11,15,16],difficult:[8,11],digest:2,digit:[3,10,11,16],digitalsignatur:[2,10,11],direct:1,directli:[1,9,15],directori:[0,14,16,18],directthreadexecutor:1,dirti:16,disadvantag:3,discov:3,discuss:[3,8,15],disk:[11,15],disobei:10,disprov:5,disput:[2,7,16],disrupt:8,distinguish:16,distribut:[2,3,5,6,10,11],distrust:[2,11],divid:2,dlg:11,doc:[0,1,16],docker:9,docsit:[0,13],doe:[1,2,3,6,7,8,9,10,11,16,18],doesn:[1,2,3,4,8,9,10,11,14,16],dokka:0,dollar:[16,17],domain:[16,17],don:[1,3,4,6,8,11,13,16],done:[0,3,11,16],dot:7,doubl:[3,14,16],doubt:[1,6],down:[1,3,10,16],download:[4,5],downsid:[1,3],drag:17,drive:[3,18],driven:14,driver:18,drm:10,dsl:[16,17],due:[1,3,6,7,10,11,16],dummi:16,dummy_pubkey_1:16,duplic:16,durat:[10,16],dure:[1,7],dynam:[16,18],each:[1,2,3,6,7,8,10,11,12,13,16,18],earli:[1,16,17,18],earliest:7,eas:8,easi:[1,3,6,10,16],easier:[1,11,16],easiest:16,easili:[1,10,11,14],econom:7,edit:4,editor:4,effect:[3,7],either:[1,2,3,6,7,10,11,16,18],element:[1,3],ellipt:6,els:[2,3,16],emb:16,embed:[3,6,9,10],emit:16,empti:16,enabl:16,encapsul:[1,15],encod:10,encount:6,end:[1,6,7,10,11,13,18],endpoint:9,enforc:[1,3,16],engin:16,english:[1,16],enorm:11,enough:[1,4,8,11,16,18],ensur:[1,2,3,4,8,11,13,15,16],enter:[16,18],entir:[2,3,7,8,10,16],entireti:7,entiti:[2,3,10,16],entri:[3,7,11,16],enumer:7,environ:[1,10,11],envisag:16,equal:[2,11,16],equival:[1,7,15,16],especi:[15,17],essenti:[9,10,15,16],establish:14,etc:[1,7,10,11,12,13,15,16],euribor:[9,10],evalu:[7,10],even:[3,6,8,10,11,16],event:[1,2,3,7,10,11,14,15],eventu:13,ever:[1,3],everi:[2,3,10,11,13,16,18],everybodi:[3,10],everyon:10,everyth:[2,8,16,18],evid:10,evolut:3,evolv:[16,18],exact:[10,16],exactli:[3,8,16],examin:[1,3,10,16],exampl:[0,1,2,3,7,8,10,11,15,16,17,18],excel:10,except:[1,11,16],excess:1,exchang:[7,11,15,16],execut:[3,10,15,16],executor:[1,8],exercis:16,exist:[2,3,5,7,16,18],exit:16,expect:[1,6,8,11,13,16],expectedtypenam:11,expectfailureoftx:16,expens:1,experi:[3,13,18],experiment:11,explain:[1,8,11,12],explan:1,explicit:[1,3,10,11],explicitli:[1,3,16],explor:[1,3,4,5,6,9,16,18],exploratori:8,expos:[1,2,8,9,10,11,15],exposur:7,express:[3,6,7,10,11,16],extend:[1,2,6,15,16],extens:[1,15,16],extent:3,extern:[6,11,18],extract:[3,9,10,11,15,16],extrem:[3,10,16],face:[6,16,17],facevalu:16,fact:[1,2,3,7,10,11,16],factor:[3,7],fail:[8,16],failur:[11,16],fairli:[1,11],fake:[6,14,16,18],fals:[1,8,10,11,16],familiar:[3,16],far:[11,14,16],fashion:1,fast:[3,8,14],fault:11,featur:[1,11,13,16,17],feed:10,feel:[16,18],fetch:[8,9,10],few:[1,6,8,9,10,11,13,14,16],fiber:11,field:[1,7,10,11,16,17],file:[0,1,3,8,9,11,14,15,16,18],fill:[1,11,16],filter:1,filterisinst:16,finalis:[7,11],financ:[11,18],financi:[3,5,11],find:[0,3,9,11,14],fine:3,finish:[8,11],firm:16,first:[1,2,4,7,8,9,10,11,12,14,15,16,18],firstli:16,fit:[1,3],fix:[1,3,5,6,7,8],fixabledealst:15,fixedleg:7,fixedlegpaymentschedul:7,fixedratepaymentev:7,fixof:10,flag:[9,18],flexibl:3,flight:3,floatingleg:7,floatinglegpaymentschedul:7,floatingratepaymentev:7,flow:[1,7,16],flux:18,fly:11,fold:1,folder:0,follow:[0,1,2,3,4,5,8,9,10,11,15,16,17],font:1,foo:[1,8],foobrokenexcept:1,fooutil:16,forc:[3,9],fordai:10,forev:13,forget:[11,16],form:[2,3,11,16],formal:[8,16],format:[0,1,3,9],forth:11,forward:[8,10,11,13,14],found:[4,9,10,11,13,18],four:16,frame:[1,11],framework:[3,5,6],free:[3,10,11],freeform:16,freeli:10,frequenc:7,frequent:11,fresh:[10,16],freshkei:11,freshli:16,from:[0,1,2,3,4,6,7,8,9,10,11,12,13,15,16,17,18],front:16,frustrat:3,full:[1,8,11,16],fulli:[1,3,8,11,16],fullysign:11,fun:[2,10,11,16],fund:3,fundament:[2,3,5,16],fungibl:[6,15,16],fungibleasset:[5,12],funni:11,further:[3,6,7,15],futur:[2,3,10,11,15,16,17,18],gain:6,game:11,garbag:[1,9,11],gather:16,gavin:3,gbp:15,gcd:3,gear:13,gener:0,generateirsandfixsom:7,generateissu:16,generatemov:16,generateredeem:16,generatespend:[11,16],genuin:1,get:[1,2,3],getbloomfilters:1,getclass:16,getcommand:16,getfacevalu:16,getfix:7,getinput:16,getissu:16,getkei:16,getlegalcontractrefer:16,getmaturityd:16,getnotarysignatur:2,getoutput:16,getown:16,getprogramref:16,getprotocoltrack:11,getsign:16,getter:16,gettim:16,getvalu:16,git:[4,12,13],github:0,give:[2,3,16],given:[2,3,8,10,11,16],givenpric:11,global:[1,3,10],glue:11,gnu:0,goal:[1,3,5,6,11,13],goe:14,gone:[11,16],good:[1,4,11,16,17,18],got:[9,11],gover:16,grade:15,gradl:[4,6],gradlew:[4,14],grammar:1,granular:3,graph:[3,6,9,11,16,17],graphit:9,greatest:3,green:4,groom:3,group:[3,5,8],groupstat:16,guarante:13,guava:[1,6],gui:11,hack:3,had:[2,16],hand:[11,16],handl:[1,2,3,8,11,16],handler:[8,11],happen:[1,2,3,10,11,13,16],happi:14,hard:[1,3,11,13],harder:[3,16],hase:7,hash:[2,3,6,9,10,11,15,16],hashcod:16,hashmap:2,hasn:4,hassl:11,hat:13,have:[1,2,3,4,6,7,8,10,11,12,13,14,16,18],haven:[12,16],heap:11,hearn:3,heart:16,heavi:13,heavili:3,hedg:7,heirarchi:1,held:16,hell:11,hello:11,help:[1,3,8,11],helper:[7,8,16],henc:[2,3,7],her:[16,17],here:[1,3,6,8,9,10,11,12,15,16,17,18],hierarch:11,hierarchi:11,high:[3,10,11],higher:[1,2,4,16],highlight:16,histori:[2,11],hit:[3,4],hold:[3,8],holder:[1,3,16],holidai:[7,10,15],home:4,hood:11,hopefulli:18,hotspot:1,how:[1,3,5,6,8,10,11,12,13,14,15],howev:[2,3,7,8,10,11,15,16],html:[0,1],http:[0,4,9,10,14,16,18],hub:11,human:[3,10,11],hundr:11,hurt:11,hypothesi:5,idea:[1,3,4,6,11,16,18],ideal:[11,16],ident:[2,3,10,11,14,15,16],identifi:[3,6,7,8,9,10,11,15],identityless:3,identityservic:11,ignor:16,illeg:10,illegalargumentexcept:[1,10,11,16],illegalstateexcept:[1,16],illustr:1,imagin:[1,11,16],immedi:[3,16],immut:[1,3,7,10,16],imper:1,implement:1,impli:11,implic:[2,3],implicitli:7,impos:[10,11,16],imposs:[3,10],improv:[3,13,16,17],inbackground:8,includ:[1,3,4,5],incorpor:10,increas:[1,8],indent:1,independ:[2,10],index:[3,4,7,16],indic:[1,7,8,11,16],individu:[1,8,16],industri:[5,6,9],infer:16,infix:16,influenc:9,info:11,inform:[1,2,3,11,12,15,16],infrastructur:[3,9],inher:3,inherit:[1,8,16],init:10,initi:[2,8,11,12,16,18],inmemorymessagingtest:8,inmemoryuniquenessprovid:2,inoutgroup:16,input:[2,3,10,11,15,16,17],inputindex:2,insert:[1,8,9,10],insid:[3,8,11,14,16],instal:[0,4,14],installdist:14,instanc:[1,3,5],instant:[1,10,11,16],instanti:[3,11],instead:[1,3,6,16,18],institut:[3,6],institutionrefer:16,instruct:[9,16],instrument:7,insuffici:3,insufficientbalanceexcept:16,integ:16,integr:[1,2,6,10,11,17],intellig:1,intend:[1,3,6,9,10,11,15],intent:[10,16,17],intention:1,interact:[1,3,10,11],interchang:15,interest:[5,6],interestrateswap:6,interfac:[1,2,5,6],intern:[6,8,16],internalis:1,interop:[6,16],interpret:[1,3,16],intersect:16,interv:15,introduc:[1,2,10,15,16],introduct:[5,6],intuit:1,invalid:[2,10,11,16],invari:16,investig:11,invoc:8,invok:[1,3,8,9,11,16],involv:[2,3,8,10,11,15,16,18],iou:6,ipsa:10,irsdemo:14,irsexport:7,irstest:7,irsutil:7,isaft:16,isempti:16,isinst:11,isn:[1,11,16,18],issu:[2,3,6,8,10,13,15,16,17,18],issuanc:[11,15,16,17],issuer:[3,16],item:16,iter:[11,13,16],itself:[2,3,7,8,9,10,11,16],jar:[0,3,9],jarinputstream:3,java:[1,3,6,8,9,11,16,18],javaclass:11,javacommercialpap:16,javadoc:1,jdk1:4,jdk:[4,11,16],jetbrain:[4,6],jira:6,jmx2graphit:9,jmx:9,jmxtran:9,job:18,join:[8,16],joint:16,jolokia:9,json:[9,18],judgement:1,jump:14,junit:[6,16],just:[1,3,4,8,9,11,16,18],justifi:5,jvm:[3,6,9,11,18],kafka:8,kdoc:1,keep:[3,11,16,17],kei:[1,3,6,8,10,11,14,15,16],kept:11,key_mismatch_at_issu:16,keymanagementservic:11,keypair:[11,16],keyword:[1,16],kick:11,kind:[3,6,8,10,11,16,18],know:[2,3,6,10,11,14],knowledg:10,known:[3,5,7],kotin:16,kotlin:[0,1,4,5],kryo:[6,8,11],label:[11,16,17],labori:16,lack:3,land:7,languag:[1,3,4,5,6,16,17,18],larg:[3,10,11,15,16,18],larger:[1,3],last:13,latenc:[2,10],later:[1,3,6,8,10,11,15,16],latest:[1,4],latter:[1,16],layer:[3,6,8,11],layout:17,lead:[1,3,16],leak:[2,3,11],learn:[3,5,11,14,16,18],least:[10,16],leav:[1,11],ledger:[3,5,7,9,10,11,16,17],ledgertransact:15,left:[8,11],leg:[6,7],legal:[2,3,10,15,16],legalcontractrefer:16,legallyidentifi:[2,10,11],legallyidentifiablenod:11,less:[11,16,17],let:[1,3,9,10,11,14,16],letter:1,level:[1,4,7,8,10,11,16],lib:0,liber:1,libor:[7,9,10],librari:[1,6,9,10,11,15,16],licens:1,life:18,lifecycl:5,lifetim:7,like:[1,2,3,4,7,8,9,10,11,13,15,16,18],likewis:16,limit:[3,5,16],line:0,linearst:15,link:[1,3,10,11,15,16],linkabl:3,linux:9,list:[0,3,8,10,11,13,14,15,16],listen:[1,6],listenablefutur:11,liter:3,littl:[1,16],live:7,livelock:3,load:[2,3,14,15,16,18],loan:[7,10],local:[0,3,4,9,10,11],locald:10,localhost:9,locat:[14,15,16],lock:[1,16],log:[11,14],logger:11,logic:[2,3,6,8,11,16,18],longer:[1,7,10,11],look:[1,7,8,9,10,11,13,16,18],loop:[1,7,16],loquitur:10,loss:10,lot:[1,3,7,14,18],low:[2,11],lower:[1,10],lurch:11,mac:9,machin:[3,5,8,10],maco:14,made:[1,3,5,7,11,12,13],mai:[1,3,6,8,9,10,11,13,16,18],mail:[13,14],main:[11,16,17,18],maintain:[2,3],maintan:10,mainten:8,major:13,make:[0,1,2,3,7,8,10,11,13,14,16],makenod:8,maker:6,malici:11,manag:[3,5,9],mani:[1,3,6,8,10,11,15,16],manipul:15,manner:11,manual:8,map:[1,2,5,7],mappabl:16,mark:[1,11,16],markdown:1,marker:[11,16],market:5,master:12,match:[3,8,10,11,16],matter:16,matur:[7,9,10,16],maturityd:16,maven:4,maximis:3,maximum:3,maybestx:11,maybetraderequest:11,mbean:9,mean:[1,3,8,10,11,15],meaning:2,measur:[7,16],mechan:[12,16],meet:16,mega_corp:16,mega_corp_kei:16,mega_corp_pubkei:17,megacorp:[16,17],member:7,memori:[2,5],menlo:1,mention:11,menu:4,mere:[7,16],merg:[3,6,12,15,16],mess:11,messag:[1,3,5,6],messagehandlerregistr:8,messagerecipi:8,messagerecipientgroup:8,messagingservic:[8,11],method:[1,5,8,9],metric:9,middl:[1,8,11],might:[1,3,4,7,11,16],mike:3,mileston:5,mind:[1,10,11,16],mine:3,minim:[3,11],minimis:[2,3,8],minimum:[3,7],minor:13,minu:16,minut:[6,10],misc:8,miss:[1,11,16,18],missingsig:11,mission:9,mix:[1,11,16],mock:8,mode:[6,8],model:1,modest:3,modif:16,modifi:[2,4,7,11,15,16],modul:[8,16],moment:8,monei:[10,16],monetari:16,monitor:[1,5],month:[7,11,13],more:[1,2,3,6,7,8,9,10,11,12,14,15,16],moreexecutor:1,most:[3,7,8,9,10,11,16],mostli:16,move:[11,12,13,16,17],movement:[11,16],much:[1,3,6,11,12,16,18],multi:[1,11,16],multipli:7,must:[2,3,8,9,10,11,16,18],mutabl:[1,3,16],mutat:3,mutual:[2,11],myfil:9,mykeypair:11,nail:1,namedbyhash:15,namespac:11,narrow:1,nativ:11,natur:16,naval:[3,10],navistar:10,necessari:[1,2,13,14],need:[0,1,2,3,5,7,8,9,11,13,14,15,16,18],negoti:[3,15],neither:[11,16],nest:11,net:[7,16,17],network:[2,3,5,6],neutral:6,never:[1,3,10,16],newli:11,newown:16,next:[1,4,7,11,16],nice:14,nio:1,noddi:9,node:[3,5,6,8],nodea:14,nodeb:14,nodeinterestr:10,nodeservic:10,non:[0,1,3,5,11,12,14,15],none:11,normal:[7,11,15,16],not_matured_at_redempt:16,notaris:2,notaryexcept:2,notaryprotocol:2,notat:11,note:[0,1,3,5,7,11],noth:[1,3,16],notic:[1,16],notif:8,notifi:8,notion:[3,6,7,16],notnul:16,now:[1,3,4,8,10,11,12,14,16,17,18],nugget:16,nullpublickei:16,number:[1,3,7,8,10,11,13,14,15,16],numer:3,obj:16,object:[1,3,6,7,8,9,10,11,15,16,17,18],oblig:[7,15],observ:[3,7,10,11],observatori:[3,10],obsolet:6,obtain:[1,2,17],obviou:[1,3,10],obvious:[7,16],occasion:5,occur:[2,10,11,16],occurr:10,odd:[11,16],off:[8,11,16,17],offer:11,offlin:8,offset:7,often:[1,3,7,10,11,16],oftenor:10,oil:12,onc:[0,1,2,6,7,8,10,11,13,15,16,18],onli:[1,2,3,6,7,8,9,10,11,16,17,18],onto:[1,11,16,17],opaqu:[6,8],opaquebyt:16,open:[2,3,4,10,11,14,17],openjdk:4,oper:[7,8,9,10,11,16],optim:1,option:[0,7,8,10,11,16,18],oracl:[3,4,5,6,7,8,9],orchestr:[5,12,18],ordain:7,order:[0,1,2,3,6,7,8,11,15,16,17],ordinari:[3,6,11,16],org:[0,4,16],orient:5,origin:[15,16],otc:6,other:[1,2,3,6,7,8,10,11,14,15,16],othersid:11,otherwis:[11,16],our:[1,3,11,13,16],ourselv:[11,16,18],oursignatur:11,out:[1,2,3,4,6,9,10,11,16],outag:8,outcom:11,outlin:[3,11],outpoint:3,output:[2,3,10,11,14,15,16,17],outsid:[3,8,10,11,16,18],outstat:16,over:[1,2,3,7,8,9,10,11,15,16],overal:[2,8],overflow:1,overload:11,overnight:15,overrid:[2,11,16],overwhelm:3,own:[1,8,9,10,11,13,16,17,18],ownablest:[11,15],owned_bi:16,owner:[11,15,16],ownership:[11,16],owningkei:[11,16],p2p:[6,11],pack:16,packet:3,page:[4,10,16],pai:[10,11,16,17],paid:[3,7],pair:[3,11,16],paper:[5,6,11,12,14],paper_1:[16,17],parallel:[3,8,11],parallelis:3,paramet:[1,11,14,16],parameteris:3,parent:11,pars:[10,18],part:[1,2,3,10,11,15,16,18],parti:[1,2,3,5,6,7,8,10],partial:[2,11,16],partialtx:11,particip:[3,16,18],particular:[1,2,3,9,11],partyandrefer:1,partyrefer:[1,16],pascal:1,pass:[2,8,11,16,17],past:[1,10,14,16,18],patch:1,path:[1,9,16],pattern:[1,3,16],paye:3,payer:[3,7],payment:[3,7,10,11,14,16,17],pdf:10,peer:[6,8,10,11],penni:16,peopl:[1,3,6,16],per:[1,3,18],perform:[1,2,3,7,10,11,14,16],perhap:[3,16],period:7,perman:[6,16],persist:[6,8,11],perspect:[3,11,16],phrase:10,physic:[2,10],pick:[8,11,13,16,18],piec:[1,2,3,8,11,16],ping:8,pip:0,pki:3,place:[0,1,3,6,7,8,10,11,13,15,16,18],plai:11,plan:[8,14],platform:[2,3,5,6,7,8,10,11,16],pleas:[1,3,4,16],pluggabl:12,plugin:[4,9],point:[1,2,3,9,10,11,13,16],pointer:[2,11],pointless:1,pong:8,pool:[1,3,11],poor:3,pop:[4,8],popular:6,popup:4,port:13,posess:11,posit:[1,2,3,11],possibl:[3,8,10,11,16],potenti:[1,2,6,11,16],pound:16,power:[3,5],practic:[3,16],pre:[0,3,7,11,16,18],preced:16,precis:[3,6,10],precondit:1,prefer:[1,3],prefix:11,preliminari:8,prepar:[3,16],present:[2,5,7,10,15,16],preserv:[2,3],press:16,pretend:9,pretti:[3,11,16],prevent:16,previou:[3,15],previous:[7,10],price:[3,10,11],primari:[6,10],primit:16,print:14,priv:11,privaci:[1,2,3,11,16],privat:[2,3,11,16,18],probabl:[4,10,16,18],problem:[2,3,10,11],proce:11,procedur:11,process:[2,3,5,7,8,9],processor:3,produc:[0,16,17],product:[1,5,6,13,15,16],profit:[16,17],profound:3,program:[1,3,6,8,9,11,14,16,18],programref:16,progress:[2,5,7],progresstrack:11,project:[4,14],proof:[3,5],propag:[5,9,16],properli:11,properti:[1,9,11,16],propos:[5,11],prose:[10,15],protect:11,protocol:[2,3,5,6,8,9,10],protocollog:11,protocolstatemachin:11,protocoltrack:11,prototyp:[1,3,5,6,10,16],prove:[2,3,5,16],provid:[0,1,2,3,7,8,9,10,11,15,16,18],provision:15,pseudo:10,ptx:11,publickei:[5,11],publicli:5,pull:4,pump:8,punish:10,purchas:[11,14],pure:[3,10],purpos:[6,11,16],push:13,put:[1,11,13,16,18],python:0,qualiti:5,quantiti:[3,6,16],quasar:11,queri:[7,10],question:[1,4,10],queu:8,queue:[1,6,8,11],quick:10,quickli:[3,8,16],quit:[1,10,11,16],r3corda:12,r3dlg:13,r3prototyp:[0,4,14],r3repositori:4,rais:2,random63bitvalu:11,random:[3,11],rang:10,rapid:[1,6,13],rate:[1,5,6],ratefixprotocol:10,rather:[1,3,11,16],raw:[9,11],reach:[2,3,7,10],reachabl:11,read:[1,3,5,6,9,10,11,16,18],readabl:[6,11],reader:16,readi:[13,16],readili:15,readm:1,real:[1,6,8,10,16,18],realis:11,realism:8,realiti:7,realli:[1,2,3,11,16],reason:[1,3,7,11,15,16],reassign:16,recal:7,receiv:[3,7,8,10,11,13,16,17],receiveandcheckproposedtransact:11,receiveandvalidatetraderequest:11,recipi:[3,8,16],recognis:[3,10,16],recommend:[1,8,18],record:8,recov:8,recreat:11,red:[4,7],redeem:[6,16,17],redempt:[16,17],redemptiontim:[16,17],reduc:1,redund:1,ref:[11,16],refactor:12,refer:[1,2,3,6,7,10,11,15,16],referenc:2,refin:6,reflect:16,refus:4,regard:2,regardless:11,regener:[7,13],regist:[1,8,9,11,18],registr:8,regular:[6,9,11,16],reissuanc:[3,16],reject:16,rel:[3,8],relabelablestep:11,relat:[7,16],relationship:16,releas:5,relev:[3,15],reli:3,reliabl:8,relianc:3,relic:9,religi:1,remain:[16,17],remeb:4,rememb:[1,4,11,16],remind:11,remot:4,remov:[8,11,16],render:[1,11,17],repeat:[1,7,8,11],replac:[2,4,7,9,13,15,16],replic:3,repoint:2,report:8,repositori:[1,4],repres:[1,3,7,8,10,11,15,16],represent:7,request:[2,3,8,10,11],requestingparti:2,requiresinglecommand:16,requirethat:16,resel:10,reserv:11,reset:7,reshap:3,resolut:[2,3,5,11],resolv:[11,15],resolvetransactionsprotocol:11,resourc:11,respect:[1,3,11,14,16],respend:3,respons:[2,3,8,10,11],rest:[2,3,8,9,11,18],restart:[4,11,14],restor:11,restructuredtext:0,result:[1,2,3,7,10,11,16],resultfutur:11,resum:11,resurrect:11,retain:8,retri:[8,11],retriev:7,reus:[3,11],reusabl:10,reveal:[2,3,11,16],revers:11,review:[1,13],revis:7,rewrit:11,right:[1,4,8,9,11,13,18],rigid:3,rigidli:1,risk:11,role:[14,18],roll:[7,11,14],rollov:[15,16],root:[14,16,17],roughli:[10,13],rout:11,router:8,rule:[1,10,11,16],run:[0,1,2,3,4,5,6,8,9,11,13],runbuy:11,runnetwork:8,runsel:11,runtim:[1,11],safe:[1,3,11,16],safeti:1,sai:[1,2,3,16],sale:[14,16],same:[1,2,3,6,7,8,10,11,14,16,17],sandbox:[3,6,16],saniti:11,satisfi:16,save:[1,16],scala:[6,16],scalabl:[1,3],scale:7,scenario:[3,18],scene:[11,16],schedul:[7,9],scope:[3,16],scrape:9,scratch:18,screen:[1,4],script:[0,3,16],scroll:14,scrub:11,seamless:6,search:[4,11,16],second:[7,11,14,16],secondari:11,secp256r1:6,section:[3,13,16],secur:[3,8,11],securehash:[2,16],see:[0,1,2,6,7,8,10,11,14,15,16,18],seed:11,seek:3,seem:3,seen:[1,7,10,11,16,17],select:[4,16],self:6,sell:[6,11,16,18],seller:5,sellerownerkei:11,sellersig:11,sellertradeinfo:11,semi:[3,10],send:[1,3,8,9,10,11,13,16],sendandrec:11,sender:3,sendsignatur:11,sens:[7,10,11,16],sent:[8,11,16],separ:[2,3,9,10,11,14,15,16],sequenc:[3,8],sequenti:[8,11],seri:11,serial:[6,8,16],serialis:[1,3,6,8,11,16],serializablewithkryo:16,serializeablewithkryo:16,seriou:[3,13],serious:18,server:[9,10,18],servic:5,servicehub:11,session:[8,11],sessionid:11,set:3,setof:11,setter:16,settim:11,settl:[8,10,15],settlement:11,setupa:14,setupb:14,sever:[3,11,16,18],sha256:16,sha256sum:9,sha:[3,9],shape:3,share:[3,7,10,11,16,18],shasum:9,she:16,shortcut:6,shorthand:16,shot:8,should:[1,2,3,4,6,8,11,14,15,16,18],shoulder:1,shouldn:[11,16],show:[3,4,6,14,16,17],shown:[11,16],shutdown:11,side:[10,11],sig:16,sign:[2,3,6,7,8,10,11,15,16],signatur:[2,3,6,8,10,11,15,16],signatureexcept:11,signaturesfromsel:11,signedtransact:[11,15,16],signer:[10,16],signific:3,significantli:7,signoff:10,signwith:[11,16],signwithecdsa:11,signwithourkei:11,silver:1,similar:[1,3,8,10,16],simpl:[1,3,6,7,8,9,11,16,17],simpler:[3,6],simplest:[3,11,16,18],simpli:[1,3,8,11,15,16],simplifi:[1,3,6,8,15,16,18],simultan:[3,8,11,16],singl:[1,2,3,9,10,11,16,17,18],singlemessagerecipi:[8,11],singleton:[11,16],sit:8,site:[1,13],situat:[1,3],size:[1,3,7,11,16],skip:11,slight:16,slightli:16,slip:13,slow:[1,3],slowest:3,small:[3,6,10,11,14,16,17],smart:[5,6,10,12],smm:11,smooth:16,snapshot:[3,12,13],snide:0,snippet:[2,11,16],softwar:[6,11,13,18],sold:[11,16,17],solv:[3,10,11],solvenc:10,some:[1,2,3,6,8,9,10,11,12,14,15,16,17,18],somed:16,someon:[2,3,8,16],someprofit:[16,17],someth:[1,3,4,7,14,15,16,18],sometim:[3,8,9,10,11,16],somewhat:[3,11],somewher:[16,17],sophist:3,sort:[10,11],sound:[1,11,16,17],sourc:[4,7,10,11],sparingli:1,special:[2,3],specialis:11,specif:[2,3,8,9,10,11,15,16,17],specifi:[0,1,2,3,6,8,10,11,16,18],speed:[3,11],spend:[3,11,16],spent:3,sphinx:0,sphinx_rtd_them:0,split:[3,6,12,15,16],spread:[2,8,11],spreadsheet:10,squar:17,src:[16,17,18],stabilis:13,stabl:13,stack:11,stage:[1,11,16,18],stai:[3,16],stake:3,standalon:[6,10],standard:[1,5,6,9,11,15,16],standardis:[3,15,16],start:[1,3,5,7,8,9,11,14],state:[2,3,5,6,7,8,10],stateandref:[11,15,16],statehistori:2,stateless:3,statemachinemanag:11,statement:[1,3,10,11,16],stateref:[2,3,15],statesoftyp:11,statist:9,status:3,step:[5,10,11],still:[2,3,11,16,18],stock:[3,10],stop:[1,8,11],storag:3,store:[2,11,15,16],stori:1,straightforward:[11,16],stream:11,stress:1,strictli:[3,7],string:[8,10,11,16],strong:6,structur:[1,3,4,6,10,11,16],studi:16,stuff:[1,11],stx:11,sub:11,subclass:[11,15],subgroup:3,submiss:10,submit:[1,2,8,11],subprotocol:[2,11],subscrib:8,subtask:11,subtl:[1,3],successor:[2,6],sudo:0,suffer:3,suffic:10,suffici:[3,5,8,10,13],suffix:16,suggest:[8,16],suitabl:[8,13],sum:16,sumcashbi:[11,16],sumcashornul:16,summari:[12,13],summaris:3,sun:1,superclass:[11,12,15],superior:1,supersed:3,supertyp:16,suppli:14,support:[1,3,5,6,7,8,10,11,12],suppos:[11,16],sure:[2,13,14,16,18],surfac:11,surround:[1,16],surviv:11,suspend:5,swap:[5,6],swapsignatureswithsel:11,symbol:4,synchronis:[1,3,10],syntax:[6,16],system:[2,3,6,9,10,11,14,16],tab:[1,4],tag:[1,13],tailor:5,take:[1,6,7,11,15,16,17],tamper:11,target:[0,1,3,6,9],targetrecipi:8,task:[3,11],team:4,technic:5,techniqu:[1,3,10,16],tell:[0,8,11],templat:15,tempor:10,temporari:3,temporarili:[11,13],tempt:16,temptat:11,ten:16,tenor:[7,9,10,15],term:[3,15,16],termin:[7,9,11,14],terminolog:3,test:[0,4,5,6,8,11,13],test_tx_tim:16,testutil:16,testwithinmemorynetwork:8,text:[1,4,9],than:[1,2,3,5,9,11,16,17],thei:[1,3,6,7,8,9,10,11,13,14,15,16],theirsessionid:11,them:[1,3,4,6,7,8,9,11,13,14,15,16,18],themselv:[8,10,11,15,16],theori:[5,10],therefor:[3,4,6,11,13,16],thi:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18],thing:[1,3,6,10,11,14,15,16,18],think:[1,3,4,11,16],third:[3,14,16],those:[3,8,9,10,11,15,16],though:[8,9,11,16],thought:[3,6],threadsaf:1,three:[14,15,16],threshold:16,through:[3,7,9,11,16,18],throughput:[2,3],throwifsignaturesaremiss:11,thrown:16,thu:[1,2,3,9,10,16],tighten:16,tightli:11,time:[1,2,3,6,7,9,10,11,15,16,17],timelin:16,timestamp:1,timestampauthoritysig:11,timestampcommand:10,timestampercli:16,timestamperservic:10,timestampingauthor:11,timestampingprotocol:11,titl:4,todo:[1,11,16],togeth:[3,11,16],token:15,told:1,toledgertransact:11,toler:[2,10],too:[1,11,16,17],took:11,tool:[6,9],toolbar:4,top:[1,3,4,11,16],topic:[8,11,18],topriv:11,toset:11,tosignedtransact:[11,16],tostr:[1,11,16],total:[3,16],toward:13,trace:11,track:[3,5,8],tracker:[6,11],trade1:14,trade:[5,6,7,10],trade_top:11,tradeoff:1,trader:5,traderdemo:18,traderequest:11,tradit:[3,16],traffic:[3,11],transact:[2,3,5,9,10,11],transactionbuild:[11,16],transactionforverif:16,transactiongroup:16,transactiongroupdsl:17,transactiongroupfor:17,transactiongroupfortest:16,transfer:16,transit:[5,16,18],treat:16,tree:11,tri:[3,16],tricki:[3,11],trigger:[10,14],trivial:[1,3],trust:[3,11],truth:11,tsa:[3,11],tsasig:11,tupl:1,ture:3,turn:[3,11,15,16,18],tutori:[5,6,10,11,12,16,18],twice:6,two:[1,2,3,5,6,7,8],twopartytradeprotocol:11,txbit:11,txhash:[3,11,16],txt:9,type:[1,2,3,5,7,10,11,12],typenam:11,typetobui:11,typic:[3,8,9,11,15,16,18],unacceptablepriceexcept:11,under:[0,11,13,16,18],underli:[3,7,11,15],underscor:16,understand:[3,8,9,16,17,18],unexecut:16,unexpect:11,unfinish:11,unfortun:[11,16],unguess:11,unifi:18,unindex:4,uniqu:[2,3,10,11],uniquenessprovid:2,unit:[2,3,4,6,8,11,16,17,18],unix:[9,14],unknow:10,unless:[1,10,11,13,16,18],unlik:[4,16],unnatur:3,unnecessari:16,unpack:[11,16],unread:11,unrecognis:16,unrel:16,unreleas:5,unserialis:11,unset:7,unspent:3,unstart:11,unsupportedoperationexcept:16,until:[2,3,7,8,11,13,18],untrustworthydata:11,unus:8,unusu:16,updat:[3,4,8,11,13,16],upgrad:[4,5],upload:5,upon:[7,11,16],url:4,usabl:[6,13],usag:1,usd:15,useless:16,user:[0,1,3,4,6,8,10,11],usr:0,usual:[3,13],util:[6,8,16],vagu:1,val:[2,8,10,11,16,17],valu:[3,6,7,10,16,17],valuabl:10,valuat:7,vanilla:[6,7],vari:5,variabl:[1,3,7,11,16],variant:16,variou:[1,3,6,9,11,16],vehicl:3,vendor:[6,9],verbos:16,veri:[1,3,6,10,17,18],verif:[3,6],verifi:[2,3,5,6,8,10,11,15],verifytransact:11,versa:[7,11,15],version:[4,6,7,8,11,12,13,15,16],versu:11,vertic:1,via:[0,1,3,7,9,10,11,14,18],vice:[7,11,15],view:[1,7],virtual:[3,5],visibl:[2,3],visualis:5,vital:11,wai:[1,3,6,9,10,11,16,18],wait:[4,8,11,14],wallet:[3,11,16],walletservic:11,want:[1,3,4,8,9,10,11,16,18],weak:10,wear:13,web:[9,10],websit:16,weekend:7,well:[0,1,3,6,7,9,10,11,15,16],went:1,were:[1,3,10,11,16],what:[1,3,4,5],whatev:[1,11,15],when:[1,2,3,7,8,9,10,11,16],whenev:1,where:[1,2,3,5,7,8,9,10,11,13,15],wherea:7,wherev:9,whether:[2,8,10,11],which:[0,1,2,3,6,7,8,9,10,11,12,13,14,15,16,18],whilst:[3,10,11,14,16],who:[1,3,6,8,11,16],whole:[2,16],whom:[3,8],whose:[9,15],why:[1,3,6,16],wide:[1,8,16],widescreen:1,widespread:1,width:1,wiki:[3,16],wikipedia:16,window:[3,4,11,14,17],wire:18,wirecommand:16,wiretransact:[2,10,11,15],wish:[3,8,10,11,16,18],within:[0,2,3,9,14],withkei:11,withnewown:11,without:1,withoutown:16,won:[8,10,11,14,16],word:[1,2],work:[1,2,3,4,5,6,7,8,9,10,11,12,14,15,16],worker:1,world:[3,10,11,16],worn:16,worri:[1,6,11],worst:3,worth:[1,16],worthless:10,would:[1,2,3,6,7,8,9,10,11,15,16,18],wouldn:[10,16],wrap:[1,9,11,15,16,18],wrapper:11,write:[1,2,5,6,9],written:[0,3,6,7,16],wrong:[1,11,14],wrote:3,wtx:[2,10,11],www:[0,4],year:7,yet:[1,3,7,11,12,16],yield:[3,11],you:[0,1,3,4,6,8,9,10,11,14,16,17,18],your:[1,3,4,5,8],your_usernam:4,yourself:3,zero:[3,16],zip:[3,9]},titles:["Building the documentation","Code style guide","Consensus Model","Data model","Getting set up","Welcome to the Corda repository!","What’s included?","The Interest Rate Swap Contract","Networking and messaging","Node administration","Writing oracle services","Protocol state machines","Release notes","Release process","Running the demos","Transaction Data Types","Writing a contract","Using the visualiser","Where to start"],titleterms:{"class":16,"function":16,about:4,administr:9,adopt:3,amount:15,api:16,approach:10,assert:[1,10],asset:16,attach:9,base:16,basic:10,bitcoin:3,build:0,buyer:11,cash:15,check:16,code:1,command:16,comment:1,commerci:16,comparison:3,complain:4,con:3,consensu:2,continu:10,contract:[6,7,15,16],corda:5,creat:7,cut:13,data:[3,10,15],date:15,demo:[14,18],detail:7,document:0,download:9,error:1,ethereum:3,fix:9,framework:10,fungibleasset:15,gener:[1,16],get:4,group:16,guid:1,how:16,implement:[2,8,10,11],includ:6,instanc:7,intellij:4,interest:[7,9],interfac:8,introduct:[10,11],known:10,kotlin:6,lack:4,length:1,lifecycl:7,line:1,machin:11,manag:11,map:8,memori:8,messag:8,method:11,mileston:12,model:[2,3],monitor:9,multipl:2,name:1,network:8,node:9,non:16,notari:2,note:12,occasion:10,oracl:10,orient:16,overview:3,paper:16,parti:[11,15],pro:3,process:13,progress:11,protocol:11,publickei:15,publicli:10,rate:[7,9],rational:3,releas:[12,13],repositori:5,requir:[0,16],run:14,sdk:4,seller:11,servic:[8,10],set:4,smart:16,space:1,start:[16,18],state:[11,15,16],step:13,style:[1,3],support:15,suspend:11,swap:7,technic:7,test:16,theori:11,thread:1,timestamp:2,track:11,trade:11,tradeoff:3,trader:[14,18],transact:15,two:[10,11],type:15,unreleas:12,upload:9,usag:2,utxo:3,valid:2,vari:10,verifi:16,visualis:17,welcom:5,what:6,where:18,without:4,write:[10,16],your:[9,16]}}) \ No newline at end of file +Search.setIndex({envversion:47,filenames:["building-the-docs","codestyle","consensus","data-model","event-scheduling","getting-set-up","index","inthebox","irs","messaging","node-administration","oracles","protocol-state-machines","release-notes","release-process","running-the-demos","transaction-data-types","tutorial-contract","visualiser","where-to-start"],objects:{},objnames:{},objtypes:{},terms:{"0_xx":5,"1mb":12,"8u45":5,"_before_":12,"_do_":12,"_foo":1,"_is_":12,"_mbeans_":10,"abstract":[3,12,13],"boolean":[3,17],"break":[11,14,17],"byte":[1,3,7,12],"case":[1,2,3,9,11,12,13,16,17],"catch":[1,5,12],"class":[],"default":[1,5,7,12,13,15,17],"enum":13,"export":[10,12,19],"final":[2,3,5,8,9,12,17],"float":[4,7,8],"function":[],"import":[1,3,4,5,9,12,14,17,19],"instanceof":17,"int":[1,2,17],"long":[1,3,4,9,12,17],"new":[1,2,3,5,6,7,8,9,10,12,13,14,17,19],"null":[4,11,17],"public":[1,3,7,9,10,11,12,16,17],"return":[1,2,4,8,9,10,11,12,13,17,19],"short":[4,9,14,17],"static":[3,11,12,17,19],"super":1,"switch":[7,12,13,17],"throw":[1,2,11,12,17],"transient":12,"true":[3,9,11,17,18],"try":[1,3,12,15,17,18,19],"var":17,"void":17,"while":16,abil:[3,9],abl:[2,3,9,11,13],abort:2,about:[],abov:[1,3,8,9,12,17],absolut:3,abstractnod:11,accept:[1,2,3,9,12,17],acceptablepric:12,access:[1,3,5,9,10,11,12,17],accid:12,accident:1,accompani:1,accord:19,accordingli:9,account:[3,16],accrual:8,accur:11,accuraci:3,achiev:[2,3,9],ack:13,acknowledg:12,across:[3,12,13],act:[2,3,9,11,12],action:[4,17,19],activ:[4,8,15],actor:[1,3,12],actual:[5,8,9,11,12,17],adapt:[1,11,12],add:[1,9,10,12,16,17],addarg:17,addcommand:12,addinputst:[12,17],addit:[1,2,3,16,17],addition:[11,12,14],addmessagehandl:[9,13],addoutputst:[12,17],address:[2,3,9,12,17],adjust:[1,8,19],admin:5,administr:[],advanc:[6,8],advantag:3,adventur:19,advertis:11,advertisedservic:2,advic:14,affect:[5,11],affection:17,affinityexecutor:1,afraid:1,after:[2,3,4,5,7,8,11,12,17,18],again:[3,8,9,11,12,15,17],against:[3,4,8,12,17],agent:10,aggreg:[3,17],agre:[4,8,12],agreement:[3,8,16],ahead:12,aim:[1,3],algorithm:[3,7,13,17,18],alic:[17,18],aliceaddr:9,alicegetsback:[17,18],alicenod:9,aliv:12,all:[0,1,2,3,5,8,9,10,11,12,13,14,15,17,19],allevi:2,allow:[1,2,3,4,7,8,11,12,16,17,19],allpossiblerecipi:9,almost:[12,17],along:[2,7,9,11,12,17],alreadi:[1,4,11,12,13,17],alright:12,also:[1,2,3,4,5,8,9,10,12,15,16,17,19],alt:17,alter:[12,17],altern:[0,1,10],although:[3,7,8,9,17,19],alwai:[1,3,4,10,12,17],amounnt:12,amount:[],amqp:7,analysi:3,andresen:3,ani:[1,2,3,4,8,9,10,11,12,14,16,17,19],annot:[1,12,17],announc:14,anonym:3,anoth:[1,2,5,10,11,12,17],answer:[1,11],anticip:1,anybodi:3,anyon:[2,17],anyth:[2,3,9,11,12,17],anywher:[9,11,17],apach:[7,9],apart:2,api:[],app:[10,14,19],appear:17,append:10,appendix:6,appli:[1,3,8,17],applic:[3,11,19],applyfix:8,appoint:2,approach:[],appropri:[1,9],approv:[3,4,12],arbitrari:[1,3,11,12,17],arbitrarili:7,architectur:[6,11],area:[9,16],aren:[12,17,19],arg:[17,18],arguabl:11,argument:[1,3,9,12,17],aris:3,around:[3,9,11,12,14,16,17,18],arrai:[3,7,12],arrang:12,arriv:[11,12],arrow:[5,8],artemi:7,articl:[2,3,4,9,11,12,19],artifact:17,ask:[1,12,17],aspect:[4,12,19],assembl:3,assemblesharedtx:12,asset:[],assetforsal:12,assetmismatchexcept:12,assettosel:12,assettypenam:12,assign:11,assist:[4,12,17,18],associ:[2,3,4,9,16,17],assum:[3,11,12,17],assumpt:12,atom:[3,11,12,15,17],attach:[],attack:2,attempt:[3,5,6,9,12],attent:12,attest:[2,11],attribut:1,audit:[3,12],authent:2,authenticatedobject:[16,17],author:[1,2,3,9,12,14,19],authoris:12,auto:[1,17],autom:[3,4,17,19],automat:[0,4,9,12,13,17,19],avail:[0,4,8,9,10,11,14,17],avoid:[1,3,12],awai:[3,12,15],awar:[1,12],awg:14,awkward:[1,12],axi:8,back:[1,3,11,12,16,17],backend:9,background:[1,3,9],backport:14,backtick:17,backward:[12,14],bad:[1,12,17],balanc:[2,3,17],band:12,bandwidth:1,bank:[3,8,16,19],bankrupt:17,bankruptci:[3,11],barrel:13,base:[],basi:[4,8,10],basic:[],bat:15,bear:[12,17],beauti:18,becaus:[1,3,5,9,10,11,12,17],becom:[1,3,4,8,12,14],been:[2,3,5,8,11,12,13,14,17],befor:[2,3,4,7,8,11,12,13,14,16,17],beforehand:15,begin:[1,3,15,17,19],behav:17,behaviour:[2,10],behind:[12,17],belong:[],below:[1,3,4,8,12,19],benefit:[2,12,17],best:[1,15,19],bet:11,better:[1,6,7,13,17,18],between:[1,3,4,8,9,11,12,13,14,15,16,17],beyond:[3,17],big:[1,3,12,17],bigdecim:11,bilater:[7,8,13],bill:17,bin:15,binari:[3,11],bind:[2,3,11],bip:3,bit:[12,17,18,19],bitbucket:5,bitcoinj:12,blah:1,blank:[1,17],block:[1,2,3,6,9,11,12,13,17],blockchain:[3,7,12],bloom:1,bloomfilt:1,blow:15,blue:[8,18],bob:17,bobaddr:9,bobnod:9,bodi:1,boil:3,bond:17,bookkeep:[7,17],boost:7,borrow:18,both:[2,3,7,8,9,11,12,15,17],bottom:12,bound:[11,12],box:[7,19],branch:14,breach:3,bread:19,breadth:12,brief:13,briefli:[9,18],bring:3,broadcast:[3,9],broke:1,broker:[],brows:[],bug:[1,13,14],bugfix:14,bui:[12,19],builder:[13,17],built:[12,17],bulk:3,bullet:1,bunch:[15,17],bundl:3,busi:[3,4,7,9,11,12,16,17,19],businesscalendar:16,butter:19,buyer:[],buyersessionid:12,bytearrai:9,bytecod:[3,12,17],cach:9,calcul:[4,8,12,16,17],calendar:[8,11,16],calibr:3,call:[1,2,3,7,8,9,10,12,14,17],callback:[1,9,12],caller:[2,17],callerident:[],came:12,camel:1,can:[0,1,2,3,4,5,7,8,9,10,11,12,13,15,16,17,18,19],cannot:[2,3,5,11,13,17],capabl:17,capit:1,capitan:0,captur:4,care:[1,3,9,11,12],carefulli:7,cash:[],cashkt:17,cashsigningpubkei:12,cashstat:12,caus:[1,17],center:17,certain:[1,7,17],certainti:2,cev:5,chain:[3,11,12,17],challeng:3,chanc:[1,12],chang:[],changenotari:2,channel:12,charact:1,charg:11,check:[],checkabl:11,checkdepend:12,checksufficientsignatur:12,chf:16,child:12,children:12,childrenfor:12,choic:[1,2,3],choos:[2,5,17],chosen:[2,3],chronolog:4,chunk:19,circl:18,claim:[3,7,17],clash:1,clean:12,cleanup:13,clear:[12,16],clearer:[9,12],clearli:1,click:[5,18],client:[2,10,11],clock:[4,11,15],clone:[1,5],close:11,closer:2,closur:1,cloud:10,cluster:2,cmd:17,coars:3,code:[],codebas:[1,17],cognit:3,coin:3,colleagu:1,collect:[1,10,13],collector:[1,10,12],collis:1,colour:15,column:10,com:[0,5,13],combin:[3,6,17],come:[3,7,12,14],command:[],commanddata:11,commerci:[],commercial_pap:17,commercialpap:[7,17,18],commercialpapertest:[17,18],commit:[2,12,14],committedst:[],commod:16,common:[3,8,12,16,17],commonleg:8,commonli:17,commun:5,compani:11,companion:[12,17],compar:[3,9],compat:14,compel:2,compil:[],complementari:4,complet:[3,4,9,12,15,17],complex:[1,3,16,17],complic:[12,17],compon:[4,9],compos:[12,16,17],compris:8,comput:[8,11,12],concept:[2,3,4,11,12,17],conceptu:12,concern:[3,12,17],conclus:[3,11],concurrenthashmap:1,condit:[2,11,12],config:10,configur:[5,10,12,15],confirm:[2,5,9],conflict:[2,3,6],confus:12,connect:[10,17],consid:[1,3,8,11,13,14,17],consist:[3,8,12],constant:[1,17],constantli:11,constraint:11,construct:[1,2,9,11,12,17,19],constructor:[4,11,17],consult:11,consum:[2,3,4,13],consumingtx:2,consumpt:[4,11],contact:[5,12],contain:[2,3,8,9,10,11,12,14,15,16,17,19],content:[1,2,3,4,5,9,10,11,17],context:[1,3,10,11,16],continu:[],contract:[],contractst:[2,4,13,16,17,18],contractstateref:17,contrast:[3,11,12],control:[1,2,3,5,10,12,13,17,19],conveni:[1,3,17],convent:[8,12],convers:16,convert:[8,16,17],convinc:12,copi:[1,3,9,12,17,19],copyonwritearraylist:1,copyright:1,corda:[],cordapp:13,core:[9,13,16,17],corner:5,correct:[2,3,14,17],correctli:[3,11,17],correspond:17,correspondingli:1,cost:[11,17],could:[1,2,3,11,12,16,17],count:8,countabl:13,counter:[1,12],counterparti:8,countri:[11,16],coupl:[11,12],cours:[10,11,17,19],cover:[2,3,11,12,16,17,19],cp_program_id:17,creat:[],createdummyir:8,createmessag:9,creation:[3,6,8,17],creator:11,crisp:17,critic:[3,14],crop:3,curl:10,currenc:[7,8,13,16,17],current:[1,2,3,4,7,8,9,11,12,13,14,16,17,18],currentwallet:12,curv:8,custom:[2,10,13,15,16],customis:19,cut:[],cycl:1,dai:[4,8,10,11,14,16,17,18],dashboard:10,data:[],databas:[3,7,12],dataset:8,date:[],dateoffset:13,daterollconvent:16,deadlin:16,deal:[1,11,15,16],dealstat:16,debug:12,decd098666b9657314870e192ced0c3519c2c9d395507a238338f8d003929de9:10,decd:10,decentralis:11,decid:[5,11,17],decis:[2,3],declar:[1,9,17],dedic:1,defin:[1,2,3,7,9,10,11,12,13,16,17,18,19],definit:[2,12,16,17],delai:[8,11],delet:[1,3,12,17],deliber:3,deliv:[9,16],deliveri:[7,9,12,15,17],demand:[3,16],demo:[],demonstr:[15,19],denial:2,denomin:7,dens:1,depend:[1,2,3,4,5,11,12,13,17],dependencytxid:12,deposit:[7,17],depth:17,deregist:9,deriv:[8,12,17],describ:[1,2,3,4,6,12,16,17],descript:1,deserv:14,design:[1,2,3,6,7,11,17,19],desir:[12,16,17],desktop:10,despit:[12,17],destin:9,destroi:[3,17],destroypaperatredempt:[17,18],destructur:17,detail:[],detect:1,determin:[4,8],develop:[1,3,7,9,12,13,14,15,17],devic:3,devis:3,diagram:[8,18],diamond:18,didn:[1,12,14,17],differ:[1,3,4,8,11,12,13,16,17],difficult:[9,12],digest:2,digit:[3,11,12,13,17],digitalsignatur:[2,11,12],direct:1,directli:[1,10,16],directori:[0,15,17,19],directthreadexecutor:1,dirti:17,disadvantag:3,discov:3,discuss:[3,9,16],disk:[12,13,16],disobei:11,disprov:6,disput:[2,8,17],disrupt:9,distinct:1,distinguish:17,distribut:[2,3,6,7,11,12],distrust:[2,12],divid:2,dlg:12,doc:[0,1,17],docker:10,docsit:[0,14],doe:[1,2,3,4,7,8,9,10,11,12,17,19],doesn:[1,2,3,5,9,10,11,12,15,17],dokka:0,dollar:[17,18],domain:[17,18],don:[1,3,5,7,9,12,14,17],done:[0,3,12,17],dot:8,doubl:[3,7,15,17],doubt:[1,7],down:[1,3,11,17],download:[],downsid:[1,3],drag:18,drive:[3,19],driven:15,driver:[13,19],drm:11,dsl:[13,17,18],due:[1,3,4,7,8,11,12,17],dummi:17,dummy_pubkey_1:17,duplic:17,durat:[4,11,17],dure:[1,4,8,13],dynam:[17,19],each:[1,2,3,4,7,8,9,11,12,13,14,17,19],earli:[1,17,18,19],earliest:[4,8],eas:9,easi:[1,3,7,11,17],easier:[1,12,17],easiest:17,easili:[1,11,12,15],econom:8,ed25519:13,edit:5,editor:5,effect:[3,8],either:[1,2,3,8,11,12,17,19],element:[1,3],elimin:7,ellipt:[],els:[2,3,17],emb:[4,17],embed:[3,10,11],emit:17,empti:[13,17],enabl:17,encapsul:[1,16],enclos:1,encod:11,encount:7,encrypt:7,end:[1,7,8,11,12,14,19],endpoint:10,enforc:[1,3,17],engin:17,english:[1,17],enorm:12,enough:[1,5,9,12,17,19],ensur:[1,2,3,5,9,12,14,16,17],enter:[17,19],entir:[2,3,8,9,11,17],entireti:8,entiti:[2,3,11,17],entri:[3,8,12,17],enumer:8,environ:[1,11,12],envisag:17,equal:[2,12,17],equival:[1,8,16,17],especi:[16,18],essenti:[10,11,16,17],establish:[4,15],etc:[1,8,11,12,13,14,16,17],euribor:[10,11],evalu:[8,11],even:[3,7,9,11,12,17],event:[],eventu:14,ever:[1,3],everi:[2,3,11,12,13,14,17,19],everybodi:[3,11],everyon:[2,11],everyth:[2,9,17,19],evid:11,evolut:3,evolv:[17,19],exact:[11,17],exactli:[3,9,17],examin:[1,3,11,17],exampl:[],excel:11,except:[1,12,17],excess:1,exchang:[8,12,16,17],execut:[3,4,11,16,17],executor:[1,9],exercis:17,exhaust:13,exist:[1,2,3,4,6,8,17,19],exit:17,expect:[1,4,9,12,14,17],expectedtypenam:12,expectfailureoftx:17,expens:1,experi:[3,14,19],experiment:[1,4,12,13],explain:[1,4,9,12,13],explan:1,explicit:[1,3,11,12],explicitli:[1,3,17],explor:[1,3,5,6,7,10,17,19],exploratori:9,expos:[1,4,9,10,11,12,16],exposur:8,express:[3,7,8,11,12,13,17],extend:[1,2,7,16,17],extens:[1,13,16,17],extent:3,extern:[12,19],extract:[3,10,11,12,16,17],extrem:[3,11,17],face:[7,17,18],facevalu:17,fact:[1,2,3,8,11,12,17],factor:[3,8],factori:4,fail:[9,17],failur:[12,17],fairli:[1,12],fake:[15,17,19],fals:[1,9,11,12,17],familiar:[3,17],far:[12,15,17],fashion:1,fast:[3,9,15],fault:12,featur:[1,12,13,14,17,18],feed:11,feel:[17,19],fetch:[9,10,11],few:[1,7,9,10,11,12,14,15,17],fiber:12,field:[1,8,11,12,13,17,18],file:[0,1,3,9,10,12,15,16,17,19],fill:[1,12,17],filter:1,filterisinst:17,finalis:[8,12],financ:[12,19],financi:[3,4,6,12,13],find:[0,3,10,12],fine:3,finish:[9,12],firm:17,first:[1,2,4,5,8,9,10,11,12,13,15,16,17,19],firstli:17,fit:[1,3],fix:[],fixabledealst:16,fixedleg:8,fixedlegpaymentschedul:8,fixedratepaymentev:8,fixingroledecid:4,fixingsessioninitiationhandl:4,fixof:11,flag:[10,19],flexibl:[2,3],flight:3,floatingleg:[4,8],floatinglegpaymentschedul:8,floatingratepaymentev:8,flow:[1,8,17],flux:19,fly:12,fold:1,folder:0,follow:[0,1,2,3,4,5,6,9,10,11,12,16,17,18],font:1,foo:[1,9],foobrokenexcept:1,fooutil:17,forc:[3,10,13],fordai:[4,11],forev:14,forget:[12,17],form:[2,3,4,12,17],formal:[9,17],format:[0,1,3,10],forth:12,forward:[9,11,12,14,15],found:[5,10,11,12,14,19],four:[7,17],frame:[1,12],framework:[],free:[3,11,12],freeform:17,freeli:11,frequenc:8,frequent:12,fresh:[11,17],freshkei:12,freshli:17,from:[0,1,2,3,5,7,8,9,10,11,12,13,14,16,17,18,19],front:17,frustrat:3,full:[1,2,9,12,17],fulli:[1,3,9,12,13,17],fullysign:12,fun:[2,4,11,12,17],fund:3,fundament:[2,3,6,17],fungibl:[7,16,17],fungibleasset:[],funni:12,further:[3,7,8,16],futur:[2,3,11,12,16,17,18,19],gain:7,game:12,garbag:[1,10,12],gather:17,gavin:3,gbp:16,gcd:3,gear:14,gener:[],generateirsandfixsom:8,generateissu:17,generatemov:17,generateredeem:17,generatespend:[12,17],genuin:1,get:[],getbloomfilters:1,getclass:17,getcommand:17,getfacevalu:17,getfix:8,getinput:[13,17],getinst:13,getissu:17,getkei:17,getlegalcontractrefer:17,getmaturityd:17,getnotarysignatur:2,getoutput:[13,17],getoutst:13,getown:17,getprogramref:17,getprotocoltrack:12,getsign:17,getter:17,gettim:17,getvalu:17,git:[5,14],github:0,give:[2,3,17],given:[2,3,9,11,12,17],givenpric:12,global:[1,3,11,13],glue:12,gnu:0,goal:[1,3,6,7,12,14],goe:15,gone:[12,17],good:[1,5,12,17,18,19],got:[10,12],gover:17,grade:16,gradl:5,gradlew:[5,15],grammar:1,granular:3,graph:[3,7,10,12,17,18],graphit:10,greater:1,greatest:3,green:5,groom:3,group:[],groupstat:17,guarante:14,guava:1,gui:12,hack:3,had:[2,13,17],hand:[4,12,17],handl:[1,2,3,9,12,13,17],handler:[4,9,12],happen:[1,2,3,4,11,12,14,17],happi:15,hard:[1,3,12,14],harder:[3,17],hase:8,hash:[2,3,7,10,11,12,16,17],hashcod:17,hashmap:[],hasn:5,hassl:12,hat:14,have:[1,2,3,4,5,7,8,9,11,12,13,14,15,17,19],haven:17,heap:12,hearn:3,heart:17,heavi:14,heavili:3,hedg:8,heirarchi:1,held:17,hell:12,hello:12,help:[1,3,4,9,12],helper:[8,9,17],henc:[2,3,8],her:[17,18],here:[1,3,7,9,10,11,12,13,16,17,18,19],hierarch:12,hierarchi:12,high:[3,11,12],higher:[1,2,5,17],highlight:[13,17],histori:[2,12],hit:[3,5],hold:[3,9],holder:[1,3,17],holidai:[8,11,16],home:5,hood:12,hopefulli:19,hotspot:1,how:[],howev:[2,3,8,9,11,12,16,17],html:[0,1],http:[0,5,10,11,15,17,19],hub:12,human:[3,11,12],hundr:12,hurt:12,hypothesi:6,idea:[1,3,5,7,12,17,19],ideal:[12,17],ident:[2,3,11,12,16,17],identifi:[3,7,8,9,10,11,12,16],identityless:3,identityservic:12,ignor:17,illeg:11,illegalargumentexcept:[1,11,12,17],illegalstateexcept:[1,17],illustr:1,imagin:[1,12,17],immedi:[3,17],immut:[1,3,8,11,17],imper:1,implement:[],impli:12,implic:[2,3],implicitli:8,impos:[11,12,17],imposs:[3,11],improv:[3,13,14,17,18],inbackground:9,includ:[],incorpor:11,increas:[1,9],indent:1,independ:[2,11],index:[3,4,5,8,17],indexsourc:4,indic:[1,4,8,9,12,17],individu:[1,9,17],industri:[6,7,10],infer:17,infix:17,influenc:10,info:12,inform:[1,2,3,12,16,17],infrastructur:[3,7,10],inher:3,inherit:[1,9,17],init:11,initi:[2,9,12,13,17,19],initialis:2,inmemorymessagingtest:9,inmemoryuniquenessprovid:[],inoutgroup:17,input:[2,3,11,12,13,16,17,18],inputindex:2,insert:[1,9,10,11],insid:[3,9,12,15,17],instal:[0,4,5,15],installdist:15,instanc:[],instant:[1,4,11,12,17],instanti:[3,4,12,13],instead:[1,3,4,7,13,17,19],instig:2,institut:[3,7],institutionrefer:17,instruct:[10,17],instrument:[4,8],insuffici:3,insufficientbalanceexcept:17,integ:[13,17],integr:[1,11,12,13,18],intellig:1,intend:[1,3,10,11,12,16],intent:[11,17,18],intention:1,inter:7,interact:[1,3,11,12],interchang:16,interest:[],interestrateswap:7,interfac:[],intern:[1,7,9,17],internalis:1,interop:[7,17],interpret:[1,3,17],intersect:17,interv:16,introduc:[1,2,4,11,13,16,17],introduct:[],intuit:1,invalid:[2,11,12,17],invari:17,investig:12,invoc:9,invok:[1,3,4,9,10,12,13,17],involv:[2,3,9,11,12,16,17,19],iou:[],ipsa:11,irrelev:4,irsdemo:15,irsexport:8,irstest:8,irsutil:8,isaft:17,isempti:17,isinst:12,isn:[1,12,17,19],issu:[2,3,7,9,11,14,16,17,18,19],issuanc:[12,16,17,18],issuer:[3,17],item:17,iter:[12,14,17],itself:[2,3,4,8,9,10,11,12,17],jar:[0,3,10],jarinputstream:3,java:[1,3,4,7,9,10,12,13,17,19],javaclass:12,javacommercialpap:17,javadoc:1,jdk1:5,jdk:[5,12,13,17],jetbrain:[5,7],jira:[],jmx2graphit:10,jmx:10,jmxtran:10,job:19,join:[9,17],joint:17,jolokia:10,json:[10,19],judgement:1,jump:15,junit:17,just:[1,3,5,9,10,12,13,17,19],justifi:6,jvm:[3,7,10,12,19],kafka:9,kdoc:1,keep:[3,12,17,18],kei:[1,3,7,9,11,12,16,17],kept:12,key_mismatch_at_issu:17,keymanagementservic:12,keypair:[12,17],keyword:[1,17],kick:12,kind:[3,7,9,11,12,17,19],know:[2,3,4,7,11,12,15],knowledg:11,known:[],kotin:17,kotlin:[],kryo:[9,12],label:[12,17,18],labori:17,lack:[],land:8,languag:[1,3,5,6,7,17,18,19],larg:[3,11,12,16,17,19],larger:[1,3],last:14,latenc:[2,11],later:[1,3,7,9,11,12,16,17],latest:[1,5,13],latter:[1,17],launch:4,layer:[3,9,12],layout:18,lead:[1,3,17],leak:[2,3,12],learn:[3,6,12,15,17,19],least:[11,17],leav:[1,12],ledger:[2,3,6,8,10,11,12,13,17,18],ledgertransact:16,left:[9,12],leg:[4,7,8],legal:[2,3,11,16,17],legalcontractrefer:17,legallyidentifi:[2,11,12],legallyidentifiablenod:12,less:[12,17,18],let:[1,3,4,10,11,12,13,15,17],letter:1,level:[1,2,5,8,9,11,12,16,17],lib:0,liber:1,libor:[8,10,11],librari:[1,10,11,12,16,17],licens:1,life:19,lifecycl:[],lifetim:8,like:[1,2,3,4,5,8,9,10,11,12,14,16,17,19],likewis:17,limit:[3,6,17],line:[],linearst:16,liner:1,link:[1,3,11,12,16,17],linkabl:3,linux:[10,13],list:[0,3,9,11,12,13,14,15,16,17],listen:1,listenablefutur:12,liter:3,littl:[1,17],live:8,livelock:3,load:[2,3,15,16,17,19],loan:[8,11],local:[0,3,5,10,11,12],locald:11,localhost:10,locat:[16,17],lock:[1,17],log:[12,15],logger:12,logic:[2,3,4,7,9,12,13,17,19],longer:[1,8,11,12],look:[1,8,9,10,11,12,14,17,19],loop:[1,8,17],loquitur:11,loss:11,lot:[1,3,8,15,19],low:[2,12],lower:[1,11],lurch:12,mac:10,machin:[],maco:15,made:[1,3,6,8,12,13,14],mai:[1,3,7,9,10,11,12,14,17,19],mail:[14,15],main:[4,12,17,18,19],maintain:[2,3],maintan:11,mainten:9,major:14,make:[0,1,2,3,8,9,11,12,13,14,15,17],makenod:9,maker:7,malici:12,manag:[],mani:[1,3,4,7,9,11,12,13,16,17],manipul:16,manner:12,manual:[4,9],map:[],mappabl:17,mark:[1,12,17],markdown:1,marker:[12,17],market:6,master:[],match:[3,9,11,12,17],matter:17,matur:[8,10,11,17],maturityd:17,maven:5,maximis:3,maximum:3,maybestx:12,maybetraderequest:12,mbean:10,mean:[1,3,4,9,11,12,16],meaning:2,measur:[8,17],mechan:[13,17],meet:17,mega_corp:17,mega_corp_kei:17,mega_corp_pubkei:18,megacorp:[17,18],member:8,memori:[],menlo:1,mention:[4,12],menu:5,mere:[8,17],merg:[3,7,13,16,17],mess:12,messag:[],messagehandlerregistr:9,messagerecipi:9,messagerecipientgroup:9,messagingservic:[9,12],method:[],metric:10,middl:[1,9,12],might:[1,3,5,8,12,17],mike:3,mileston:[],mind:[1,11,12,17],mine:3,minim:[3,12],minimis:[2,3,9],minimum:[3,8],minor:14,minu:17,minut:[7,11],misc:9,miss:[1,12,17,19],missingsig:12,mission:10,mix:[1,12,17],mock:9,mode:9,model:[],modest:3,modif:17,modifi:[2,5,8,12,16,17],modul:[1,9,13,17],moment:9,monei:[11,17],monetari:17,monitor:[],month:[8,12,14],more:[1,2,3,7,8,9,10,11,12,13,15,16,17],moreexecutor:1,most:[1,3,8,9,10,11,12,17],mostli:17,move:[12,13,14,17,18],movement:[12,17],much:[1,3,7,12,13,17,19],multi:[1,7,12,17],multilater:13,multipli:8,must:[1,2,3,4,9,10,11,12,17,19],mutabl:[1,3,17],mutat:3,mutual:[2,12],myfil:10,mykeypair:12,nail:1,namedbyhash:16,namespac:12,narrow:1,nativ:12,natur:17,naval:[3,11],navistar:11,necessari:[1,2,14,15],need:[0,1,2,3,4,6,8,9,10,12,14,15,16,17,19],negoti:[3,16],neither:[12,17],nest:12,net:[8,13,17,18],nettabl:7,network:[],neutral:7,never:[1,3,11,17],newli:[4,12],newnotari:2,newown:17,newsecurerandom:13,next:[1,4,5,8,12,17],nextfixingof:4,nextscheduledact:4,nice:15,nio:1,noddi:10,node:[],nodea:15,nodeb:15,nodeinterestr:11,nodeservic:11,non:[],none:[4,12],nonemptyset:13,normal:[8,12,16,17],not_matured_at_redempt:17,notabl:1,notaris:2,notarychang:13,notarychangeprotocol:2,notaryexcept:2,notaryprotocol:2,notaryservic:13,notat:12,note:[],noth:[1,3,4,13,17],notic:[1,17],notif:9,notifi:9,notion:[3,8,17],notnul:17,now:[1,3,5,9,11,12,13,15,17,18,19],nugget:17,nullpublickei:17,number:[1,3,8,9,11,12,14,15,16,17],numer:3,obj:17,object:[1,3,4,7,8,9,10,11,12,13,16,17,18,19],oblig:[7,8,13,16],observ:[3,4,8,11,12],observatori:[3,11],obsolet:4,obtain:[],obviou:[1,2,3,11],obvious:[8,17],occasion:[],occur:[2,4,11,12,17],occurr:11,odd:[12,17],off:[9,12,17,18],offer:12,offlin:9,offset:8,often:[1,3,8,11,12,17],oftenor:11,oil:13,old:2,omit:4,onc:[0,1,2,4,7,8,9,11,12,14,16,17,19],onli:[1,2,3,7,8,9,10,11,12,13,17,18,19],onto:[1,12,17,18],opaqu:[7,9],opaquebyt:17,open:[2,3,5,11,12,15,18],openjdk:5,oper:[4,8,9,10,11,12,17],optim:1,option:[0,1,4,8,9,11,12,17,19],oracl:[],orchestr:[6,7,13,19],ordain:8,order:[0,1,2,3,7,8,9,12,16,17,18],ordinari:[3,12,17],org:[0,5,17],orient:[],origin:[16,17],originalst:2,otc:7,other:[1,2,3,4,7,8,9,11,12,15,16,17],othersid:12,otherwis:[1,4,12,17],our:[1,2,3,4,12,14,17],ourselv:[12,17,19],oursignatur:12,out:[1,2,3,4,5,7,10,11,12,17],outag:9,outcom:12,outlin:[3,12],outpoint:3,output:[2,3,11,12,13,15,16,17,18],outsid:[3,9,11,12,17,19],outstat:17,over:[1,2,3,8,9,10,11,12,16,17],overal:[2,4,9],overdu:4,overflow:1,overload:12,overnight:16,overrid:[4,12,17],overwhelm:3,own:[1,2,9,10,11,12,13,14,17,18,19],ownablest:[12,16],owned_bi:17,owner:[12,16,17],ownership:[12,17],owningkei:[12,17],p2p:12,pack:17,packet:3,page:[5,11,17],pai:[11,12,17,18],paid:[3,8],pair:[3,12,17],paper:[],paper_1:[17,18],parallel:[3,9,12],parallelis:3,paramet:[1,4,12,15,17],parameteris:3,parent:12,pars:[11,19],part:[1,2,3,4,11,12,13,16,17,19],parti:[],partial:[2,12,17],partialtx:12,particip:[2,3,13,17,19],particular:[1,2,3,10,12,13],partyandrefer:1,partyrefer:[1,17],pascal:1,pass:[2,9,12,17,18],past:[1,11,15,17,19],patch:1,path:[1,4,10,17],pattern:[1,3,17],paye:3,payer:[3,8],payment:[3,4,8,11,12,15,17,18],pdf:11,peer:[7,9,11,12],penni:17,peopl:[1,3,7,17],per:[1,3,4,19],perform:[1,2,3,4,8,11,12,15,17],perhap:[1,3,4,17],period:8,perman:17,persist:[7,9,12,13],perspect:[3,12,17],phrase:11,physic:[2,11,13],pick:[9,12,13,14,17,19],piec:[1,2,3,9,12,17],ping:9,pip:0,pki:3,place:[0,1,3,4,7,8,9,11,12,14,16,17,19],plai:12,plan:[9,15],platform:[2,3,4,6,7,8,9,11,12,16,17],pleas:[1,3,5,13,17],pluggabl:13,plugin:[5,10],point:[1,2,3,4,10,11,12,14,17],pointer:[2,12,16],pointless:1,pong:9,pool:[1,3,12],poor:3,pop:[5,9],popular:7,popup:5,port:14,posess:12,posit:[1,2,3,12],possess:2,possibl:[3,9,11,12,17],potenti:[1,2,7,12,17],pound:17,power:[3,6],practic:[3,17],pre:[0,3,8,12,17,19],preced:17,precis:[3,7,11],precondit:1,prefer:[1,3],prefix:[1,12],preliminari:9,prepar:[3,17],present:[2,6,8,11,16,17],preserv:[2,3],press:17,pretend:10,pretti:[3,12,17],prevent:17,previou:[3,13,16],previous:[4,8,11,13],price:[3,11,12],primari:[7,11],primit:17,print:15,priv:12,privaci:[1,2,3,12,13,17],privat:[1,3,12,17,19],privatefoo:1,probabl:[5,11,17,19],problem:[2,3,11,12],proce:12,procedur:12,process:[],processor:3,produc:[0,4,17,18],product:[1,4,6,7,14,16,17],profit:[17,18],profound:3,program:[1,3,9,10,12,15,16,17,19],programref:17,progress:[],progresstrack:12,project:[5,15],proof:[3,6],propag:[6,10,17],properli:12,properti:[],propos:[6,12],prose:[11,16],protect:12,protocol:[],protocollog:[4,12],protocollogicref:4,protocollogicreffactori:4,protocolstatemachin:12,protocoltrack:12,prototyp:[1,3,6,7,11,17],prove:[2,3,6,17],provid:[0,1,2,3,8,9,10,11,12,16,17,19],provision:16,pseudo:11,ptx:12,publicfoo:1,publickei:[],publicli:[],pull:5,pump:9,punish:11,purchas:[12,15],pure:[3,11],purpos:[7,12,17],push:14,put:[1,12,14,17,19],python:0,qualiti:6,quantiti:[3,7,17],quasar:12,queri:[4,8,11],question:[1,2,4,5,11],queu:9,queue:[1,9,12],quick:11,quickli:[3,9,17],quit:[1,11,12,17],r3corda:13,r3dlg:14,r3prototyp:[0,5,15],r3repositori:5,rais:2,random63bitvalu:12,random:[3,4,12,13],rang:11,rapid:[1,7,14],rate:[],ratefixprotocol:11,rather:[1,3,12,13,17],raw:[10,12],reach:[2,3,4,8,11],reachabl:12,read:[1,3,6,7,10,11,12,17,19],readabl:[7,12],reader:17,readi:[14,17],readili:16,readm:1,real:[1,9,11,17,19],realis:12,realism:9,realiti:8,realli:[1,2,3,12,17],reason:[1,3,8,12,16,17],reassign:17,recal:8,receiv:[3,8,9,11,12,14,17,18],receiveandcheckproposedtransact:12,receiveandvalidatetraderequest:12,recipi:[3,9,17],recognis:[3,11,17],recommend:[1,9,19],record:[2,4,9],recordtransact:4,recov:9,recreat:12,red:[5,8],redeem:[7,17,18],redempt:[17,18],redemptiontim:[17,18],reduc:1,redund:1,ref:[12,17],refactor:13,refer:[1,2,3,4,7,8,11,12,16,17],referenc:2,refin:7,reflect:17,refus:5,regard:2,regardless:12,regener:[8,14],regist:[1,9,10,12,19],registr:9,regular:[10,12,17],reissuanc:[3,17],reject:17,rel:[3,9],relabelablestep:12,relat:[8,17],relationship:17,releas:[],relev:[3,13,16],reli:3,reliabl:9,relianc:3,relic:10,religi:1,remain:[4,17,18],remeb:5,rememb:[1,4,5,12,17],remind:12,remot:5,remov:[9,12,17],renam:13,render:[1,12,18],repeat:[1,8,9,12],replac:[2,5,8,10,14,16,17],replic:3,repoint:2,report:9,repositori:[],repres:[1,3,8,9,11,12,16,17],represent:8,request:[2,3,9,11,12,13],requestingparti:2,requiresinglecommand:17,requirethat:17,resel:11,reserv:12,reset:8,reshap:3,resolut:[2,3,6,12],resolv:[1,12,16],resolvetransactionsprotocol:12,resourc:12,respect:[1,3,12,15,17],respend:3,respons:[2,3,4,9,11,12],rest:[2,3,7,9,10,12,19],restart:[5,12],restor:12,restrict:1,restructuredtext:0,result:[1,2,3,8,11,12,17],resultfutur:12,resum:[12,13],resurrect:12,retain:9,retri:[7,9,12],retriev:[2,8],reus:[3,12],reusabl:11,reveal:[2,3,12,17],revers:12,review:[1,13,14],revis:8,rewrit:12,right:[1,5,9,10,12,14,19],rigid:3,rigidli:1,risk:12,robust:13,role:[4,15,19],roll:[8,12,15],rollov:[16,17],root:[15,17,18],roughli:[11,14],rout:12,router:9,rule:[1,11,12,13,17],run:[],runbuy:12,runnetwork:9,runsel:12,runtim:[1,12],safe:[1,3,12,17],safeti:1,sai:[1,2,3,17],sale:[15,17],same:[1,2,3,4,7,8,9,11,12,15,17,18],sandbox:[3,4,7,17],saniti:12,satisfi:17,save:[1,17],scala:[7,17],scalabl:[1,3],scale:8,scenario:[3,19],scene:[12,17],schedul:[],schedulablest:4,scheduledact:4,scope:[3,17],scrape:10,scratch:19,screen:[1,5],script:[0,3,17],scroll:15,scrub:12,seamless:7,search:[5,12,17],second:[8,12,15,17],secondari:12,secp256r1:13,section:[3,14,17],secur:[3,4,9,12],securehash:[2,17],securerandom:13,see:[0,1,2,4,7,8,9,11,12,15,16,17,19],seed:12,seek:3,seem:3,seen:[1,8,11,12,17,18],select:[2,5,13,17],self:[],sell:[12,17,19],seller:[],sellerownerkei:12,sellersig:12,sellertradeinfo:12,semi:[3,11],send:[1,3,9,10,11,12,14,17],sendandrec:12,sender:3,sendsignatur:12,sens:[8,11,12,17],sensit:4,sent:[4,9,12,17],separ:[2,3,10,11,12,15,16,17],sequenc:[3,9],sequenti:[9,12],seri:12,serial:[7,9,17],serialis:[1,3,7,9,12,17],serializablewithkryo:17,serializeablewithkryo:17,seriou:[3,14],serious:19,server:[10,11,19],servic:[],servicehub:[4,12],session:[4,9,12],sessionid:[4,12],set:[],setof:12,setter:17,settim:12,settl:[9,11,16],settlement:12,setup:4,setupa:15,setupb:15,sever:[3,12,17,19],sha256:17,sha256sum:10,sha:[3,10],shape:3,share:[3,8,11,12,17,19],shasum:10,she:17,shortcut:7,shorthand:17,shot:9,should:[1,2,3,4,5,7,9,12,13,15,16,17,19],shoulder:1,shouldn:[12,17],show:[3,5,7,15,17,18],shown:[12,17],shutdown:12,side:[11,12],sig:17,sign:[2,3,7,8,9,11,12,16,17],signatur:[],signatureexcept:12,signaturesfromsel:12,signedtransact:[12,16,17],signer:[11,17],signific:3,significantli:8,signoff:11,signwith:[12,17],signwithecdsa:12,signwithourkei:12,silver:1,similar:[1,3,9,11,13,17],simpl:[1,3,7,8,9,10,12,17,18],simplenotaryservic:2,simpler:[3,7],simplest:[3,12,17,19],simpli:[1,2,3,9,12,16,17],simplifi:[1,3,9,16,17,19],simultan:[3,9,12,17],singl:[1,3,10,11,12,17,18,19],singlemessagerecipi:[9,12],singleton:[12,17],sit:9,site:[1,14],situat:[1,3],size:[1,3,8,12,17],skip:12,slight:17,slightli:17,slip:14,slow:[1,3],slowest:3,small:[3,4,11,12,15,17,18],smaller:13,smart:[],smm:12,smooth:17,snapshot:[3,13,14],snide:0,snippet:[2,12,17],softwar:[12,14,19],sold:[12,17,18],solv:[3,11,12],solvenc:11,some:[1,2,3,4,7,9,10,11,12,13,15,16,17,18,19],somed:17,someon:[2,3,9,17],someprofit:[17,18],someth:[1,3,5,8,15,16,17,19],sometim:[3,9,10,11,12,17],somewhat:[3,12],somewher:[17,18],sophist:3,sort:[11,12],sound:[1,12,17,18],sourc:[4,5,8,11,12],sparingli:1,special:[2,3],specialis:12,specif:[2,3,4,9,10,11,12,13,16,17,18],specifi:[0,1,2,3,7,9,11,12,13,17,19],speed:[3,12],spend:[3,7,12,17],spent:3,sphinx:0,sphinx_rtd_them:0,spirit:13,split:[3,7,13,16,17],spread:[2,9,12],spreadsheet:11,squar:18,src:[17,18,19],ssl:7,stabilis:14,stabl:14,stack:12,stage:[1,12,17,19],stai:[3,17],stake:3,standalon:11,standard:[1,6,10,12,16,17],standardis:[3,16,17],start:[],state:[],stateandref:[2,12,16,17],statehistori:2,stateless:3,statemachinemanag:12,statement:[1,3,11,12,17],stateref:[2,3,4,16],statesoftyp:12,statist:10,status:3,step:[],still:[2,3,4,12,13,17,19],stock:[3,11],stop:[1,9,12],storag:3,store:[2,12,13,16,17],stori:1,straightforward:[12,17],stream:12,stress:1,strictli:[3,8],string:[9,11,12,17],strong:7,structur:[1,3,5,7,11,12,17],studi:17,stuff:[1,12],stx:12,sub:[1,12],subclass:[12,16],subgroup:3,submiss:11,submit:[1,2,9,12],subprotocol:[2,12],subscrib:9,subtask:12,subtl:[1,3],successor:[2,4,7],succinct:1,sudo:0,suffer:3,suffic:11,suffici:[3,6,9,11,14],suffix:17,suggest:[9,17],suggestinterestrateannouncementtimewindow:4,suit:13,suitabl:[4,9,14],sum:17,sumcashbi:[12,17],sumcashornul:17,summari:[13,14],summaris:3,sun:1,superclass:[12,13,16],superior:1,supersed:3,supertyp:17,suppli:15,support:[],suppos:[12,17],suppress:[1,13],suppresswarn:1,sure:[2,13,14,15,17,19],surfac:12,surround:[1,17],surviv:12,suspend:[],swap:[],swapsignatureswithsel:12,symbol:5,synchronis:[1,3,11],syntax:[7,17],system:[2,3,7,10,11,12,13,15,17],tab:[1,5],tag:[1,14],tailor:6,take:[1,4,7,8,12,16,17,18],tamper:12,target:[0,1,3,7,10],targetrecipi:9,task:[3,4,12],team:5,technic:[],techniqu:[1,3,11,17],tell:[0,9,12],templat:16,tempor:11,temporari:3,temporarili:[12,14],tempt:17,temptat:12,ten:17,tenor:[8,10,11,16],term:[3,4,16,17],termin:[8,10,12,15],terminolog:3,test:[],test_tx_tim:17,testutil:17,testwithinmemorynetwork:9,text:[1,5,10],than:[1,2,3,6,10,12,13,17,18],thei:[1,3,4,7,8,9,10,11,12,14,15,16,17],theirsessionid:12,them:[1,3,4,5,7,8,9,10,12,14,15,16,17,19],themselv:[9,11,12,16,17],theori:[],therefor:[3,5,7,12,14,17],thi:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19],thing:[1,3,4,7,11,12,15,16,17,19],think:[1,3,5,12,17],third:[3,15,17],thisstateref:4,those:[3,4,9,10,11,12,16,17],though:[9,10,12,17],thought:[3,7],threadsaf:1,three:[15,16,17],threshold:17,through:[3,4,8,10,12,17,19],throughput:[2,3],throwifsignaturesaremiss:12,thrown:17,thu:[1,3,4,10,11,17],tighten:17,tightli:12,time:[1,2,3,4,7,8,10,11,12,13,16,17,18],timelin:17,timestamp:[],timestampauthoritysig:12,timestampcommand:11,timestampercli:17,timestamperservic:11,timestampingauthor:12,timestampingprotocol:12,titl:5,todo:[1,12,17],togeth:[3,12,17],token:16,told:1,toledgertransact:12,toler:[2,4,11],too:[1,12,17,18],took:12,tool:[7,10],toolbar:5,top:[1,3,5,12,17],topic:[9,12,19],topriv:12,toset:12,tosignedtransact:[12,17],tostr:[1,12,17],total:[3,17],toward:14,trace:12,track:[],tracker:12,trade1:15,trade:[],trade_top:12,tradeoff:[],trader:[],traderdemo:19,traderequest:12,tradit:[3,17],traffic:[3,12],transact:[],transactionbuild:[12,13,17],transactionforverif:17,transactiongroup:17,transactiongroupdsl:18,transactiongroupfor:18,transactiongroupfortest:17,transactionst:[2,13,16],transactiontyp:13,transfer:17,transit:[6,17,19],treat:17,tree:12,tri:[3,17],tricki:[3,12],trigger:[4,11,15],trivial:[1,3],trust:[3,12],truth:12,tsa:[3,12],tsasig:12,tupl:1,ture:3,turn:[3,12,16,17,19],tutori:[6,7,11,12,13,17,19],twice:7,two:[],twopartydealprotocol:4,twopartytradeprotocol:12,txbit:12,txhash:[3,12,17],txt:10,type:[],typenam:12,typetobui:12,typic:[3,4,9,10,12,16,17,19],unacceptablepriceexcept:12,under:[0,12,14,17,19],underli:[3,8,12,16],underscor:[1,17],understand:[3,9,10,17,18,19],unexecut:17,unexpect:12,unfinish:12,unfortun:[12,17],unguess:12,unifi:19,uniform:4,unindex:5,uniqu:[2,3,11,12,13],uniquenessprovid:[],unit:[2,3,5,7,9,12,13,17,18,19],unix:[10,15],unknow:11,unless:[1,11,12,14,17,19],unlik:[5,17],unnatur:3,unnecessari:17,unpack:[12,17],unqiu:4,unread:12,unrecognis:17,unrel:17,unreleas:[],unschedul:4,unserialis:12,unset:8,unspent:3,unstart:12,unsupportedoperationexcept:17,until:[2,3,4,8,9,12,14,19],untrustworthydata:12,unus:9,unusu:17,upcom:4,updat:[3,5,9,12,13,14,17],upgrad:[5,6,13],upload:[],upon:[8,12,17],url:5,usabl:[7,14],usag:[],usd:16,useless:17,user:[0,1,3,5,7,9,11,12,13],usr:0,usual:[1,3,14],utc:4,util:[9,17],vagu:1,val:[1,2,4,9,11,12,17,18],validatingnotaryservic:2,valu:[1,3,7,8,11,17,18],valuabl:11,valuat:8,vanilla:[7,8],vari:[],variabl:[1,3,8,12,17],variant:17,variou:[1,3,7,10,12,17],vehicl:3,vendor:[7,10],verbos:17,veri:[1,3,7,11,18,19],verif:[3,7],verifi:[],verifytransact:12,versa:[8,12,16],version:[5,8,9,12,13,14,16,17],versu:12,vertic:1,via:[0,1,3,4,8,10,11,12,15,19],vice:[8,12,16],view:[1,8],virtual:[3,6],visibl:[2,3],visualis:[],vital:12,wai:[1,3,4,7,10,11,12,13,17,19],wait:[4,5,9,12,15],wallet:[3,4,12,13,17],walletservic:12,want:[1,3,5,9,10,11,12,13,17,19],weak:11,wear:14,web:[10,11],websit:17,weekend:8,well:[0,1,3,4,7,8,10,11,12,16,17],went:1,were:[1,3,11,12,17],what:[],whatev:[1,12,16],when:[1,2,3,4,8,9,10,11,12,13,17],whenev:1,where:[],wherea:8,wherev:10,whether:[2,9,11,12],which:[0,1,2,3,4,7,8,9,10,11,12,13,14,15,16,17,19],whilst:[3,11,12,15,17],whitelist:4,who:[1,3,7,9,12,13,17],whole:[2,17],whom:[3,9],whose:[10,16],why:[1,3,7,17],wide:[1,9,17],widescreen:1,widespread:1,width:1,wiki:[3,17],wikipedia:17,window:[3,5,12,15,18],wire:19,wirecommand:17,wiretransact:[2,11,12,16],wish:[3,9,11,12,13,17,19],within:[0,1,2,3,10,15],withkei:12,withnewown:12,without:[],withoutown:17,won:[9,11,12,15,17],word:[1,2],work:[1,2,3,4,5,6,7,8,9,10,11,12,13,15,16,17],worker:1,world:[3,11,12,17],worn:17,worri:[1,7,12],worst:3,worth:[1,17],worthless:11,would:[1,3,7,8,9,10,11,12,16,17,19],wouldn:[11,17],wrap:[1,10,12,13,16,17,19],wrapper:[1,2,12],write:[],written:[0,3,7,8,17],wrong:[1,12,15],wrote:3,wtx:[2,11,12],www:[0,5],year:8,yet:[1,3,7,8,12,17],yield:[3,12],you:[0,1,3,4,5,7,9,10,11,12,13,15,17,18,19],your:[],your_usernam:5,yourself:3,zero:[3,17],zip:[3,10],zone:4,zoneddatetim:4},titles:["Building the documentation","Code style guide","Consensus model","Data model","Event scheduling","Getting set up","Welcome to the Corda repository!","What’s included?","The Interest Rate Swap Contract","Networking and messaging","Node administration","Writing oracle services","Protocol state machines","Release notes","Release process","Running the demos","Data types","Writing a contract","Using the visualiser","Where to start"],titleterms:{"class":17,"function":17,about:5,administr:10,adopt:3,amount:16,api:17,approach:11,assert:[1,11],asset:17,attach:10,base:17,basic:11,bitcoin:3,build:0,buyer:12,cash:16,chang:2,check:17,code:1,command:17,comment:1,commerci:17,comparison:3,compil:1,complain:5,con:3,consensu:2,continu:11,contract:[7,8,17],corda:6,creat:8,cut:14,data:[3,11,16],date:16,demo:[15,19],detail:8,document:0,download:10,error:1,ethereum:3,event:4,exampl:4,fix:10,framework:11,fungibleasset:16,gener:[1,17],get:5,group:17,guid:1,how:[4,17],implement:[4,9,11,12],includ:7,instanc:8,intellij:5,interest:[8,10],interfac:9,introduct:[4,11,12],known:11,kotlin:7,lack:5,length:1,lifecycl:[8,16],line:1,machin:12,manag:12,map:9,memori:9,messag:9,method:12,mileston:13,model:[2,3],monitor:10,multipl:2,name:1,network:9,node:10,non:17,notari:2,note:13,obtain:2,occasion:11,oracl:11,orient:17,overview:3,paper:17,parti:[12,16],pro:3,process:14,progress:12,properti:1,protocol:12,publickei:16,publicli:11,rate:[8,10],rational:3,releas:[13,14],repositori:6,requir:[0,17],run:[2,15],schedul:4,sdk:5,seller:12,servic:[2,9,11],set:5,signatur:2,smart:17,space:1,start:[17,19],state:[12,16,17],step:14,style:[1,3],support:16,suspend:12,swap:8,technic:8,test:17,theori:12,thread:1,timestamp:2,track:12,trade:12,tradeoff:3,trader:[15,19],transact:16,two:[11,12],type:16,unreleas:13,upload:10,usag:[],utxo:3,valid:2,vari:11,verifi:17,visualis:18,warn:1,welcom:6,what:7,where:19,without:5,write:[11,17],your:[10,17]}}) \ No newline at end of file diff --git a/docs/build/html/transaction-data-types.html b/docs/build/html/transaction-data-types.html index b34ee7b810..9a9d97489c 100644 --- a/docs/build/html/transaction-data-types.html +++ b/docs/build/html/transaction-data-types.html @@ -8,7 +8,7 @@ - Transaction Data Types — R3 Corda latest documentation + Data types — R3 Corda latest documentation @@ -31,7 +31,7 @@ - + @@ -90,16 +90,16 @@
      • What’s included?
      • Getting set up
      • Data model
      • -
      • Transaction Data Types

        Appendix

          @@ -150,7 +151,7 @@
          • Docs »
          • -
          • Transaction Data Types
          • +
          • Data types
          • @@ -164,8 +165,8 @@
            -
            -

            Transaction Data Types

            +
            +

            Data types

            There is a large library of data types used in Corda transactions and contract state objects.

            Amount

            @@ -190,13 +191,15 @@ delivered (themselves referring to a currency), an -

            Contract State

            +
            +

            State

            A Corda contract is composed of three parts; the executable code, the legal prose, and the state objects that represent the details of the contract (see Data model for further detail). States essentially convert the generic template -(code and legal prose) into a specific instance. In a WireTransaction, outputs are provided as ContractState +(code and legal prose) into a specific instance. In a WireTransaction, outputs are provided as TransactionState implementations, while the inputs are references to the outputs of a previous transaction. These references are then stored as StateRef objects, which are converted to StateAndRef on demand.

            +

            The TransactionState is a 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).

            A number of interfaces then extend ContractState, representing standardised functionality for states:

            @@ -223,8 +226,8 @@ interface for its subclasses’ state objects to implement. The clear use-ca 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 Types

            +
            +

            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 @@ -244,7 +247,7 @@ for signatures present on the transaction, as well as list of parties for those

            -

            Date Support

            +

            Date support

            There are a number of supporting interfaces and classes for use by contract 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 @@ -265,7 +268,7 @@ dates used.

          • Protocol state machines
          • Writing oracle services
          • +
          • Event scheduling

          Appendix

          Appendix

          Appendix

            From 5c0e7fbbf20f92f7a6c5b536f94f33bdbd1faf2b Mon Sep 17 00:00:00 2001 From: Shams Asari Date: Tue, 5 Jul 2016 10:22:11 +0100 Subject: [PATCH 072/114] Moved topic parameter from send/receive methods to a ProtocolLogic property --- .../protocols/TwoPartyTradeProtocol.kt | 16 ++-- .../r3corda/core/protocols/ProtocolLogic.kt | 21 ++-- .../protocols/FetchAttachmentsProtocol.kt | 5 +- .../r3corda/protocols/FetchDataProtocol.kt | 6 +- .../protocols/FetchTransactionsProtocol.kt | 4 +- .../com/r3corda/protocols/NotaryProtocol.kt | 37 +++---- .../com/r3corda/protocols/RatesFixProtocol.kt | 17 ++-- .../protocols/ResolveTransactionsProtocol.kt | 2 + .../protocols/ServiceRequestMessage.kt | 7 +- .../r3corda/protocols/TwoPartyDealProtocol.kt | 29 ++++-- .../AbstractStateReplacementProtocol.kt | 26 ++--- .../kotlin/protocols/NotaryChangeProtocol.kt | 15 +-- .../ProtocolLogicRefFromJavaTest.java | 13 +++ .../core/protocols/ProtocolLogicRefTest.kt | 4 + .../node/internal/testing/TradeSimulation.kt | 4 +- .../node/services/NotaryChangeService.kt | 4 +- .../services/clientapi/NodeInterestRates.kt | 42 ++++---- .../statemachine/StateMachineManager.kt | 5 +- .../services/transactions/NotaryService.kt | 2 +- .../messaging/TwoPartyTradeProtocolTests.kt | 4 +- .../services/InMemoryNetworkMapServiceTest.kt | 23 ++--- .../node/services/NodeSchedulerServiceTest.kt | 1 + .../statemachine/StateMachineManagerTests.kt | 4 + .../kotlin/node/services/NotaryChangeTests.kt | 10 +- .../kotlin/com/r3corda/demos/TraderDemo.kt | 96 +++++++++---------- .../demos/protocols/AutoOfferProtocol.kt | 10 +- .../demos/protocols/ExitServerProtocol.kt | 7 +- .../protocols/UpdateBusinessDayProtocol.kt | 4 +- 28 files changed, 223 insertions(+), 195 deletions(-) diff --git a/contracts/src/main/kotlin/com/r3corda/protocols/TwoPartyTradeProtocol.kt b/contracts/src/main/kotlin/com/r3corda/protocols/TwoPartyTradeProtocol.kt index 9a3a5db056..7efd145934 100644 --- a/contracts/src/main/kotlin/com/r3corda/protocols/TwoPartyTradeProtocol.kt +++ b/contracts/src/main/kotlin/com/r3corda/protocols/TwoPartyTradeProtocol.kt @@ -42,7 +42,8 @@ import java.util.* * To see an example of how to use this class, look at the unit tests. */ object TwoPartyTradeProtocol { - val TRADE_TOPIC = "platform.trade" + + val TOPIC = "platform.trade" class UnacceptablePriceException(val givenPrice: Amount>) : Exception() class AssetMismatchException(val expectedTypeName: String, val typeName: String) : Exception() { @@ -82,6 +83,8 @@ object TwoPartyTradeProtocol { fun tracker() = ProgressTracker(AWAITING_PROPOSAL, VERIFYING, SIGNING, NOTARY, SENDING_SIGS) } + override val topic: String get() = TOPIC + @Suspendable override fun call(): SignedTransaction { val partialTX: SignedTransaction = receiveAndCheckProposedTransaction() @@ -108,7 +111,7 @@ object TwoPartyTradeProtocol { // Make the first message we'll send to kick off the protocol. val hello = SellerTradeInfo(assetToSell, price, myKeyPair.public, sessionID) - val maybeSTX = sendAndReceive(TRADE_TOPIC, otherSide, buyerSessionID, sessionID, hello) + val maybeSTX = sendAndReceive(otherSide, buyerSessionID, sessionID, hello) progressTracker.currentStep = VERIFYING @@ -166,7 +169,7 @@ object TwoPartyTradeProtocol { logger.trace { "Built finished transaction, sending back to secondary!" } - send(TRADE_TOPIC, otherSide, buyerSessionID, SignaturesFromSeller(ourSignature, notarySignature)) + send(otherSide, buyerSessionID, SignaturesFromSeller(ourSignature, notarySignature)) return fullySigned } } @@ -185,6 +188,7 @@ object TwoPartyTradeProtocol { object SWAPPING_SIGNATURES : ProgressTracker.Step("Swapping signatures with the seller") + override val topic: String get() = TOPIC override val progressTracker = ProgressTracker(RECEIVING, VERIFYING, SIGNING, SWAPPING_SIGNATURES) @Suspendable @@ -195,8 +199,6 @@ object TwoPartyTradeProtocol { val (ptx, cashSigningPubKeys) = assembleSharedTX(tradeRequest) val stx = signWithOurKeys(cashSigningPubKeys, ptx) - // exitProcess(0) - val signatures = swapSignaturesWithSeller(stx, tradeRequest.sessionID) logger.trace { "Got signatures from seller, verifying ... " } @@ -215,7 +217,7 @@ object TwoPartyTradeProtocol { private fun receiveAndValidateTradeRequest(): SellerTradeInfo { progressTracker.currentStep = RECEIVING // Wait for a trade request to come in on our pre-provided session ID. - val maybeTradeRequest = receive(TRADE_TOPIC, sessionID) + val maybeTradeRequest = receive(sessionID) progressTracker.currentStep = VERIFYING maybeTradeRequest.validate { @@ -246,7 +248,7 @@ object TwoPartyTradeProtocol { // TODO: Protect against the seller terminating here and leaving us in the lurch without the final tx. - return sendAndReceive(TRADE_TOPIC, otherSide, theirSessionID, sessionID, stx).validate { it } + return sendAndReceive(otherSide, theirSessionID, sessionID, stx).validate { it } } private fun signWithOurKeys(cashSigningPubKeys: List, ptx: TransactionBuilder): SignedTransaction { diff --git a/core/src/main/kotlin/com/r3corda/core/protocols/ProtocolLogic.kt b/core/src/main/kotlin/com/r3corda/core/protocols/ProtocolLogic.kt index 25f500d7fa..c07cf36d86 100644 --- a/core/src/main/kotlin/com/r3corda/core/protocols/ProtocolLogic.kt +++ b/core/src/main/kotlin/com/r3corda/core/protocols/ProtocolLogic.kt @@ -25,6 +25,7 @@ import org.slf4j.Logger * it to the [subProtocol] method. It will return the result of that protocol when it completes. */ abstract class ProtocolLogic { + /** Reference to the [Fiber] instance that is the top level controller for the entire flow. */ lateinit var psm: ProtocolStateMachine<*> @@ -38,24 +39,29 @@ abstract class ProtocolLogic { */ val serviceHub: ServiceHub get() = psm.serviceHub + /** + * The topic to use when communicating with other parties. If more than one topic is required then use sub-protocols. + * Note that this is temporary until protocol sessions are properly implemented. + */ + protected abstract val topic: String + // Kotlin helpers that allow the use of generic types. - inline fun sendAndReceive(topic: String, - destination: Party, + inline fun sendAndReceive(destination: Party, sessionIDForSend: Long, sessionIDForReceive: Long, payload: Any): UntrustworthyData { return psm.sendAndReceive(topic, destination, sessionIDForSend, sessionIDForReceive, payload, T::class.java) } - inline fun receive(topic: String, sessionIDForReceive: Long): UntrustworthyData { - return receive(topic, sessionIDForReceive, T::class.java) + inline fun receive(sessionIDForReceive: Long): UntrustworthyData { + return receive(sessionIDForReceive, T::class.java) } - @Suspendable fun receive(topic: String, sessionIDForReceive: Long, clazz: Class): UntrustworthyData { - return psm.receive(topic, sessionIDForReceive, clazz) + @Suspendable fun receive(sessionIDForReceive: Long, receiveType: Class): UntrustworthyData { + return psm.receive(topic, sessionIDForReceive, receiveType) } - @Suspendable fun send(topic: String, destination: Party, sessionID: Long, payload: Any) { + @Suspendable fun send(destination: Party, sessionID: Long, payload: Any) { psm.send(topic, destination, sessionID, payload) } @@ -99,4 +105,5 @@ abstract class ProtocolLogic { /** This is where you fill out your business logic. */ @Suspendable abstract fun call(): T + } \ No newline at end of file diff --git a/core/src/main/kotlin/com/r3corda/protocols/FetchAttachmentsProtocol.kt b/core/src/main/kotlin/com/r3corda/protocols/FetchAttachmentsProtocol.kt index 993c078206..0e1c579b2b 100644 --- a/core/src/main/kotlin/com/r3corda/protocols/FetchAttachmentsProtocol.kt +++ b/core/src/main/kotlin/com/r3corda/protocols/FetchAttachmentsProtocol.kt @@ -13,13 +13,14 @@ import java.io.InputStream */ class FetchAttachmentsProtocol(requests: Set, otherSide: Party) : FetchDataProtocol(requests, otherSide) { + companion object { const val TOPIC = "platform.fetch.attachment" } - override fun load(txid: SecureHash): Attachment? = serviceHub.storageService.attachments.openAttachment(txid) + override val topic: String get() = TOPIC - override val queryTopic: String = TOPIC + override fun load(txid: SecureHash): Attachment? = serviceHub.storageService.attachments.openAttachment(txid) override fun convert(wire: ByteArray): Attachment { return object : Attachment { diff --git a/core/src/main/kotlin/com/r3corda/protocols/FetchDataProtocol.kt b/core/src/main/kotlin/com/r3corda/protocols/FetchDataProtocol.kt index ee4dc1d31c..f72aafbeb9 100644 --- a/core/src/main/kotlin/com/r3corda/protocols/FetchDataProtocol.kt +++ b/core/src/main/kotlin/com/r3corda/protocols/FetchDataProtocol.kt @@ -33,11 +33,9 @@ abstract class FetchDataProtocol( class HashNotFound(val requested: SecureHash) : BadAnswer() class DownloadedVsRequestedDataMismatch(val requested: SecureHash, val got: SecureHash) : BadAnswer() - class Request(val hashes: List, replyTo: Party, override val sessionID: Long) : AbstractRequestMessage(replyTo) + data class Request(val hashes: List, override val replyToParty: Party, override val sessionID: Long) : PartyRequestMessage data class Result(val fromDisk: List, val downloaded: List) - protected abstract val queryTopic: String - @Suspendable override fun call(): Result { // Load the items we have from disk and figure out which we're missing. @@ -51,7 +49,7 @@ abstract class FetchDataProtocol( val sid = random63BitValue() val fetchReq = Request(toFetch, serviceHub.storageService.myLegalIdentity, sid) // TODO: Support "large message" response streaming so response sizes are not limited by RAM. - val maybeItems = sendAndReceive>(queryTopic, otherSide, 0, sid, fetchReq) + val maybeItems = sendAndReceive>(otherSide, 0, sid, fetchReq) // Check for a buggy/malicious peer answering with something that we didn't ask for. val downloaded = validateFetchResponse(maybeItems, toFetch) maybeWriteToDisk(downloaded) diff --git a/core/src/main/kotlin/com/r3corda/protocols/FetchTransactionsProtocol.kt b/core/src/main/kotlin/com/r3corda/protocols/FetchTransactionsProtocol.kt index 667937c1be..69d7535ea7 100644 --- a/core/src/main/kotlin/com/r3corda/protocols/FetchTransactionsProtocol.kt +++ b/core/src/main/kotlin/com/r3corda/protocols/FetchTransactionsProtocol.kt @@ -14,10 +14,12 @@ import com.r3corda.core.crypto.SecureHash */ class FetchTransactionsProtocol(requests: Set, otherSide: Party) : FetchDataProtocol(requests, otherSide) { + companion object { const val TOPIC = "platform.fetch.tx" } + override val topic: String get() = TOPIC + override fun load(txid: SecureHash): SignedTransaction? = serviceHub.storageService.validatedTransactions.getTransaction(txid) - override val queryTopic: String = TOPIC } \ No newline at end of file diff --git a/core/src/main/kotlin/com/r3corda/protocols/NotaryProtocol.kt b/core/src/main/kotlin/com/r3corda/protocols/NotaryProtocol.kt index 1da1d4d674..2157ca8dbf 100644 --- a/core/src/main/kotlin/com/r3corda/protocols/NotaryProtocol.kt +++ b/core/src/main/kotlin/com/r3corda/protocols/NotaryProtocol.kt @@ -22,8 +22,8 @@ import com.r3corda.core.utilities.UntrustworthyData import java.security.PublicKey object NotaryProtocol { - val TOPIC = "platform.notary.request" - val TOPIC_INITIATE = "platform.notary.initiate" + + val TOPIC = "platform.notary" /** * A protocol to be used for obtaining a signature from a [NotaryService] ascertaining the transaction @@ -34,6 +34,7 @@ object NotaryProtocol { */ class Client(private val stx: SignedTransaction, override val progressTracker: ProgressTracker = Client.tracker()) : ProtocolLogic() { + companion object { object REQUESTING : ProgressTracker.Step("Requesting signature by Notary service") @@ -43,6 +44,8 @@ object NotaryProtocol { fun tracker() = ProgressTracker(REQUESTING, VALIDATING) } + override val topic: String get() = TOPIC + lateinit var notaryParty: Party @Suspendable @@ -54,10 +57,10 @@ object NotaryProtocol { val receiveSessionID = random63BitValue() val handshake = Handshake(serviceHub.storageService.myLegalIdentity, sendSessionID, receiveSessionID) - sendAndReceive(TOPIC_INITIATE, notaryParty, 0, receiveSessionID, handshake) + sendAndReceive(notaryParty, 0, receiveSessionID, handshake) val request = SignRequest(stx, serviceHub.storageService.myLegalIdentity) - val response = sendAndReceive(TOPIC, notaryParty, sendSessionID, receiveSessionID, request) + val response = sendAndReceive(notaryParty, sendSessionID, receiveSessionID, request) val notaryResult = validateResponse(response) return notaryResult.sig ?: throw NotaryException(notaryResult.error!!) @@ -113,27 +116,26 @@ object NotaryProtocol { val receiveSessionID: Long, val timestampChecker: TimestampChecker, val uniquenessProvider: UniquenessProvider) : ProtocolLogic() { + + override val topic: String get() = TOPIC + @Suspendable override fun call() { - val request = receive(TOPIC, receiveSessionID).validate { it } - val stx = request.tx + val (stx, reqIdentity) = receive(receiveSessionID).validate { it } val wtx = stx.tx - val reqIdentity = request.callerIdentity - val result: Result - try { + val result = try { validateTimestamp(wtx) beforeCommit(stx, reqIdentity) commitInputStates(wtx, reqIdentity) val sig = sign(stx.txBits) - result = Result.noError(sig) - + Result.noError(sig) } catch(e: NotaryException) { - result = Result.withError(e.error) + Result.withError(e.error) } - send(TOPIC, otherSide, sendSessionID, result) + send(otherSide, sendSessionID, result) } private fun validateTimestamp(tx: WireTransaction) { @@ -178,14 +180,13 @@ object NotaryProtocol { } } - class Handshake( - replyTo: Party, + data class Handshake( + override val replyToParty: Party, val sendSessionID: Long, - override val sessionID: Long) : AbstractRequestMessage(replyTo) + override val sessionID: Long) : PartyRequestMessage /** TODO: The caller must authenticate instead of just specifying its identity */ - class SignRequest(val tx: SignedTransaction, - val callerIdentity: Party) + data class SignRequest(val tx: SignedTransaction, val callerIdentity: Party) data class Result private constructor(val sig: DigitalSignature.LegallyIdentifiable?, val error: NotaryError?) { companion object { diff --git a/core/src/main/kotlin/com/r3corda/protocols/RatesFixProtocol.kt b/core/src/main/kotlin/com/r3corda/protocols/RatesFixProtocol.kt index fd1378f548..d61ad3d968 100644 --- a/core/src/main/kotlin/com/r3corda/protocols/RatesFixProtocol.kt +++ b/core/src/main/kotlin/com/r3corda/protocols/RatesFixProtocol.kt @@ -33,10 +33,9 @@ open class RatesFixProtocol(protected val tx: TransactionBuilder, private val rateTolerance: BigDecimal, private val timeOut: Duration, override val progressTracker: ProgressTracker = RatesFixProtocol.tracker(fixOf.name)) : ProtocolLogic() { + companion object { val TOPIC = "platform.rates.interest.fix" - val TOPIC_SIGN = TOPIC + ".sign" - val TOPIC_QUERY = TOPIC + ".query" class QUERYING(val name: String) : ProgressTracker.Step("Querying oracle for $name interest rate") object WORKING : ProgressTracker.Step("Working with data returned by oracle") @@ -45,10 +44,12 @@ open class RatesFixProtocol(protected val tx: TransactionBuilder, fun tracker(fixName: String) = ProgressTracker(QUERYING(fixName), WORKING, SIGNING) } + override val topic: String get() = TOPIC + class FixOutOfRange(val byAmount: BigDecimal) : Exception() - class QueryRequest(val queries: List, replyTo: Party, override val sessionID: Long, val deadline: Instant) : AbstractRequestMessage(replyTo) - class SignRequest(val tx: WireTransaction, replyTo: Party, override val sessionID: Long) : AbstractRequestMessage(replyTo) + data class QueryRequest(val queries: List, override val replyToParty: Party, override val sessionID: Long, val deadline: Instant) : PartyRequestMessage + data class SignRequest(val tx: WireTransaction, override val replyToParty: Party, override val sessionID: Long) : PartyRequestMessage @Suspendable override fun call() { @@ -79,11 +80,11 @@ open class RatesFixProtocol(protected val tx: TransactionBuilder, } @Suspendable - fun sign(): DigitalSignature.LegallyIdentifiable { + private fun sign(): DigitalSignature.LegallyIdentifiable { val sessionID = random63BitValue() val wtx = tx.toWireTransaction() val req = SignRequest(wtx, serviceHub.storageService.myLegalIdentity, sessionID) - val resp = sendAndReceive(TOPIC_SIGN, oracle, 0, sessionID, req) + val resp = sendAndReceive(oracle, 0, sessionID, req) return resp.validate { sig -> check(sig.signer == oracle) @@ -93,12 +94,12 @@ open class RatesFixProtocol(protected val tx: TransactionBuilder, } @Suspendable - fun query(): Fix { + private fun query(): Fix { val sessionID = random63BitValue() val deadline = suggestInterestRateAnnouncementTimeWindow(fixOf.name, oracle.name, fixOf.forDay).end val req = QueryRequest(listOf(fixOf), serviceHub.storageService.myLegalIdentity, sessionID, deadline) // TODO: add deadline to receive - val resp = sendAndReceive>(TOPIC_QUERY, oracle, 0, sessionID, req) + val resp = sendAndReceive>(oracle, 0, sessionID, req) return resp.validate { val fix = it.first() diff --git a/core/src/main/kotlin/com/r3corda/protocols/ResolveTransactionsProtocol.kt b/core/src/main/kotlin/com/r3corda/protocols/ResolveTransactionsProtocol.kt index f6bc21fd56..2e09d2c348 100644 --- a/core/src/main/kotlin/com/r3corda/protocols/ResolveTransactionsProtocol.kt +++ b/core/src/main/kotlin/com/r3corda/protocols/ResolveTransactionsProtocol.kt @@ -70,6 +70,8 @@ class ResolveTransactionsProtocol(private val txHashes: Set, serviceHub.recordTransactions(downloadedSignedTxns) } + override val topic: String get() = throw UnsupportedOperationException() + @Suspendable private fun fetchDependenciesAndCheckSignatures(depsToCheck: Set, toVerify: HashSet, diff --git a/core/src/main/kotlin/com/r3corda/protocols/ServiceRequestMessage.kt b/core/src/main/kotlin/com/r3corda/protocols/ServiceRequestMessage.kt index 6f6fbb21ee..3f878b3ce7 100644 --- a/core/src/main/kotlin/com/r3corda/protocols/ServiceRequestMessage.kt +++ b/core/src/main/kotlin/com/r3corda/protocols/ServiceRequestMessage.kt @@ -6,14 +6,17 @@ import com.r3corda.core.node.services.NetworkMapCache /** * Abstract superclass for request messages sent to services, which includes common - * fields such as replyTo and replyToTopic. + * fields such as replyTo and sessionID. */ interface ServiceRequestMessage { val sessionID: Long fun getReplyTo(networkMapCache: NetworkMapCache): MessageRecipients } -abstract class AbstractRequestMessage(val replyToParty: Party): ServiceRequestMessage { +interface PartyRequestMessage : ServiceRequestMessage { + + val replyToParty: Party + override fun getReplyTo(networkMapCache: NetworkMapCache): MessageRecipients { return networkMapCache.partyNodes.single { it.identity == replyToParty }.address } diff --git a/core/src/main/kotlin/com/r3corda/protocols/TwoPartyDealProtocol.kt b/core/src/main/kotlin/com/r3corda/protocols/TwoPartyDealProtocol.kt index f716dfa314..b81cefa4f7 100644 --- a/core/src/main/kotlin/com/r3corda/protocols/TwoPartyDealProtocol.kt +++ b/core/src/main/kotlin/com/r3corda/protocols/TwoPartyDealProtocol.kt @@ -30,7 +30,10 @@ import java.time.Duration * */ object TwoPartyDealProtocol { + val DEAL_TOPIC = "platform.deal" + /** This topic exists purely for [FixingSessionInitiation] to be sent from [FixingRoleDecider] to [FixingSessionInitiationHandler] */ + val FIX_INITIATE_TOPIC = "platform.fix.initiate" class DealMismatchException(val expectedDeal: ContractState, val actualDeal: ContractState) : Exception() { override fun toString() = "The submitted deal didn't match the expected: $expectedDeal vs $actualDeal" @@ -69,6 +72,8 @@ object TwoPartyDealProtocol { fun tracker() = ProgressTracker(AWAITING_PROPOSAL, VERIFYING, SIGNING, NOTARY, SENDING_SIGS, RECORDING, COPYING_TO_REGULATOR) } + override val topic: String get() = DEAL_TOPIC + abstract val payload: U abstract val notaryNode: NodeInfo abstract val otherSide: Party @@ -83,7 +88,7 @@ object TwoPartyDealProtocol { // Make the first message we'll send to kick off the protocol. val hello = Handshake(payload, myKeyPair.public, sessionID) - val maybeSTX = sendAndReceive(DEAL_TOPIC, otherSide, otherSessionID, sessionID, hello) + val maybeSTX = sendAndReceive(otherSide, otherSessionID, sessionID, hello) return maybeSTX } @@ -152,7 +157,7 @@ object TwoPartyDealProtocol { // Copy the transaction to every regulator in the network. This is obviously completely bogus, it's // just for demo purposes. for (regulator in regulators) { - send("regulator.all.seeing.eye", regulator.identity, 0, fullySigned) + send(regulator.identity, 0, fullySigned) } } @@ -178,7 +183,7 @@ object TwoPartyDealProtocol { logger.trace { "Built finished transaction, sending back to other party!" } - send(DEAL_TOPIC, otherSide, otherSessionID, SignaturesFromPrimary(ourSignature, notarySignature)) + send(otherSide, otherSessionID, SignaturesFromPrimary(ourSignature, notarySignature)) return fullySigned } } @@ -202,6 +207,8 @@ object TwoPartyDealProtocol { fun tracker() = ProgressTracker(RECEIVING, VERIFYING, SIGNING, SWAPPING_SIGNATURES, RECORDING) } + override val topic: String get() = DEAL_TOPIC + abstract val otherSide: Party abstract val sessionID: Long @@ -234,7 +241,7 @@ object TwoPartyDealProtocol { private fun receiveAndValidateHandshake(): Handshake { progressTracker.currentStep = RECEIVING // Wait for a trade request to come in on our pre-provided session ID. - val handshake = receive>(DEAL_TOPIC, sessionID) + val handshake = receive>(sessionID) progressTracker.currentStep = VERIFYING handshake.validate { @@ -249,7 +256,7 @@ object TwoPartyDealProtocol { // TODO: Protect against the seller terminating here and leaving us in the lurch without the final tx. - return sendAndReceive(DEAL_TOPIC, otherSide, theirSessionID, sessionID, stx).validate { it } + return sendAndReceive(otherSide, theirSessionID, sessionID, stx).validate { it } } private fun signWithOurKeys(signingPubKeys: List, ptx: TransactionBuilder): SignedTransaction { @@ -424,8 +431,6 @@ object TwoPartyDealProtocol { serviceHub.networkMapCache.notaryNodes.filter { it.identity == dealToFix.state.notary }.single() } - /** This topic exists purely for [FixingSessionInitiation] to be sent from [FixingRoleDecider] to [FixingSessionInitiationHandler] */ - val FIX_INITIATE_TOPIC = "platform.fix.initiate" /** Used to set up the session between [Floater] and [Fixer] */ data class FixingSessionInitiation(val sessionID: Long, val party: Party, val sender: Party, val timeout: Duration) @@ -439,13 +444,18 @@ object TwoPartyDealProtocol { * * TODO: Replace [FixingSessionInitiation] and [FixingSessionInitiationHandler] with generic session initiation logic once it exists. */ - class FixingRoleDecider(val ref: StateRef, val timeout: Duration, override val progressTracker: ProgressTracker = tracker(ref.toString())) : ProtocolLogic() { + class FixingRoleDecider(val ref: StateRef, + val timeout: Duration, + override val progressTracker: ProgressTracker = tracker(ref.toString())) : ProtocolLogic() { + companion object { class LOADING(ref: String) : ProgressTracker.Step("Loading state $ref to decide fixing role") fun tracker(ref: String) = ProgressTracker(LOADING(ref)) } + override val topic: String get() = FIX_INITIATE_TOPIC + @Suspendable override fun call(): Unit { progressTracker.nextStep() @@ -458,7 +468,7 @@ object TwoPartyDealProtocol { val initation = FixingSessionInitiation(sessionID, sortedParties[0], serviceHub.storageService.myLegalIdentity, timeout) // Send initiation to other side to launch one side of the fixing protocol (the Fixer). - send(FIX_INITIATE_TOPIC, sortedParties[1], 0, initation) + send(sortedParties[1], 0, initation) // Then start the other side of the fixing protocol. val protocol = Floater(ref, sessionID) @@ -466,4 +476,5 @@ object TwoPartyDealProtocol { } } } + } \ No newline at end of file diff --git a/core/src/main/kotlin/protocols/AbstractStateReplacementProtocol.kt b/core/src/main/kotlin/protocols/AbstractStateReplacementProtocol.kt index ba302424d9..1aafd6fed8 100644 --- a/core/src/main/kotlin/protocols/AbstractStateReplacementProtocol.kt +++ b/core/src/main/kotlin/protocols/AbstractStateReplacementProtocol.kt @@ -10,8 +10,8 @@ import com.r3corda.core.node.NodeInfo import com.r3corda.core.protocols.ProtocolLogic import com.r3corda.core.random63BitValue import com.r3corda.core.utilities.ProgressTracker -import com.r3corda.protocols.AbstractRequestMessage import com.r3corda.protocols.NotaryProtocol +import com.r3corda.protocols.PartyRequestMessage import com.r3corda.protocols.ResolveTransactionsProtocol import java.security.PublicKey @@ -32,9 +32,9 @@ abstract class AbstractStateReplacementProtocol { val stx: SignedTransaction } - class Handshake(val sessionIdForSend: Long, - replyTo: Party, - override val sessionID: Long) : AbstractRequestMessage(replyTo) + data class Handshake(val sessionIdForSend: Long, + override val replyToParty: Party, + override val sessionID: Long) : PartyRequestMessage abstract class Instigator(val originalState: StateAndRef, val modification: T, @@ -48,9 +48,6 @@ abstract class AbstractStateReplacementProtocol { fun tracker() = ProgressTracker(SIGNING, NOTARY) } - abstract val TOPIC_CHANGE: String - abstract val TOPIC_INITIATE: String - @Suspendable override fun call(): StateAndRef { val (stx, participants) = assembleTx() @@ -88,7 +85,7 @@ abstract class AbstractStateReplacementProtocol { } val allSignatures = participantSignatures + getNotarySignature(stx) - sessions.forEach { send(TOPIC_CHANGE, it.key.identity, it.value, allSignatures) } + sessions.forEach { send(it.key.identity, it.value, allSignatures) } return allSignatures } @@ -99,9 +96,9 @@ abstract class AbstractStateReplacementProtocol { val proposal = assembleProposal(originalState.ref, modification, stx) val handshake = Handshake(sessionIdForSend, serviceHub.storageService.myLegalIdentity, sessionIdForReceive) - sendAndReceive(TOPIC_INITIATE, node.identity, 0, sessionIdForReceive, handshake) + sendAndReceive(node.identity, 0, sessionIdForReceive, handshake) - val response = sendAndReceive(TOPIC_CHANGE, node.identity, sessionIdForSend, sessionIdForReceive, proposal) + val response = sendAndReceive(node.identity, sessionIdForSend, sessionIdForReceive, proposal) val participantSignature = response.validate { if (it.sig == null) throw StateReplacementException(it.error!!) else { @@ -136,13 +133,10 @@ abstract class AbstractStateReplacementProtocol { fun tracker() = ProgressTracker(VERIFYING, APPROVING, REJECTING) } - abstract val TOPIC_CHANGE: String - abstract val TOPIC_INITIATE: String - @Suspendable override fun call() { progressTracker.currentStep = VERIFYING - val proposal = receive>(TOPIC_CHANGE, sessionIdForReceive).validate { it } + val proposal = receive>(sessionIdForReceive).validate { it } try { verifyProposal(proposal) @@ -168,7 +162,7 @@ abstract class AbstractStateReplacementProtocol { val mySignature = sign(stx) val response = Result.noError(mySignature) - val swapSignatures = sendAndReceive>(TOPIC_CHANGE, otherSide, sessionIdForSend, sessionIdForReceive, response) + val swapSignatures = sendAndReceive>(otherSide, sessionIdForSend, sessionIdForReceive, response) val allSignatures = swapSignatures.validate { signatures -> signatures.forEach { it.verifyWithECDSA(stx.txBits) } @@ -184,7 +178,7 @@ abstract class AbstractStateReplacementProtocol { private fun reject(e: StateReplacementRefused) { progressTracker.currentStep = REJECTING val response = Result.withError(e) - send(TOPIC_CHANGE, otherSide, sessionIdForSend, response) + send(otherSide, sessionIdForSend, response) } /** diff --git a/core/src/main/kotlin/protocols/NotaryChangeProtocol.kt b/core/src/main/kotlin/protocols/NotaryChangeProtocol.kt index f4427aee15..8d587c71fb 100644 --- a/core/src/main/kotlin/protocols/NotaryChangeProtocol.kt +++ b/core/src/main/kotlin/protocols/NotaryChangeProtocol.kt @@ -16,8 +16,8 @@ import java.security.PublicKey * use the new updated state for future transactions. */ object NotaryChangeProtocol: AbstractStateReplacementProtocol() { - val TOPIC_INITIATE = "platform.notary.change.initiate" - val TOPIC_CHANGE = "platform.notary.change.execute" + + val TOPIC = "platform.notary.change" data class Proposal(override val stateRef: StateRef, override val modification: Party, @@ -28,10 +28,7 @@ object NotaryChangeProtocol: AbstractStateReplacementProtocol() { progressTracker: ProgressTracker = tracker()) : AbstractStateReplacementProtocol.Instigator(originalState, newNotary, progressTracker) { - override val TOPIC_CHANGE: String - get() = NotaryChangeProtocol.TOPIC_CHANGE - override val TOPIC_INITIATE: String - get() = NotaryChangeProtocol.TOPIC_INITIATE + override val topic: String get() = TOPIC override fun assembleProposal(stateRef: StateRef, modification: Party, stx: SignedTransaction): AbstractStateReplacementProtocol.Proposal = NotaryChangeProtocol.Proposal(stateRef, modification, stx) @@ -53,10 +50,8 @@ object NotaryChangeProtocol: AbstractStateReplacementProtocol() { sessionIdForReceive: Long, override val progressTracker: ProgressTracker = tracker()) : AbstractStateReplacementProtocol.Acceptor(otherSide, sessionIdForSend, sessionIdForReceive) { - override val TOPIC_CHANGE: String - get() = NotaryChangeProtocol.TOPIC_CHANGE - override val TOPIC_INITIATE: String - get() = NotaryChangeProtocol.TOPIC_INITIATE + + override val topic: String get() = TOPIC /** * Check the notary change proposal. diff --git a/core/src/test/java/com/r3corda/core/protocols/ProtocolLogicRefFromJavaTest.java b/core/src/test/java/com/r3corda/core/protocols/ProtocolLogicRefFromJavaTest.java index 4e7a3a707f..66466d3393 100644 --- a/core/src/test/java/com/r3corda/core/protocols/ProtocolLogicRefFromJavaTest.java +++ b/core/src/test/java/com/r3corda/core/protocols/ProtocolLogicRefFromJavaTest.java @@ -2,6 +2,7 @@ package com.r3corda.core.protocols; import com.google.common.collect.Sets; +import org.jetbrains.annotations.NotNull; import org.junit.Test; public class ProtocolLogicRefFromJavaTest { @@ -15,6 +16,12 @@ public class ProtocolLogicRefFromJavaTest { public Void call() { return null; } + + @NotNull + @Override + protected String getTopic() { + throw new UnsupportedOperationException(); + } } public static class JavaNoArgProtocolLogic extends ProtocolLogic { @@ -26,6 +33,12 @@ public class ProtocolLogicRefFromJavaTest { public Void call() { return null; } + + @NotNull + @Override + protected String getTopic() { + throw new UnsupportedOperationException(); + } } @Test diff --git a/core/src/test/kotlin/com/r3corda/core/protocols/ProtocolLogicRefTest.kt b/core/src/test/kotlin/com/r3corda/core/protocols/ProtocolLogicRefTest.kt index a3ad42d0de..bcede610b1 100644 --- a/core/src/test/kotlin/com/r3corda/core/protocols/ProtocolLogicRefTest.kt +++ b/core/src/test/kotlin/com/r3corda/core/protocols/ProtocolLogicRefTest.kt @@ -18,17 +18,21 @@ class ProtocolLogicRefTest { override fun call(): Unit { } + + override val topic: String get() = throw UnsupportedOperationException() } class KotlinNoArgProtocolLogic : ProtocolLogic() { override fun call(): Unit { } + override val topic: String get() = throw UnsupportedOperationException() } @Suppress("UNUSED_PARAMETER") // We will never use A or b class NotWhiteListedKotlinProtocolLogic(A: Int, b: String) : ProtocolLogic() { override fun call(): Unit { } + override val topic: String get() = throw UnsupportedOperationException() } lateinit var factory: ProtocolLogicRefFactory diff --git a/node/src/main/kotlin/com/r3corda/node/internal/testing/TradeSimulation.kt b/node/src/main/kotlin/com/r3corda/node/internal/testing/TradeSimulation.kt index f86236517e..a28baef28b 100644 --- a/node/src/main/kotlin/com/r3corda/node/internal/testing/TradeSimulation.kt +++ b/node/src/main/kotlin/com/r3corda/node/internal/testing/TradeSimulation.kt @@ -61,8 +61,8 @@ class TradeSimulation(runAsync: Boolean, latencyInjector: InMemoryMessagingNetwo showConsensusFor(listOf(buyer, seller, notary)) showProgressFor(listOf(buyer, seller)) - val buyerFuture = buyer.smm.add("bank.$buyerBankIndex.${TwoPartyTradeProtocol.TRADE_TOPIC}.buyer", buyerProtocol) - val sellerFuture = seller.smm.add("bank.$sellerBankIndex.${TwoPartyTradeProtocol.TRADE_TOPIC}.seller", sellerProtocol) + val buyerFuture = buyer.smm.add("bank.$buyerBankIndex.${TwoPartyTradeProtocol.TOPIC}.buyer", buyerProtocol) + val sellerFuture = seller.smm.add("bank.$sellerBankIndex.${TwoPartyTradeProtocol.TOPIC}.seller", sellerProtocol) return Futures.successfulAsList(buyerFuture, sellerFuture) } diff --git a/node/src/main/kotlin/com/r3corda/node/services/NotaryChangeService.kt b/node/src/main/kotlin/com/r3corda/node/services/NotaryChangeService.kt index e1b88f1c36..8931ceedeb 100644 --- a/node/src/main/kotlin/com/r3corda/node/services/NotaryChangeService.kt +++ b/node/src/main/kotlin/com/r3corda/node/services/NotaryChangeService.kt @@ -14,7 +14,7 @@ import protocols.NotaryChangeProtocol */ class NotaryChangeService(net: MessagingService, val smm: StateMachineManager, networkMapCache: NetworkMapCache) : AbstractNodeService(net, networkMapCache) { init { - addMessageHandler(NotaryChangeProtocol.TOPIC_INITIATE, + addMessageHandler(NotaryChangeProtocol.TOPIC, { req: AbstractStateReplacementProtocol.Handshake -> handleChangeNotaryRequest(req) } ) } @@ -24,7 +24,7 @@ class NotaryChangeService(net: MessagingService, val smm: StateMachineManager, n req.replyToParty, req.sessionID, req.sessionIdForSend) - smm.add(NotaryChangeProtocol.TOPIC_CHANGE, protocol) + smm.add(NotaryChangeProtocol.TOPIC, protocol) return Ack } } diff --git a/node/src/main/kotlin/com/r3corda/node/services/clientapi/NodeInterestRates.kt b/node/src/main/kotlin/com/r3corda/node/services/clientapi/NodeInterestRates.kt index f4cd859470..94d4c9dbeb 100644 --- a/node/src/main/kotlin/com/r3corda/node/services/clientapi/NodeInterestRates.kt +++ b/node/src/main/kotlin/com/r3corda/node/services/clientapi/NodeInterestRates.kt @@ -17,6 +17,7 @@ import com.r3corda.node.services.api.AbstractNodeService import com.r3corda.node.services.api.AcceptsFileUpload import com.r3corda.node.utilities.FiberBox import com.r3corda.protocols.RatesFixProtocol +import com.r3corda.protocols.ServiceRequestMessage import org.slf4j.LoggerFactory import java.io.InputStream import java.math.BigDecimal @@ -48,32 +49,36 @@ object NodeInterestRates { private val logger = LoggerFactory.getLogger(Service::class.java) init { - addMessageHandler(RatesFixProtocol.TOPIC_SIGN, - { req: RatesFixProtocol.SignRequest -> oracle.sign(req.tx) }, - { message, e -> logger.error("Exception during interest rate oracle request processing", e) } - ) - addMessageHandler(RatesFixProtocol.TOPIC_QUERY, - { req: RatesFixProtocol.QueryRequest -> - /** - * We put this into a protocol so that if it blocks waiting for the interest rate to become - * available, we a) don't block this thread and b) allow the fact we are waiting - * to be persisted/checkpointed. - * Interest rates become available when they are uploaded via the web as per [DataUploadServlet], - * if they haven't already been uploaded that way. - */ - node.smm.add("fixing", FixQueryHandler(this, req)) - return@addMessageHandler + addMessageHandler(RatesFixProtocol.TOPIC, + { req: ServiceRequestMessage -> + if (req is RatesFixProtocol.SignRequest) { + oracle.sign(req.tx) + } + else { + /** + * We put this into a protocol so that if it blocks waiting for the interest rate to become + * available, we a) don't block this thread and b) allow the fact we are waiting + * to be persisted/checkpointed. + * Interest rates become available when they are uploaded via the web as per [DataUploadServlet], + * if they haven't already been uploaded that way. + */ + node.smm.add("fixing", FixQueryHandler(this, req as RatesFixProtocol.QueryRequest)) + Unit + } }, { message, e -> logger.error("Exception during interest rate oracle request processing", e) } ) } - private class FixQueryHandler(val service: Service, val request: RatesFixProtocol.QueryRequest) : ProtocolLogic() { + private class FixQueryHandler(val service: Service, + val request: RatesFixProtocol.QueryRequest) : ProtocolLogic() { + companion object { object RECEIVED : ProgressTracker.Step("Received fix request") - object SENDING : ProgressTracker.Step("Sending fix response") } + + override val topic: String get() = RatesFixProtocol.TOPIC override val progressTracker = ProgressTracker(RECEIVED, SENDING) init { @@ -84,9 +89,8 @@ object NodeInterestRates { override fun call(): Unit { val answers = service.oracle.query(request.queries, request.deadline) progressTracker.currentStep = SENDING - send("${RatesFixProtocol.TOPIC}.query", request.replyToParty, request.sessionID, answers) + send(request.replyToParty, request.sessionID, answers) } - } // File upload support diff --git a/node/src/main/kotlin/com/r3corda/node/services/statemachine/StateMachineManager.kt b/node/src/main/kotlin/com/r3corda/node/services/statemachine/StateMachineManager.kt index dfb752cfd0..affe832ce1 100644 --- a/node/src/main/kotlin/com/r3corda/node/services/statemachine/StateMachineManager.kt +++ b/node/src/main/kotlin/com/r3corda/node/services/statemachine/StateMachineManager.kt @@ -253,8 +253,9 @@ class StateMachineManager(val serviceHub: ServiceHubInternal, tokenizableService request.payload?.let { val topic = "${request.topic}.${request.sessionIDForSend}" psm.logger.trace { "Sending message of type ${it.javaClass.name} using topic $topic to ${request.destination} (${it.toString().abbreviate(50)})" } - val address = serviceHub.networkMapCache.getNodeByLegalName(request.destination!!.name)!!.address - serviceHub.networkService.send(topic, it, address) + val node = serviceHub.networkMapCache.getNodeByLegalName(request.destination!!.name) + requireNotNull(node) { "Don't know about ${request.destination}" } + serviceHub.networkService.send(topic, it, node!!.address) } if (request is FiberRequest.NotExpectingResponse) { // We sent a message, but don't expect a response, so re-enter the continuation to let it keep going. diff --git a/node/src/main/kotlin/com/r3corda/node/services/transactions/NotaryService.kt b/node/src/main/kotlin/com/r3corda/node/services/transactions/NotaryService.kt index aa69394e70..6287861bac 100644 --- a/node/src/main/kotlin/com/r3corda/node/services/transactions/NotaryService.kt +++ b/node/src/main/kotlin/com/r3corda/node/services/transactions/NotaryService.kt @@ -32,7 +32,7 @@ abstract class NotaryService(val smm: StateMachineManager, abstract val protocolFactory: NotaryProtocol.Factory init { - addMessageHandler(NotaryProtocol.TOPIC_INITIATE, + addMessageHandler(NotaryProtocol.TOPIC, { req: NotaryProtocol.Handshake -> processRequest(req) } ) } diff --git a/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt b/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt index 3f3629008b..1b8de5b263 100644 --- a/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt +++ b/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt @@ -58,14 +58,14 @@ class TwoPartyTradeProtocolTests { otherSide: Party, assetToSell: StateAndRef, price: Amount>, myKeyPair: KeyPair, buyerSessionID: Long): ListenableFuture { val seller = TwoPartyTradeProtocol.Seller(otherSide, notary, assetToSell, price, myKeyPair, buyerSessionID) - return smm.add("${TwoPartyTradeProtocol.TRADE_TOPIC}.seller", seller) + return smm.add("${TwoPartyTradeProtocol.TOPIC}.seller", seller) } private fun runBuyer(smm: StateMachineManager, notaryNode: NodeInfo, otherSide: Party, acceptablePrice: Amount>, typeToBuy: Class, sessionID: Long): ListenableFuture { val buyer = TwoPartyTradeProtocol.Buyer(otherSide, notaryNode.identity, acceptablePrice, typeToBuy, sessionID) - return smm.add("${TwoPartyTradeProtocol.TRADE_TOPIC}.buyer", buyer) + return smm.add("${TwoPartyTradeProtocol.TOPIC}.buyer", buyer) } @Before diff --git a/node/src/test/kotlin/com/r3corda/node/services/InMemoryNetworkMapServiceTest.kt b/node/src/test/kotlin/com/r3corda/node/services/InMemoryNetworkMapServiceTest.kt index 29c1221d98..5f55b8906e 100644 --- a/node/src/test/kotlin/com/r3corda/node/services/InMemoryNetworkMapServiceTest.kt +++ b/node/src/test/kotlin/com/r3corda/node/services/InMemoryNetworkMapServiceTest.kt @@ -68,50 +68,45 @@ class InMemoryNetworkMapServiceTest { assert(!service.processRegistrationChangeRequest(NetworkMapService.RegistrationRequest(removeWireChange, mapServiceNode.info.address, Long.MIN_VALUE)).success) } - class TestAcknowledgePSM(val server: NodeInfo, val hash: SecureHash) - : ProtocolLogic() { + class TestAcknowledgePSM(val server: NodeInfo, val hash: SecureHash) : ProtocolLogic() { + override val topic: String get() = NetworkMapService.PUSH_ACK_PROTOCOL_TOPIC @Suspendable override fun call() { val req = NetworkMapService.UpdateAcknowledge(hash, serviceHub.networkService.myAddress) - send(NetworkMapService.PUSH_ACK_PROTOCOL_TOPIC, server.identity, 0, req) + send(server.identity, 0, req) } } class TestFetchPSM(val server: NodeInfo, val subscribe: Boolean, val ifChangedSinceVersion: Int? = null) : ProtocolLogic?>() { + override val topic: String get() = NetworkMapService.FETCH_PROTOCOL_TOPIC @Suspendable override fun call(): Collection? { val sessionID = random63BitValue() val req = NetworkMapService.FetchMapRequest(subscribe, ifChangedSinceVersion, serviceHub.networkService.myAddress, sessionID) - return sendAndReceive( - NetworkMapService.FETCH_PROTOCOL_TOPIC, server.identity, 0, sessionID, req) - .validate { it.nodes } + return sendAndReceive(server.identity, 0, sessionID, req).validate { it.nodes } } } class TestRegisterPSM(val server: NodeInfo, val reg: NodeRegistration, val privateKey: PrivateKey) : ProtocolLogic() { + override val topic: String get() = NetworkMapService.REGISTER_PROTOCOL_TOPIC @Suspendable override fun call(): NetworkMapService.RegistrationResponse { val sessionID = random63BitValue() val req = NetworkMapService.RegistrationRequest(reg.toWire(privateKey), serviceHub.networkService.myAddress, sessionID) - - return sendAndReceive( - NetworkMapService.REGISTER_PROTOCOL_TOPIC, server.identity, 0, sessionID, req) - .validate { it } + return sendAndReceive(server.identity, 0, sessionID, req).validate { it } } } class TestSubscribePSM(val server: NodeInfo, val subscribe: Boolean) : ProtocolLogic() { + override val topic: String get() = NetworkMapService.SUBSCRIPTION_PROTOCOL_TOPIC @Suspendable override fun call(): NetworkMapService.SubscribeResponse { val sessionID = random63BitValue() val req = NetworkMapService.SubscribeRequest(subscribe, serviceHub.networkService.myAddress, sessionID) - - return sendAndReceive( - NetworkMapService.SUBSCRIPTION_PROTOCOL_TOPIC, server.identity, 0, sessionID, req) - .validate { it } + return sendAndReceive(server.identity, 0, sessionID, req).validate { it } } } diff --git a/node/src/test/kotlin/com/r3corda/node/services/NodeSchedulerServiceTest.kt b/node/src/test/kotlin/com/r3corda/node/services/NodeSchedulerServiceTest.kt index 20a7d14edb..566d2aff3f 100644 --- a/node/src/test/kotlin/com/r3corda/node/services/NodeSchedulerServiceTest.kt +++ b/node/src/test/kotlin/com/r3corda/node/services/NodeSchedulerServiceTest.kt @@ -97,6 +97,7 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() { (serviceHub as TestReference).testReference.calls += increment (serviceHub as TestReference).testReference.countDown.countDown() } + override val topic: String get() = throw UnsupportedOperationException() } class Command : TypeOnlyCommandData() diff --git a/node/src/test/kotlin/com/r3corda/node/services/statemachine/StateMachineManagerTests.kt b/node/src/test/kotlin/com/r3corda/node/services/statemachine/StateMachineManagerTests.kt index 8877aeb059..5a7dd02003 100644 --- a/node/src/test/kotlin/com/r3corda/node/services/statemachine/StateMachineManagerTests.kt +++ b/node/src/test/kotlin/com/r3corda/node/services/statemachine/StateMachineManagerTests.kt @@ -59,6 +59,8 @@ class StateMachineManagerTests { protocolStarted = true Fiber.park() } + + override val topic: String get() = throw UnsupportedOperationException() } @@ -68,6 +70,8 @@ class StateMachineManagerTests { @Suspendable override fun call() {} + + override val topic: String get() = throw UnsupportedOperationException() } diff --git a/node/src/test/kotlin/node/services/NotaryChangeTests.kt b/node/src/test/kotlin/node/services/NotaryChangeTests.kt index d89eae2ad5..d81c674800 100644 --- a/node/src/test/kotlin/node/services/NotaryChangeTests.kt +++ b/node/src/test/kotlin/node/services/NotaryChangeTests.kt @@ -11,10 +11,10 @@ import com.r3corda.node.services.network.NetworkMapService import com.r3corda.node.services.transactions.SimpleNotaryService import org.junit.Before import org.junit.Test -import protocols.StateReplacementException -import protocols.StateReplacementRefused import protocols.NotaryChangeProtocol import protocols.NotaryChangeProtocol.Instigator +import protocols.StateReplacementException +import protocols.StateReplacementRefused import java.util.concurrent.ExecutionException import kotlin.test.assertEquals import kotlin.test.assertFailsWith @@ -46,7 +46,7 @@ class NotaryChangeTests { val state = issueState(clientNodeA) val newNotary = newNotaryNode.info.identity val protocol = Instigator(state, newNotary) - val future = clientNodeA.smm.add(NotaryChangeProtocol.TOPIC_CHANGE, protocol) + val future = clientNodeA.smm.add(NotaryChangeProtocol.TOPIC, protocol) net.runNetwork() @@ -59,7 +59,7 @@ class NotaryChangeTests { val state = issueMultiPartyState(clientNodeA, clientNodeB) val newNotary = newNotaryNode.info.identity val protocol = Instigator(state, newNotary) - val future = clientNodeA.smm.add(NotaryChangeProtocol.TOPIC_CHANGE, protocol) + val future = clientNodeA.smm.add(NotaryChangeProtocol.TOPIC, protocol) net.runNetwork() @@ -75,7 +75,7 @@ class NotaryChangeTests { val state = issueMultiPartyState(clientNodeA, clientNodeB) val newEvilNotary = Party("Evil Notary", generateKeyPair().public) val protocol = Instigator(state, newEvilNotary) - val future = clientNodeA.smm.add(NotaryChangeProtocol.TOPIC_CHANGE, protocol) + val future = clientNodeA.smm.add(NotaryChangeProtocol.TOPIC, protocol) net.runNetwork() diff --git a/src/main/kotlin/com/r3corda/demos/TraderDemo.kt b/src/main/kotlin/com/r3corda/demos/TraderDemo.kt index 0d29284155..c1e6fce49c 100644 --- a/src/main/kotlin/com/r3corda/demos/TraderDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/TraderDemo.kt @@ -36,6 +36,7 @@ import java.nio.file.Paths import java.security.PublicKey import java.time.Instant import java.util.* +import java.util.concurrent.CountDownLatch import kotlin.system.exitProcess import kotlin.test.assertEquals @@ -202,77 +203,64 @@ private fun runBuyer(node: Node, amount: Amount>) { it.storePath } - val future = if (node.isPreviousCheckpointsPresent) { - node.smm.findStateMachines(TraderDemoProtocolBuyer::class.java).single().second - } else { + // Self issue some cash. + // + // TODO: At some point this demo should be extended to have a central bank node. + node.services.fillWithSomeTestCash(3000.DOLLARS, node.info.identity) + + // Wait around until a node asks to start a trade with us. In a real system, this part would happen out of band + // via some other system like an exchange or maybe even a manual messaging system like Bloomberg. But for the + // next stage in our building site, we will just auto-generate fake trades to give our nodes something to do. + // + // As the seller initiates the two-party trade protocol, here, we will be the buyer. + node.services.networkService.addMessageHandler("$DEMO_TOPIC.0") { message, registration -> // We use a simple scenario-specific wrapper protocol to make things happen. - val buyer = TraderDemoProtocolBuyer(attachmentsPath, node.info.identity, amount) + val otherSide = message.data.deserialize() + val buyer = TraderDemoProtocolBuyer(otherSide, attachmentsPath, amount) node.smm.add("demo.buyer", buyer) } - future.get() // This thread will halt forever here. + CountDownLatch(1).await() // Prevent the application from terminating } // We create a couple of ad-hoc test protocols that wrap the two party trade protocol, to give us the demo logic. val DEMO_TOPIC = "initiate.demo.trade" -private class TraderDemoProtocolBuyer(private val attachmentsPath: Path, - val notary: Party, - val amount: Amount>) : ProtocolLogic() { - companion object { - object WAITING_FOR_SELLER_TO_CONNECT : ProgressTracker.Step("Waiting for seller to connect to us") +private class TraderDemoProtocolBuyer(val otherSide: Party, + private val attachmentsPath: Path, + val amount: Amount>, + override val progressTracker: ProgressTracker = ProgressTracker(STARTING_BUY)) : ProtocolLogic() { - object STARTING_BUY : ProgressTracker.Step("Seller connected, purchasing commercial paper asset") - } + object STARTING_BUY : ProgressTracker.Step("Seller connected, purchasing commercial paper asset") - override val progressTracker = ProgressTracker(WAITING_FOR_SELLER_TO_CONNECT, STARTING_BUY) + override val topic: String get() = DEMO_TOPIC @Suspendable override fun call() { - // Self issue some cash. - // - // TODO: At some point this demo should be extended to have a central bank node. - serviceHub.fillWithSomeTestCash(3000.DOLLARS, notary) + // The session ID disambiguates the test trade. + val sessionID = random63BitValue() + progressTracker.currentStep = STARTING_BUY + send(otherSide, 0, sessionID) - while (true) { - // Wait around until a node asks to start a trade with us. In a real system, this part would happen out of band - // via some other system like an exchange or maybe even a manual messaging system like Bloomberg. But for the - // next stage in our building site, we will just auto-generate fake trades to give our nodes something to do. - // - // As the seller initiates the two-party trade protocol, here, we will be the buyer. - try { - progressTracker.currentStep = WAITING_FOR_SELLER_TO_CONNECT - val newPartnerParty = receive(DEMO_TOPIC, 0).validate { - val ourVersionOfParty = serviceHub.networkMapCache.getNodeByLegalName(it.name)!!.identity - require(ourVersionOfParty == it) - it - } + val notary = serviceHub.networkMapCache.notaryNodes[0] + val buyer = TwoPartyTradeProtocol.Buyer( + otherSide, + notary.identity, + amount, + CommercialPaper.State::class.java, + sessionID) - // The session ID disambiguates the test trade. - val sessionID = random63BitValue() - progressTracker.currentStep = STARTING_BUY - send(DEMO_TOPIC, newPartnerParty, 0, sessionID) + // This invokes the trading protocol and out pops our finished transaction. + val tradeTX: SignedTransaction = subProtocol(buyer) + // TODO: This should be moved into the protocol itself. + serviceHub.recordTransactions(listOf(tradeTX)) - val notary = serviceHub.networkMapCache.notaryNodes[0] - val buyer = TwoPartyTradeProtocol.Buyer(newPartnerParty, notary.identity, amount, - CommercialPaper.State::class.java, sessionID) + logger.info("Purchase complete - we are a happy customer! Final transaction is: " + + "\n\n${Emoji.renderIfSupported(tradeTX.tx)}") - // This invokes the trading protocol and out pops our finished transaction. - val tradeTX: SignedTransaction = subProtocol(buyer) - // TODO: This should be moved into the protocol itself. - serviceHub.recordTransactions(listOf(tradeTX)) - - logger.info("Purchase complete - we are a happy customer! Final transaction is: " + - "\n\n${Emoji.renderIfSupported(tradeTX.tx)}") - - logIssuanceAttachment(tradeTX) - logBalance() - - } catch(e: Exception) { - logger.error("Something went wrong whilst trading!", e) - } - } + logIssuanceAttachment(tradeTX) + logBalance() } private fun logBalance() { @@ -318,11 +306,13 @@ private class TraderDemoProtocolSeller(val otherSide: Party, fun tracker() = ProgressTracker(ANNOUNCING, SELF_ISSUING, TRADING) } + override val topic: String get() = DEMO_TOPIC + @Suspendable override fun call() { progressTracker.currentStep = ANNOUNCING - val sessionID = sendAndReceive(DEMO_TOPIC, otherSide, 0, 0, serviceHub.storageService.myLegalIdentity).validate { it } + val sessionID = sendAndReceive(otherSide, 0, 0, serviceHub.storageService.myLegalIdentity).validate { it } progressTracker.currentStep = SELF_ISSUING diff --git a/src/main/kotlin/com/r3corda/demos/protocols/AutoOfferProtocol.kt b/src/main/kotlin/com/r3corda/demos/protocols/AutoOfferProtocol.kt index a2f5a72fa3..de4f754fc1 100644 --- a/src/main/kotlin/com/r3corda/demos/protocols/AutoOfferProtocol.kt +++ b/src/main/kotlin/com/r3corda/demos/protocols/AutoOfferProtocol.kt @@ -81,6 +81,7 @@ object AutoOfferProtocol { fun tracker() = ProgressTracker(RECEIVED, ANNOUNCING, DEALING) } + override val topic: String get() = TOPIC override val progressTracker = tracker() init { @@ -95,17 +96,14 @@ object AutoOfferProtocol { val notary = serviceHub.networkMapCache.notaryNodes.first().identity // need to pick which ever party is not us val otherParty = notUs(*dealToBeOffered.parties).single() - val otherNode = (serviceHub.networkMapCache.getNodeByLegalName(otherParty.name)) - requireNotNull(otherNode) { "Cannot identify other party " + otherParty.name + ", know about: " + serviceHub.networkMapCache.partyNodes.map { it.identity } } - val otherSide = otherNode!!.identity progressTracker.currentStep = ANNOUNCING - send(TOPIC, otherSide, 0, AutoOfferMessage(serviceHub.storageService.myLegalIdentity, notary, ourSessionID, dealToBeOffered)) + send(otherParty, 0, AutoOfferMessage(serviceHub.storageService.myLegalIdentity, notary, ourSessionID, dealToBeOffered)) progressTracker.currentStep = DEALING - val stx = subProtocol(TwoPartyDealProtocol.Acceptor(otherSide, notary, dealToBeOffered, ourSessionID, progressTracker.getChildProgressTracker(DEALING)!!)) + val stx = subProtocol(TwoPartyDealProtocol.Acceptor(otherParty, notary, dealToBeOffered, ourSessionID, progressTracker.getChildProgressTracker(DEALING)!!)) return stx } - fun notUs(vararg parties: Party): List { + private fun notUs(vararg parties: Party): List { val notUsParties: MutableList = arrayListOf() for (party in parties) { if (serviceHub.storageService.myLegalIdentity != party) { diff --git a/src/main/kotlin/com/r3corda/demos/protocols/ExitServerProtocol.kt b/src/main/kotlin/com/r3corda/demos/protocols/ExitServerProtocol.kt index a3b9d6a01c..007aebd7e2 100644 --- a/src/main/kotlin/com/r3corda/demos/protocols/ExitServerProtocol.kt +++ b/src/main/kotlin/com/r3corda/demos/protocols/ExitServerProtocol.kt @@ -39,6 +39,8 @@ object ExitServerProtocol { */ class Broadcast(@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") val exitCode: Integer) : ProtocolLogic() { + override val topic: String get() = TOPIC + @Suspendable override fun call(): Boolean { if (enabled) { @@ -60,10 +62,7 @@ object ExitServerProtocol { if (recipient.address is MockNetworkMapCache.MockAddress) { // Ignore } else { - // TODO: messaging ourselves seems to trigger a bug for the time being and we continuously receive messages - if (recipient.identity != serviceHub.storageService.myLegalIdentity) { - send(TOPIC, recipient.identity, 0, message) - } + send(recipient.identity, 0, message) } } } diff --git a/src/main/kotlin/com/r3corda/demos/protocols/UpdateBusinessDayProtocol.kt b/src/main/kotlin/com/r3corda/demos/protocols/UpdateBusinessDayProtocol.kt index 00ede632fa..ce9884bce0 100644 --- a/src/main/kotlin/com/r3corda/demos/protocols/UpdateBusinessDayProtocol.kt +++ b/src/main/kotlin/com/r3corda/demos/protocols/UpdateBusinessDayProtocol.kt @@ -38,6 +38,8 @@ object UpdateBusinessDayProtocol { fun tracker() = ProgressTracker(NOTIFYING) } + override val topic: String get() = TOPIC + @Suspendable override fun call(): Unit { progressTracker.currentStep = NOTIFYING @@ -52,7 +54,7 @@ object UpdateBusinessDayProtocol { if (recipient.address is MockNetworkMapCache.MockAddress) { // Ignore } else { - send(TOPIC, recipient.identity, 0, message) + send(recipient.identity, 0, message) } } } From 99fe3dfe75131ad0e6c89f86d2ca01f7a0df0112 Mon Sep 17 00:00:00 2001 From: Matthew Nesbit Date: Wed, 6 Jul 2016 13:23:41 +0100 Subject: [PATCH 073/114] Make the IRS Demo web api an api plugin (scanned from the Node classpath) and use the same permission checking entry point for web api's as the scheduler. --- .../r3corda/core/node/CordaPluginRegistry.kt | 26 +++++++++++++++++ .../com/r3corda/core/node/ServiceHub.kt | 19 ++++++++++++ .../com/r3corda/node/internal/AbstractNode.kt | 22 +++++++++++++- .../kotlin/com/r3corda/node/internal/Node.kt | 19 +++++++----- .../node/services/api/ServiceHubInternal.kt | 7 +++++ src/main/kotlin/com/r3corda/demos/IRSDemo.kt | 15 ++++++++-- .../kotlin/com/r3corda/demos/RateFixDemo.kt | 3 +- .../r3corda/demos/api/InterestRateSwapAPI.kt | 29 ++++++++++--------- .../demos/protocols/ExitServerProtocol.kt | 7 ++--- .../com.r3corda.core.node.CordaPluginRegistry | 2 ++ 10 files changed, 118 insertions(+), 31 deletions(-) create mode 100644 core/src/main/kotlin/com/r3corda/core/node/CordaPluginRegistry.kt create mode 100644 src/main/resources/META-INF/services/com.r3corda.core.node.CordaPluginRegistry diff --git a/core/src/main/kotlin/com/r3corda/core/node/CordaPluginRegistry.kt b/core/src/main/kotlin/com/r3corda/core/node/CordaPluginRegistry.kt new file mode 100644 index 0000000000..d93bc96783 --- /dev/null +++ b/core/src/main/kotlin/com/r3corda/core/node/CordaPluginRegistry.kt @@ -0,0 +1,26 @@ +package com.r3corda.core.node + +/** + * Implement this interface on a class advertised in a META-INF/services/com.r3corda.core.node.CordaPluginRegistry file + * to extend a Corda node with additional application services. + */ +interface CordaPluginRegistry { + /** + * List of JAX-RS classes inside the contract jar. They are expected to have a single parameter constructor that takes a ServiceHub as input. + * These are listed as Class<*>, because they will be instantiated inside an AttachmentClassLoader so that subsequent protocols, contracts, etc + * will be running in the appropriate isolated context. + */ + val webApis: List> + + /** + * Set of top level protocol class names that will be initiated by the plugin. + * This is used to extend the white listed protocols that can be initiated from the ServiceHub invokeProtocolAsync method + */ + val protocolLogicClassNameWhitelist: Set + + /** + * Set of associated constructor parameters that will be passed into the protocols. + * This is used to control what can be passed to protocols initiated from the ServiceHub invokeProtocolAsync method + */ + val protocolArgsClassNameWhitelist: Set +} \ No newline at end of file diff --git a/core/src/main/kotlin/com/r3corda/core/node/ServiceHub.kt b/core/src/main/kotlin/com/r3corda/core/node/ServiceHub.kt index 893f83a868..a6453f4651 100644 --- a/core/src/main/kotlin/com/r3corda/core/node/ServiceHub.kt +++ b/core/src/main/kotlin/com/r3corda/core/node/ServiceHub.kt @@ -1,8 +1,10 @@ package com.r3corda.core.node +import com.google.common.util.concurrent.ListenableFuture import com.r3corda.core.contracts.* import com.r3corda.core.messaging.MessagingService import com.r3corda.core.node.services.* +import com.r3corda.core.protocols.ProtocolLogic import java.time.Clock /** @@ -61,4 +63,21 @@ interface ServiceHub { val definingTx = storageService.validatedTransactions.getTransaction(stateRef.txhash) ?: throw TransactionResolutionException(stateRef.txhash) return definingTx.tx.outputs[stateRef.index] } + + /** + * Will check [logicType] and [args] against a whitelist and if acceptable then construct and initiate the protocol. + * + * @throws IllegalProtocolLogicException or IllegalArgumentException if there are problems with the [logicType] or [args] + */ + fun invokeProtocolAsync(logicType: Class>, vararg args: Any?): ListenableFuture + + /** + * Will check [logicType] and [args] against a whitelist and if acceptable then construct and initiate the protocol. + * + * Will block and return any protocol result when the protocol eventually completes. + */ + fun invokeProtocolSync(logicType: Class>, vararg args: Any?): T { + return invokeProtocolAsync(logicType, *args).get() + } + } \ No newline at end of file diff --git a/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt index 7838807b5a..47a6510294 100644 --- a/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt @@ -5,10 +5,12 @@ import com.google.common.util.concurrent.ListenableFuture import com.google.common.util.concurrent.SettableFuture import com.r3corda.core.RunOnCallerThread import com.r3corda.core.contracts.SignedTransaction +import com.r3corda.core.contracts.StateRef import com.r3corda.core.crypto.Party import com.r3corda.core.messaging.MessagingService import com.r3corda.core.messaging.runOnNextMessage import com.r3corda.core.node.CityDatabase +import com.r3corda.core.node.CordaPluginRegistry import com.r3corda.core.node.NodeInfo import com.r3corda.core.node.PhysicalLocation import com.r3corda.core.node.services.* @@ -46,12 +48,14 @@ import com.r3corda.node.services.wallet.NodeWalletService import com.r3corda.node.utilities.ANSIProgressObserver import com.r3corda.node.utilities.AddOrRemove import com.r3corda.node.utilities.AffinityExecutor +import com.r3corda.protocols.TwoPartyDealProtocol import org.slf4j.Logger import java.nio.file.FileAlreadyExistsException import java.nio.file.Files import java.nio.file.Path import java.security.KeyPair import java.time.Clock +import java.time.Duration import java.util.* /** @@ -97,7 +101,7 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration, // Internal only override val monitoringService: MonitoringService = MonitoringService(MetricRegistry()) - override val protocolLogicRefFactory = ProtocolLogicRefFactory() + override val protocolLogicRefFactory:ProtocolLogicRefFactory get() = protocolLogicFactory override fun startProtocol(loggerName: String, logic: ProtocolLogic): ListenableFuture { return smm.add(loggerName, logic) @@ -124,6 +128,7 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration, lateinit var net: MessagingService lateinit var api: APIServer lateinit var scheduler: SchedulerService + lateinit var protocolLogicFactory: ProtocolLogicRefFactory var isPreviousCheckpointsPresent = false private set @@ -158,6 +163,8 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration, checkpointStorage, serverThread) + protocolLogicFactory = initialiseProtocolLogicFactory() + // This object doesn't need to be referenced from this class because it registers handlers on the network // service and so that keeps it from being collected. DataVendingService(net, storage, services.networkMapCache) @@ -180,6 +187,19 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration, return this } + private fun initialiseProtocolLogicFactory(): ProtocolLogicRefFactory { + val serviceLoader = ServiceLoader.load(CordaPluginRegistry::class.java) + val pluginRegistries = serviceLoader.toList() + val protocolLogicClassNameWhitelist = pluginRegistries.flatMap { x -> x.protocolLogicClassNameWhitelist }.toMutableSet() + val protocolArgsClassNameWhitelist = pluginRegistries.flatMap { x -> x.protocolArgsClassNameWhitelist }.toMutableSet() + + //Add in standard protocol whitelist + protocolLogicClassNameWhitelist.add(TwoPartyDealProtocol.FixingRoleDecider::class.java.name) + protocolArgsClassNameWhitelist.add(StateRef::class.java.name) + protocolArgsClassNameWhitelist.add(Duration::class.java.name) + return ProtocolLogicRefFactory(protocolLogicClassNameWhitelist, protocolArgsClassNameWhitelist) + } + /** * Run any tasks that are needed to ensure the node is in a correct state before running start() */ diff --git a/node/src/main/kotlin/com/r3corda/node/internal/Node.kt b/node/src/main/kotlin/com/r3corda/node/internal/Node.kt index 85cfac29a3..98e7a72745 100644 --- a/node/src/main/kotlin/com/r3corda/node/internal/Node.kt +++ b/node/src/main/kotlin/com/r3corda/node/internal/Node.kt @@ -3,10 +3,11 @@ package com.r3corda.node.internal import com.codahale.metrics.JmxReporter import com.google.common.net.HostAndPort import com.r3corda.core.messaging.MessagingService +import com.r3corda.core.node.CordaPluginRegistry import com.r3corda.core.node.NodeInfo +import com.r3corda.core.node.ServiceHub import com.r3corda.core.node.services.ServiceType import com.r3corda.core.utilities.loggerFor -import com.r3corda.node.api.APIServer import com.r3corda.node.serialization.NodeClock import com.r3corda.node.services.config.NodeConfiguration import com.r3corda.node.services.messaging.ArtemisMessagingService @@ -27,9 +28,9 @@ import java.io.RandomAccessFile import java.lang.management.ManagementFactory import java.net.InetSocketAddress import java.nio.channels.FileLock -import java.nio.file.Files import java.nio.file.Path import java.time.Clock +import java.util.* import javax.management.ObjectName class ConfigurationException(message: String) : Exception(message) @@ -55,8 +56,7 @@ class ConfigurationException(message: String) : Exception(message) */ class Node(dir: Path, val p2pAddr: HostAndPort, val webServerAddr: HostAndPort, configuration: NodeConfiguration, networkMapAddress: NodeInfo?, advertisedServices: Set, - clock: Clock = NodeClock(), - val clientAPIs: List> = listOf()) : AbstractNode(dir, configuration, networkMapAddress, advertisedServices, clock) { + clock: Clock = NodeClock()) : AbstractNode(dir, configuration, networkMapAddress, advertisedServices, clock) { companion object { /** The port that is used by default if none is specified. As you know, 31337 is the most elite number. */ val DEFAULT_PORT = 31337 @@ -109,12 +109,15 @@ class Node(dir: Path, val p2pAddr: HostAndPort, val webServerAddr: HostAndPort, resourceConfig.register(ResponseFilter()) resourceConfig.register(api) - for(customAPIClass in clientAPIs) { - val customAPI = customAPIClass.getConstructor(APIServer::class.java).newInstance(api) + val serviceLoader = ServiceLoader.load(CordaPluginRegistry::class.java) + val pluginRegistries = serviceLoader.toList() + val webAPIsOnClasspath = pluginRegistries.flatMap { x -> x.webApis } + for (webapi in webAPIsOnClasspath) { + log.info("Add Plugin web API from attachment ${webapi.name}") + val customAPI = webapi.getConstructor(ServiceHub::class.java).newInstance(services) resourceConfig.register(customAPI) } - // 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")) @@ -187,5 +190,5 @@ class Node(dir: Path, val p2pAddr: HostAndPort, val webServerAddr: HostAndPort, val ourProcessID: String = ManagementFactory.getRuntimeMXBean().name.split("@")[0] f.setLength(0) f.write(ourProcessID.toByteArray()) - } + } } diff --git a/node/src/main/kotlin/com/r3corda/node/services/api/ServiceHubInternal.kt b/node/src/main/kotlin/com/r3corda/node/services/api/ServiceHubInternal.kt index e206a28644..1a0ade26d9 100644 --- a/node/src/main/kotlin/com/r3corda/node/services/api/ServiceHubInternal.kt +++ b/node/src/main/kotlin/com/r3corda/node/services/api/ServiceHubInternal.kt @@ -29,4 +29,11 @@ abstract class ServiceHubInternal : ServiceHub { * itself, at which point this method would not be needed (by the scheduler) */ abstract fun startProtocol(loggerName: String, logic: ProtocolLogic): ListenableFuture + + override fun invokeProtocolAsync(logicType: Class>, vararg args: Any?): ListenableFuture { + val logicRef = protocolLogicRefFactory.create(logicType, *args) + @Suppress("UNCHECKED_CAST") + val logic = protocolLogicRefFactory.toProtocolLogic(logicRef) as ProtocolLogic + return startProtocol(logicType.simpleName, logic) + } } \ No newline at end of file diff --git a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt index c2a60d4609..f2eedcc04e 100644 --- a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt @@ -1,9 +1,11 @@ package com.r3corda.demos import com.google.common.net.HostAndPort +import com.r3corda.contracts.InterestRateSwap import com.r3corda.core.crypto.Party import com.r3corda.core.logElapsedTime import com.r3corda.core.messaging.SingleMessageRecipient +import com.r3corda.core.node.CordaPluginRegistry import com.r3corda.core.node.NodeInfo import com.r3corda.core.node.services.ServiceType import com.r3corda.core.serialization.deserialize @@ -241,6 +243,16 @@ object CliParamsSpec { val nonOptions = parser.nonOptions() } +class IRSDemoPluginRegistry : CordaPluginRegistry { + override val webApis: List> = listOf(InterestRateSwapAPI::class.java) + override val protocolLogicClassNameWhitelist: Set = setOf(AutoOfferProtocol.Requester::class.java.name, + UpdateBusinessDayProtocol.Broadcast::class.java.name, + ExitServerProtocol.Broadcast::class.java.name) + override val protocolArgsClassNameWhitelist: Set = setOf(InterestRateSwap.State::class.java.name, + java.time.LocalDate::class.java.name, + kotlin.Int::class.java.name) +} + private class NotSetupException: Throwable { constructor(message: String): super(message) {} } @@ -374,8 +386,7 @@ private fun startNode(params: CliParams.RunNode, networkMap: SingleMessageRecipi } val node = logElapsedTime("Node startup") { - Node(params.dir, params.networkAddress, params.apiAddress, config, networkMapId, advertisedServices, DemoClock(), - listOf(InterestRateSwapAPI::class.java)).start() + Node(params.dir, params.networkAddress, params.apiAddress, config, networkMapId, advertisedServices, DemoClock()).start() } // TODO: This should all be replaced by the identity service being updated diff --git a/src/main/kotlin/com/r3corda/demos/RateFixDemo.kt b/src/main/kotlin/com/r3corda/demos/RateFixDemo.kt index 96473b033c..1374c58dd4 100644 --- a/src/main/kotlin/com/r3corda/demos/RateFixDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/RateFixDemo.kt @@ -76,8 +76,7 @@ fun main(args: Array) { val apiAddr = HostAndPort.fromParts(myNetAddr.hostText, myNetAddr.port + 1) val node = logElapsedTime("Node startup") { Node(dir, myNetAddr, apiAddr, config, networkMapAddress, - advertisedServices, DemoClock(), - listOf(InterestRateSwapAPI::class.java)).setup().start() } + advertisedServices, DemoClock()).setup().start() } val notary = node.services.networkMapCache.notaryNodes[0] diff --git a/src/main/kotlin/com/r3corda/demos/api/InterestRateSwapAPI.kt b/src/main/kotlin/com/r3corda/demos/api/InterestRateSwapAPI.kt index 9197216da7..911e924ddc 100644 --- a/src/main/kotlin/com/r3corda/demos/api/InterestRateSwapAPI.kt +++ b/src/main/kotlin/com/r3corda/demos/api/InterestRateSwapAPI.kt @@ -1,15 +1,16 @@ package com.r3corda.demos.api import com.r3corda.contracts.InterestRateSwap +import com.r3corda.core.contracts.SignedTransaction +import com.r3corda.core.node.ServiceHub +import com.r3corda.core.node.services.linearHeadsOfType import com.r3corda.core.utilities.loggerFor import com.r3corda.demos.protocols.AutoOfferProtocol import com.r3corda.demos.protocols.ExitServerProtocol import com.r3corda.demos.protocols.UpdateBusinessDayProtocol -import com.r3corda.node.api.APIServer -import com.r3corda.node.api.ProtocolClassRef -import com.r3corda.node.api.StatesQuery import java.net.URI import java.time.LocalDate +import java.time.LocalDateTime import javax.ws.rs.* import javax.ws.rs.core.MediaType import javax.ws.rs.core.Response @@ -35,23 +36,23 @@ import javax.ws.rs.core.Response * or if the demodate or population of deals should be reset (will only work while persistence is disabled). */ @Path("irs") -class InterestRateSwapAPI(val api: APIServer) { +class InterestRateSwapAPI(val services: ServiceHub) { private val logger = loggerFor() private fun generateDealLink(deal: InterestRateSwap.State) = "/api/irs/deals/" + deal.common.tradeID private fun getDealByRef(ref: String): InterestRateSwap.State? { - val states = api.queryStates(StatesQuery.selectDeal(ref)) - return if (states.isEmpty()) null else { - val deals = api.fetchStates(states).values.map { it?.data as InterestRateSwap.State }.filterNotNull() + val states = services.walletService.linearHeadsOfType().filterValues { it.state.data.ref == ref } + return if (states.isEmpty()) null else { + val deals = states.values.map { it.state.data } return if (deals.isEmpty()) null else deals[0] } } private fun getAllDeals(): Array { - val states = api.queryStates(StatesQuery.selectAllDeals()) - val swaps = api.fetchStates(states).values.map { it?.data as InterestRateSwap.State }.filterNotNull().toTypedArray() + val states = services.walletService.linearHeadsOfType() + val swaps = states.values.map { it.state.data }.toTypedArray() return swaps } @@ -64,7 +65,7 @@ class InterestRateSwapAPI(val api: APIServer) { @Path("deals") @Consumes(MediaType.APPLICATION_JSON) fun storeDeal(newDeal: InterestRateSwap.State): Response { - api.invokeProtocolSync(ProtocolClassRef(AutoOfferProtocol.Requester::class.java.name!!), mapOf("dealToBeOffered" to newDeal)) + services.invokeProtocolSync(AutoOfferProtocol.Requester::class.java,newDeal) return Response.created(URI.create(generateDealLink(newDeal))).build() } @@ -84,10 +85,10 @@ class InterestRateSwapAPI(val api: APIServer) { @Path("demodate") @Consumes(MediaType.APPLICATION_JSON) fun storeDemoDate(newDemoDate: LocalDate): Response { - val priorDemoDate = api.serverTime().toLocalDate() + val priorDemoDate = fetchDemoDate() // Can only move date forwards if (newDemoDate.isAfter(priorDemoDate)) { - api.invokeProtocolSync(ProtocolClassRef(UpdateBusinessDayProtocol.Broadcast::class.java.name!!), mapOf("date" to newDemoDate)) + services.invokeProtocolSync(UpdateBusinessDayProtocol.Broadcast::class.java,newDemoDate) return Response.ok().build() } val msg = "demodate is already $priorDemoDate and can only be updated with a later date" @@ -99,14 +100,14 @@ class InterestRateSwapAPI(val api: APIServer) { @Path("demodate") @Produces(MediaType.APPLICATION_JSON) fun fetchDemoDate(): LocalDate { - return api.serverTime().toLocalDate() + return LocalDateTime.now(services.clock).toLocalDate() } @PUT @Path("restart") @Consumes(MediaType.APPLICATION_JSON) fun exitServer(): Response { - api.invokeProtocolSync(ProtocolClassRef(ExitServerProtocol.Broadcast::class.java.name!!), mapOf("exitCode" to 83)) + services.invokeProtocolSync(ExitServerProtocol.Broadcast::class.java,83) return Response.ok().build() } } diff --git a/src/main/kotlin/com/r3corda/demos/protocols/ExitServerProtocol.kt b/src/main/kotlin/com/r3corda/demos/protocols/ExitServerProtocol.kt index a3b9d6a01c..85bf7cf9ee 100644 --- a/src/main/kotlin/com/r3corda/demos/protocols/ExitServerProtocol.kt +++ b/src/main/kotlin/com/r3corda/demos/protocols/ExitServerProtocol.kt @@ -37,20 +37,19 @@ object ExitServerProtocol { * This takes a Java Integer rather than Kotlin Int as that is what we end up with in the calling map and currently * we do not support coercing numeric types in the reflective search for matching constructors */ - class Broadcast(@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") val exitCode: Integer) : ProtocolLogic() { + class Broadcast(@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") val exitCode: Int) : ProtocolLogic() { @Suspendable override fun call(): Boolean { if (enabled) { - val rc = exitCode.toInt() - val message = ExitMessage(rc) + val message = ExitMessage(exitCode) for (recipient in serviceHub.networkMapCache.partyNodes) { doNextRecipient(recipient, message) } // Sleep a little in case any async message delivery to other nodes needs to happen Strand.sleep(1, TimeUnit.SECONDS) - System.exit(rc) + System.exit(exitCode) } return enabled } diff --git a/src/main/resources/META-INF/services/com.r3corda.core.node.CordaPluginRegistry b/src/main/resources/META-INF/services/com.r3corda.core.node.CordaPluginRegistry new file mode 100644 index 0000000000..279300f9f9 --- /dev/null +++ b/src/main/resources/META-INF/services/com.r3corda.core.node.CordaPluginRegistry @@ -0,0 +1,2 @@ +# Register a ServiceLoader service extending from com.r3corda.node.CordaPluginRegistry +com.r3corda.demos.IRSDemoPluginRegistry \ No newline at end of file From bf4272b64ad31d651e36e0fea1a23f9bc425fdb2 Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Fri, 1 Jul 2016 16:09:58 +0100 Subject: [PATCH 074/114] core: transaction/ledger DSL interfaces and implementation for tests --- .../core/testing/LedgerDslInterpreter.kt | 35 +++ .../com/r3corda/core/testing/TestDsl.kt | 295 ++++++++++++++++++ .../core/testing/TransactionDslInterpreter.kt | 64 ++++ 3 files changed, 394 insertions(+) create mode 100644 core/src/main/kotlin/com/r3corda/core/testing/LedgerDslInterpreter.kt create mode 100644 core/src/main/kotlin/com/r3corda/core/testing/TestDsl.kt create mode 100644 core/src/main/kotlin/com/r3corda/core/testing/TransactionDslInterpreter.kt diff --git a/core/src/main/kotlin/com/r3corda/core/testing/LedgerDslInterpreter.kt b/core/src/main/kotlin/com/r3corda/core/testing/LedgerDslInterpreter.kt new file mode 100644 index 0000000000..c8b7668e18 --- /dev/null +++ b/core/src/main/kotlin/com/r3corda/core/testing/LedgerDslInterpreter.kt @@ -0,0 +1,35 @@ +package com.r3corda.core.testing + +import com.r3corda.core.contracts.Attachment +import com.r3corda.core.contracts.ContractState +import com.r3corda.core.crypto.SecureHash +import com.r3corda.core.node.services.IdentityService +import com.r3corda.core.node.services.StorageService +import com.r3corda.core.node.services.testing.MockStorageService + +interface LedgerDslInterpreter> { + fun transaction(dsl: TransactionDsl.() -> Unit): Unit + fun nonVerifiedTransaction(dsl: TransactionDsl.() -> Unit): Unit + fun tweak(dsl: LedgerDsl>.() -> Unit) + fun attachment(attachment: Attachment): SecureHash + fun _verifies(identityService: IdentityService, storageService: StorageService) +} + +/** + * This is the class the top-level primitives deal with. It delegates all other primitives to the contained interpreter. + * This way we have a decoupling of the DSL "AST" and the interpretation(s) of it. Note how the delegation forces + * covariance of the TransactionInterpreter parameter + */ +class LedgerDsl< + State: ContractState, + out TransactionInterpreter: TransactionDslInterpreter, + out LedgerInterpreter: LedgerDslInterpreter + > (val interpreter: LedgerInterpreter) + : LedgerDslInterpreter> by interpreter { + + @JvmOverloads + fun verifies( + identityService: IdentityService = MOCK_IDENTITY_SERVICE, + storageService: StorageService = MockStorageService() + ) = _verifies(identityService, storageService) +} diff --git a/core/src/main/kotlin/com/r3corda/core/testing/TestDsl.kt b/core/src/main/kotlin/com/r3corda/core/testing/TestDsl.kt new file mode 100644 index 0000000000..f508ba58fb --- /dev/null +++ b/core/src/main/kotlin/com/r3corda/core/testing/TestDsl.kt @@ -0,0 +1,295 @@ +package com.r3corda.core.testing + +import com.r3corda.core.contracts.* +import com.r3corda.core.crypto.Party +import com.r3corda.core.crypto.SecureHash +import com.r3corda.core.node.services.IdentityService +import com.r3corda.core.node.services.StorageService +import java.security.PublicKey +import java.util.* + +inline fun ledger( + dsl: LedgerDsl, TestLedgerDslInterpreter>.() -> Unit) = + dsl(LedgerDsl(TestLedgerDslInterpreter.create())) + +@Deprecated( + message = "ledger doesn't nest, use tweak", + replaceWith = ReplaceWith("tweak"), + level = DeprecationLevel.ERROR) +fun TransactionDslInterpreter.ledger( + dsl: LedgerDsl, TestLedgerDslInterpreter>.() -> Unit) { + this.toString() + dsl.toString() +} + +@Deprecated( + message = "ledger doesn't nest, use tweak", + replaceWith = ReplaceWith("tweak"), + level = DeprecationLevel.ERROR) +fun LedgerDslInterpreter>.ledger( + dsl: LedgerDsl, TestLedgerDslInterpreter>.() -> Unit) { + this.toString() + dsl.toString() +} + +/** + * This interpreter builds a transaction, and [TransactionDsl.verifies] that the resolved transaction is correct. Note + * that transactions corresponding to input states are not verified. Use [LedgerDsl.verifies] for that. + */ +data class TestTransactionDslInterpreter( + private val ledgerInterpreter: TestLedgerDslInterpreter, + private val inputStateRefs: ArrayList = arrayListOf(), + internal val outputStates: ArrayList = arrayListOf(), + private val attachments: ArrayList = arrayListOf(), + private val commands: ArrayList = arrayListOf(), + private val signers: LinkedHashSet = LinkedHashSet(), + private val transactionType: TransactionType = TransactionType.General() +) : TransactionDslInterpreter { + + private fun copy(): TestTransactionDslInterpreter = + TestTransactionDslInterpreter( + ledgerInterpreter = ledgerInterpreter.copy(), + inputStateRefs = ArrayList(inputStateRefs), + outputStates = ArrayList(outputStates), + attachments = ArrayList(attachments), + commands = ArrayList(commands), + signers = LinkedHashSet(signers), + transactionType = transactionType + ) + + internal fun toWireTransaction(): WireTransaction = + WireTransaction( + inputs = inputStateRefs, + outputs = outputStates.map { it.state }, + attachments = attachments, + commands = commands, + signers = signers.toList(), + type = transactionType + ) + + override fun input(stateLabel: String) { + val notary = stateLabel.output.notary.owningKey + signers.add(notary) + inputStateRefs.add(stateLabel.outputRef) + } + + override fun input(stateRef: StateRef) { + val notary = ledgerInterpreter.resolveStateRef(stateRef).notary + signers.add(notary.owningKey) + inputStateRefs.add(stateRef) + } + + override fun output(label: String?, notary: Party, contractState: State) { + outputStates.add(LabeledOutput(label, TransactionState(contractState, notary))) + } + + override fun attachment(attachmentId: SecureHash) { + attachments.add(attachmentId) + } + + override fun _command(signers: List, commandData: CommandData) { + this.signers.addAll(signers) + commands.add(Command(commandData, signers)) + } + + override fun _verifies(identityService: IdentityService) { + val resolvedTransaction = ledgerInterpreter.resolveWireTransaction(toWireTransaction(), identityService) + resolvedTransaction.verify() + } + + override fun failsWith(expectedMessage: String?, identityService: IdentityService) { + val exceptionThrown = try { + _verifies(identityService) + false + } catch (exception: Exception) { + if (expectedMessage != null) { + val exceptionMessage = exception.message + if (exceptionMessage == null) { + throw AssertionError( + "Expected exception containing '$expectedMessage' but raised exception had no message" + ) + } else if (!exceptionMessage.toLowerCase().contains(expectedMessage.toLowerCase())) { + throw AssertionError( + "Expected exception containing '$expectedMessage' but raised exception was '$exceptionMessage'" + ) + } + } + true + } + + if (!exceptionThrown) { + throw AssertionError("Expected exception but didn't get one") + } + } + + override fun tweak(dsl: TransactionDsl>.() -> Unit) = + dsl(TransactionDsl(copy())) + + override fun retrieveOutputStateAndRef(label: String): StateAndRef? = + ledgerInterpreter.labelToOutputStateAndRefs[label] +} + +class AttachmentResolutionException(val attachmentId: SecureHash) : + Exception("Attachment with id $attachmentId not found") + +data class TestLedgerDslInterpreter private constructor ( + internal val stateClazz: Class, + internal val labelToOutputStateAndRefs: HashMap> = HashMap(), + private val transactionWithLocations: HashMap = HashMap(), + private val nonVerifiedTransactionWithLocations: HashMap = HashMap(), + private val attachments: HashMap = HashMap() +) : LedgerDslInterpreter> { + + // We specify [labelToOutputStateAndRefs] just so that Kotlin picks the primary constructor instead of cycling + constructor(stateClazz: Class) : this(stateClazz, labelToOutputStateAndRefs = HashMap()) + + companion object { + /** + * Convenience factory to avoid having to pass in the Class + */ + inline fun create() = TestLedgerDslInterpreter(State::class.java) + + private fun getCallerLocation(offset: Int): String { + val stackTraceElement = Thread.currentThread().stackTrace[3 + offset] + return stackTraceElement.toString() + } + } + + private data class WireTransactionWithLocation(val transaction: WireTransaction, val location: String) + private class VerifiesFailed(transactionLocation: String, cause: Throwable) : + Exception("Transaction defined at ($transactionLocation) didn't verify: $cause", cause) + + internal fun copy(): TestLedgerDslInterpreter = + TestLedgerDslInterpreter( + stateClazz = stateClazz, + labelToOutputStateAndRefs = HashMap(labelToOutputStateAndRefs), + transactionWithLocations = HashMap(transactionWithLocations), + nonVerifiedTransactionWithLocations = HashMap(nonVerifiedTransactionWithLocations), + attachments = HashMap(attachments) + ) + + fun resolveWireTransaction(wireTransaction: WireTransaction, identityService: IdentityService): TransactionForVerification { + return wireTransaction.run { + val authenticatedCommands = commands.map { + AuthenticatedObject(it.signers, it.signers.mapNotNull { identityService.partyFromKey(it) }, it.value) + } + val resolvedInputStates = inputs.map { resolveStateRef(it) } + val resolvedAttachments = attachments.map { resolveAttachment(it) } + TransactionForVerification( + inputs = resolvedInputStates, + outputs = outputs, + commands = authenticatedCommands, + origHash = wireTransaction.serialized.hash, + attachments = resolvedAttachments, + signers = signers.toList(), + type = type + ) + + } + } + + fun resolveStateRef(stateRef: StateRef): TransactionState { + val transactionWithLocation = + transactionWithLocations[stateRef.txhash] ?: + nonVerifiedTransactionWithLocations[stateRef.txhash] ?: + throw TransactionResolutionException(stateRef.txhash) + val output = transactionWithLocation.transaction.outputs[stateRef.index] + return if (stateClazz.isInstance(output.data)) @Suppress("UNCHECKED_CAST") { + output as TransactionState + } else { + throw IllegalArgumentException("Referenced state is of another type than requested") + } + } + + fun resolveAttachment(attachmentId: SecureHash): Attachment = + attachments[attachmentId] ?: throw AttachmentResolutionException(attachmentId) + + private fun interpretTransactionDsl(dsl: TransactionDsl>.() -> Unit): + TestTransactionDslInterpreter { + val transactionInterpreter = TestTransactionDslInterpreter(this) + dsl(TransactionDsl(transactionInterpreter)) + return transactionInterpreter + } + + private fun toTransactionGroup(identityService: IdentityService, storageService: StorageService): TransactionGroup { + val ledgerTransactions = transactionWithLocations.map { + it.value.transaction.toLedgerTransaction(identityService, storageService.attachments) + } + val nonVerifiedLedgerTransactions = nonVerifiedTransactionWithLocations.map { + it.value.transaction.toLedgerTransaction(identityService, storageService.attachments) + } + return TransactionGroup(ledgerTransactions.toSet(), nonVerifiedLedgerTransactions.toSet()) + } + + private fun recordTransactionWithTransactionMap( + dsl: TransactionDsl>.() -> Unit, + transactionMap: HashMap = HashMap() + ) { + val transactionLocation = getCallerLocation(3) + val transactionInterpreter = interpretTransactionDsl(dsl) + // Create the WireTransaction + val wireTransaction = transactionInterpreter.toWireTransaction() + // Record the output states + transactionInterpreter.outputStates.forEachIndexed { index, labeledOutput -> + if (labeledOutput.label != null) { + labelToOutputStateAndRefs[labeledOutput.label] = wireTransaction.outRef(index) + } + } + + transactionMap[wireTransaction.serialized.hash] = + WireTransactionWithLocation(wireTransaction, transactionLocation) + + } + + override fun transaction(dsl: TransactionDsl>.() -> Unit) = + recordTransactionWithTransactionMap(dsl, transactionWithLocations) + + override fun nonVerifiedTransaction(dsl: TransactionDsl>.() -> Unit) = + recordTransactionWithTransactionMap(dsl, nonVerifiedTransactionWithLocations) + + override fun tweak( + dsl: LedgerDsl, + LedgerDslInterpreter>>.() -> Unit) = + dsl(LedgerDsl(copy())) + + override fun attachment(attachment: Attachment): SecureHash { + attachments[attachment.id] = attachment + return attachment.id + } + + override fun _verifies(identityService: IdentityService, storageService: StorageService) { + val transactionGroup = toTransactionGroup(identityService, storageService) + try { + transactionGroup.verify() + } catch (exception: TransactionVerificationException) { + throw VerifiesFailed(transactionWithLocations[exception.tx.origHash]?.location ?: "", exception) + } + } +} + +fun main(args: Array) { + ledger { + nonVerifiedTransaction { + output("hello") { DummyLinearState() } + } + + transaction { + input("hello") + tweak { + timestamp(TEST_TX_TIME, MEGA_CORP_PUBKEY) + fails() + } + } + + tweak { + + transaction { + input("hello") + timestamp(TEST_TX_TIME, MEGA_CORP_PUBKEY) + fails() + } + } + + verifies() + } +} diff --git a/core/src/main/kotlin/com/r3corda/core/testing/TransactionDslInterpreter.kt b/core/src/main/kotlin/com/r3corda/core/testing/TransactionDslInterpreter.kt new file mode 100644 index 0000000000..ac8eba0adf --- /dev/null +++ b/core/src/main/kotlin/com/r3corda/core/testing/TransactionDslInterpreter.kt @@ -0,0 +1,64 @@ +package com.r3corda.core.testing + +import com.r3corda.core.contracts.* +import com.r3corda.core.crypto.Party +import com.r3corda.core.crypto.SecureHash +import com.r3corda.core.node.services.IdentityService +import com.r3corda.core.seconds +import java.security.PublicKey +import java.time.Instant + + +/** + * [State] is bound at the top level. This allows the definition of e.g. [String.output], however it also means that we + * cannot mix different types of states in the same transaction. + * TODO: Move the [State] binding to the primitives' level to allow different State types, use reflection to check types + * dynamically, come up with a substitute for primitives relying on early bind + */ +interface TransactionDslInterpreter { + fun input(stateLabel: String) + fun input(stateRef: StateRef) + fun output(label: String?, notary: Party, contractState: State) + fun attachment(attachmentId: SecureHash) + fun _command(signers: List, commandData: CommandData) + fun _verifies(identityService: IdentityService) + fun failsWith(expectedMessage: String?, identityService: IdentityService) + fun tweak(dsl: TransactionDsl>.() -> Unit) + fun retrieveOutputStateAndRef(label: String): StateAndRef? + + val String.outputStateAndRef: StateAndRef + get() = retrieveOutputStateAndRef(this) ?: throw IllegalArgumentException("State with label '$this' was not found") + val String.output: TransactionState + get() = outputStateAndRef.state + val String.outputRef: StateRef + get() = outputStateAndRef.ref +} + + +class TransactionDsl< + State: ContractState, + out TransactionInterpreter: TransactionDslInterpreter + > (val interpreter: TransactionInterpreter) + : TransactionDslInterpreter by interpreter { + + // Convenience functions + fun output(label: String? = null, notary: Party = DUMMY_NOTARY, contractStateClosure: () -> State) = + output(label, notary, contractStateClosure()) + @JvmOverloads + fun output(label: String? = null, contractState: State) = output(label, DUMMY_NOTARY, contractState) + + fun command(vararg signers: PublicKey, commandDataClosure: () -> CommandData) = + _command(listOf(*signers), commandDataClosure()) + fun command(signer: PublicKey, commandData: CommandData) = _command(listOf(signer), commandData) + + fun verifies(identityService: IdentityService = MOCK_IDENTITY_SERVICE) = _verifies(identityService) + + @JvmOverloads + fun timestamp(time: Instant, notary: PublicKey = DUMMY_NOTARY.owningKey) = + timestamp(TimestampCommand(time, 30.seconds), notary) + @JvmOverloads + fun timestamp(data: TimestampCommand, notary: PublicKey = DUMMY_NOTARY.owningKey) = command(notary, data) + + fun fails(identityService: IdentityService = MOCK_IDENTITY_SERVICE) = failsWith(null, identityService) + infix fun `fails with`(msg: String) = failsWith(msg, MOCK_IDENTITY_SERVICE) +} From 4a89be8785e1248d155552c79f5bc981b4212903 Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Mon, 4 Jul 2016 16:59:49 +0100 Subject: [PATCH 075/114] build: Run integtests after regular ones --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 69f11733df..00cd005810 100644 --- a/build.gradle +++ b/build.gradle @@ -129,7 +129,7 @@ task integrationTest(type: Test) { testClassesDir = sourceSets.integrationTest.output.classesDir classpath = sourceSets.integrationTest.runtimeClasspath } -test.dependsOn(integrationTest) +test.finalizedBy(integrationTest) tasks.withType(Test) { reports.html.destination = file("${reporting.baseDir}/${name}") From 9b36df607e885dbdbc4c1b6f9fee6e77156d211d Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Mon, 4 Jul 2016 17:13:55 +0100 Subject: [PATCH 076/114] core: Remove binding of State type in test dsl --- .../core/testing/LedgerDslInterpreter.kt | 44 ++-- .../com/r3corda/core/testing/TestDsl.kt | 188 +++++++++++------- .../com/r3corda/core/testing/TestUtils.kt | 14 +- .../core/testing/TransactionDslInterpreter.kt | 33 +-- 4 files changed, 163 insertions(+), 116 deletions(-) diff --git a/core/src/main/kotlin/com/r3corda/core/testing/LedgerDslInterpreter.kt b/core/src/main/kotlin/com/r3corda/core/testing/LedgerDslInterpreter.kt index c8b7668e18..b39b39c19c 100644 --- a/core/src/main/kotlin/com/r3corda/core/testing/LedgerDslInterpreter.kt +++ b/core/src/main/kotlin/com/r3corda/core/testing/LedgerDslInterpreter.kt @@ -1,18 +1,21 @@ package com.r3corda.core.testing -import com.r3corda.core.contracts.Attachment -import com.r3corda.core.contracts.ContractState +import com.r3corda.core.contracts.* import com.r3corda.core.crypto.SecureHash -import com.r3corda.core.node.services.IdentityService -import com.r3corda.core.node.services.StorageService -import com.r3corda.core.node.services.testing.MockStorageService -interface LedgerDslInterpreter> { - fun transaction(dsl: TransactionDsl.() -> Unit): Unit - fun nonVerifiedTransaction(dsl: TransactionDsl.() -> Unit): Unit - fun tweak(dsl: LedgerDsl>.() -> Unit) +interface OutputStateLookup { + fun retrieveOutputStateAndRef(clazz: Class, label: String): StateAndRef +} + + + +interface LedgerDslInterpreter : + OutputStateLookup { + fun transaction(transactionLabel: String?, dsl: TransactionDsl.() -> Unit): WireTransaction + fun nonVerifiedTransaction(transactionLabel: String?, dsl: TransactionDsl.() -> Unit): WireTransaction + fun tweak(dsl: LedgerDsl>.() -> Unit) fun attachment(attachment: Attachment): SecureHash - fun _verifies(identityService: IdentityService, storageService: StorageService) + fun verifies() } /** @@ -21,15 +24,18 @@ interface LedgerDslInterpreter, - out LedgerInterpreter: LedgerDslInterpreter + out TransactionInterpreter: TransactionDslInterpreter, + out LedgerInterpreter: LedgerDslInterpreter > (val interpreter: LedgerInterpreter) - : LedgerDslInterpreter> by interpreter { + : LedgerDslInterpreter by interpreter { - @JvmOverloads - fun verifies( - identityService: IdentityService = MOCK_IDENTITY_SERVICE, - storageService: StorageService = MockStorageService() - ) = _verifies(identityService, storageService) + fun transaction(dsl: TransactionDsl.() -> Unit) = transaction(null, dsl) + fun nonVerifiedTransaction(dsl: TransactionDsl.() -> Unit) = + nonVerifiedTransaction(null, dsl) + + inline fun String.outputStateAndRef(): StateAndRef = + retrieveOutputStateAndRef(State::class.java, this) + inline fun String.output(): TransactionState = + outputStateAndRef().state + fun String.outputRef(): StateRef = outputStateAndRef().ref } diff --git a/core/src/main/kotlin/com/r3corda/core/testing/TestDsl.kt b/core/src/main/kotlin/com/r3corda/core/testing/TestDsl.kt index f508ba58fb..e1b6e70f0a 100644 --- a/core/src/main/kotlin/com/r3corda/core/testing/TestDsl.kt +++ b/core/src/main/kotlin/com/r3corda/core/testing/TestDsl.kt @@ -1,23 +1,34 @@ package com.r3corda.core.testing import com.r3corda.core.contracts.* +import com.r3corda.core.crypto.DigitalSignature import com.r3corda.core.crypto.Party import com.r3corda.core.crypto.SecureHash +import com.r3corda.core.crypto.signWithECDSA import com.r3corda.core.node.services.IdentityService import com.r3corda.core.node.services.StorageService +import com.r3corda.core.node.services.testing.MockStorageService +import com.r3corda.core.serialization.serialize +import java.security.KeyPair import java.security.PublicKey import java.util.* -inline fun ledger( - dsl: LedgerDsl, TestLedgerDslInterpreter>.() -> Unit) = - dsl(LedgerDsl(TestLedgerDslInterpreter.create())) +inline fun ledger( + identityService: IdentityService = MOCK_IDENTITY_SERVICE, + storageService: StorageService = MockStorageService(), + dsl: LedgerDsl.() -> Unit +): LedgerDsl { + val ledgerDsl = LedgerDsl(TestLedgerDslInterpreter(identityService, storageService)) + dsl(ledgerDsl) + return ledgerDsl +} @Deprecated( message = "ledger doesn't nest, use tweak", replaceWith = ReplaceWith("tweak"), level = DeprecationLevel.ERROR) -fun TransactionDslInterpreter.ledger( - dsl: LedgerDsl, TestLedgerDslInterpreter>.() -> Unit) { +fun TransactionDslInterpreter.ledger( + dsl: LedgerDsl.() -> Unit) { this.toString() dsl.toString() } @@ -26,8 +37,8 @@ fun TransactionDslInterpreter.ledger( message = "ledger doesn't nest, use tweak", replaceWith = ReplaceWith("tweak"), level = DeprecationLevel.ERROR) -fun LedgerDslInterpreter>.ledger( - dsl: LedgerDsl, TestLedgerDslInterpreter>.() -> Unit) { +fun LedgerDslInterpreter.ledger( + dsl: LedgerDsl.() -> Unit) { this.toString() dsl.toString() } @@ -36,17 +47,16 @@ fun LedgerDslInterpreter( - private val ledgerInterpreter: TestLedgerDslInterpreter, +data class TestTransactionDslInterpreter( + private val ledgerInterpreter: TestLedgerDslInterpreter, private val inputStateRefs: ArrayList = arrayListOf(), internal val outputStates: ArrayList = arrayListOf(), private val attachments: ArrayList = arrayListOf(), private val commands: ArrayList = arrayListOf(), private val signers: LinkedHashSet = LinkedHashSet(), private val transactionType: TransactionType = TransactionType.General() -) : TransactionDslInterpreter { - - private fun copy(): TestTransactionDslInterpreter = +) : TransactionDslInterpreter, OutputStateLookup { + private fun copy(): TestTransactionDslInterpreter = TestTransactionDslInterpreter( ledgerInterpreter = ledgerInterpreter.copy(), inputStateRefs = ArrayList(inputStateRefs), @@ -68,18 +78,18 @@ data class TestTransactionDslInterpreter( ) override fun input(stateLabel: String) { - val notary = stateLabel.output.notary.owningKey - signers.add(notary) - inputStateRefs.add(stateLabel.outputRef) + val stateAndRef = retrieveOutputStateAndRef(ContractState::class.java, stateLabel) + signers.add(stateAndRef.state.notary.owningKey) + inputStateRefs.add(stateAndRef.ref) } override fun input(stateRef: StateRef) { - val notary = ledgerInterpreter.resolveStateRef(stateRef).notary + val notary = ledgerInterpreter.resolveStateRef(stateRef).notary signers.add(notary.owningKey) inputStateRefs.add(stateRef) } - override fun output(label: String?, notary: Party, contractState: State) { + override fun output(label: String?, notary: Party, contractState: ContractState) { outputStates.add(LabeledOutput(label, TransactionState(contractState, notary))) } @@ -92,14 +102,14 @@ data class TestTransactionDslInterpreter( commands.add(Command(commandData, signers)) } - override fun _verifies(identityService: IdentityService) { - val resolvedTransaction = ledgerInterpreter.resolveWireTransaction(toWireTransaction(), identityService) + override fun verifies() { + val resolvedTransaction = ledgerInterpreter.resolveWireTransaction(toWireTransaction()) resolvedTransaction.verify() } - override fun failsWith(expectedMessage: String?, identityService: IdentityService) { + override fun failsWith(expectedMessage: String?) { val exceptionThrown = try { - _verifies(identityService) + verifies() false } catch (exception: Exception) { if (expectedMessage != null) { @@ -110,7 +120,7 @@ data class TestTransactionDslInterpreter( ) } else if (!exceptionMessage.toLowerCase().contains(expectedMessage.toLowerCase())) { throw AssertionError( - "Expected exception containing '$expectedMessage' but raised exception was '$exceptionMessage'" + "Expected exception containing '$expectedMessage' but raised exception was '$exception'" ) } } @@ -122,58 +132,60 @@ data class TestTransactionDslInterpreter( } } - override fun tweak(dsl: TransactionDsl>.() -> Unit) = + override fun tweak(dsl: TransactionDsl.() -> Unit) = dsl(TransactionDsl(copy())) - override fun retrieveOutputStateAndRef(label: String): StateAndRef? = - ledgerInterpreter.labelToOutputStateAndRefs[label] + override fun retrieveOutputStateAndRef(clazz: Class, label: String) = ledgerInterpreter.retrieveOutputStateAndRef(clazz, label) } -class AttachmentResolutionException(val attachmentId: SecureHash) : +class AttachmentResolutionException(attachmentId: SecureHash) : Exception("Attachment with id $attachmentId not found") -data class TestLedgerDslInterpreter private constructor ( - internal val stateClazz: Class, - internal val labelToOutputStateAndRefs: HashMap> = HashMap(), +data class TestLedgerDslInterpreter private constructor ( + private val identityService: IdentityService, + private val storageService: StorageService, + internal val labelToOutputStateAndRefs: HashMap> = HashMap(), private val transactionWithLocations: HashMap = HashMap(), - private val nonVerifiedTransactionWithLocations: HashMap = HashMap(), - private val attachments: HashMap = HashMap() -) : LedgerDslInterpreter> { + private val nonVerifiedTransactionWithLocations: HashMap = HashMap() +) : LedgerDslInterpreter { // We specify [labelToOutputStateAndRefs] just so that Kotlin picks the primary constructor instead of cycling - constructor(stateClazz: Class) : this(stateClazz, labelToOutputStateAndRefs = HashMap()) + constructor(identityService: IdentityService, storageService: StorageService) : this( + identityService, storageService, labelToOutputStateAndRefs = HashMap() + ) companion object { - /** - * Convenience factory to avoid having to pass in the Class - */ - inline fun create() = TestLedgerDslInterpreter(State::class.java) - private fun getCallerLocation(offset: Int): String { val stackTraceElement = Thread.currentThread().stackTrace[3 + offset] return stackTraceElement.toString() } } - private data class WireTransactionWithLocation(val transaction: WireTransaction, val location: String) - private class VerifiesFailed(transactionLocation: String, cause: Throwable) : + internal data class WireTransactionWithLocation( + val label: String?, + val transaction: WireTransaction, + val location: String + ) + class VerifiesFailed(transactionLocation: String, cause: Throwable) : Exception("Transaction defined at ($transactionLocation) didn't verify: $cause", cause) + class TypeMismatch(requested: Class<*>, actual: Class<*>) : + Exception("Actual type $actual is not a subtype of requested type $requested") - internal fun copy(): TestLedgerDslInterpreter = + internal fun copy(): TestLedgerDslInterpreter = TestLedgerDslInterpreter( - stateClazz = stateClazz, + identityService, + storageService, labelToOutputStateAndRefs = HashMap(labelToOutputStateAndRefs), transactionWithLocations = HashMap(transactionWithLocations), - nonVerifiedTransactionWithLocations = HashMap(nonVerifiedTransactionWithLocations), - attachments = HashMap(attachments) + nonVerifiedTransactionWithLocations = HashMap(nonVerifiedTransactionWithLocations) ) - fun resolveWireTransaction(wireTransaction: WireTransaction, identityService: IdentityService): TransactionForVerification { + internal fun resolveWireTransaction(wireTransaction: WireTransaction): TransactionForVerification { return wireTransaction.run { val authenticatedCommands = commands.map { AuthenticatedObject(it.signers, it.signers.mapNotNull { identityService.partyFromKey(it) }, it.value) } - val resolvedInputStates = inputs.map { resolveStateRef(it) } + val resolvedInputStates = inputs.map { resolveStateRef(it) } val resolvedAttachments = attachments.map { resolveAttachment(it) } TransactionForVerification( inputs = resolvedInputStates, @@ -188,30 +200,30 @@ data class TestLedgerDslInterpreter private constructor ( } } - fun resolveStateRef(stateRef: StateRef): TransactionState { + internal inline fun resolveStateRef(stateRef: StateRef): TransactionState { val transactionWithLocation = transactionWithLocations[stateRef.txhash] ?: nonVerifiedTransactionWithLocations[stateRef.txhash] ?: throw TransactionResolutionException(stateRef.txhash) val output = transactionWithLocation.transaction.outputs[stateRef.index] - return if (stateClazz.isInstance(output.data)) @Suppress("UNCHECKED_CAST") { + return if (State::class.java.isAssignableFrom(output.data.javaClass)) @Suppress("UNCHECKED_CAST") { output as TransactionState } else { - throw IllegalArgumentException("Referenced state is of another type than requested") + throw TypeMismatch(requested = State::class.java, actual = output.data.javaClass) } } - fun resolveAttachment(attachmentId: SecureHash): Attachment = - attachments[attachmentId] ?: throw AttachmentResolutionException(attachmentId) + internal fun resolveAttachment(attachmentId: SecureHash): Attachment = + storageService.attachments.openAttachment(attachmentId) ?: throw AttachmentResolutionException(attachmentId) - private fun interpretTransactionDsl(dsl: TransactionDsl>.() -> Unit): - TestTransactionDslInterpreter { + private fun interpretTransactionDsl(dsl: TransactionDsl.() -> Unit): + TestTransactionDslInterpreter { val transactionInterpreter = TestTransactionDslInterpreter(this) dsl(TransactionDsl(transactionInterpreter)) return transactionInterpreter } - private fun toTransactionGroup(identityService: IdentityService, storageService: StorageService): TransactionGroup { + fun toTransactionGroup(): TransactionGroup { val ledgerTransactions = transactionWithLocations.map { it.value.transaction.toLedgerTransaction(identityService, storageService.attachments) } @@ -221,10 +233,23 @@ data class TestLedgerDslInterpreter private constructor ( return TransactionGroup(ledgerTransactions.toSet(), nonVerifiedLedgerTransactions.toSet()) } + fun transactionName(transactionHash: SecureHash): String? { + val transactionWithLocation = transactionWithLocations[transactionHash] + return if (transactionWithLocation != null) { + transactionWithLocation.label ?: "TX[${transactionWithLocation.location}]" + } else { + null + } + } + + fun outputToLabel(state: ContractState): String? = + labelToOutputStateAndRefs.filter { it.value.state.data == state }.keys.firstOrNull() + private fun recordTransactionWithTransactionMap( - dsl: TransactionDsl>.() -> Unit, + transactionLabel: String?, + dsl: TransactionDsl.() -> Unit, transactionMap: HashMap = HashMap() - ) { + ): WireTransaction { val transactionLocation = getCallerLocation(3) val transactionInterpreter = interpretTransactionDsl(dsl) // Create the WireTransaction @@ -237,38 +262,67 @@ data class TestLedgerDslInterpreter private constructor ( } transactionMap[wireTransaction.serialized.hash] = - WireTransactionWithLocation(wireTransaction, transactionLocation) + WireTransactionWithLocation(transactionLabel, wireTransaction, transactionLocation) + return wireTransaction } - override fun transaction(dsl: TransactionDsl>.() -> Unit) = - recordTransactionWithTransactionMap(dsl, transactionWithLocations) + override fun transaction(transactionLabel: String?, dsl: TransactionDsl.() -> Unit) = + recordTransactionWithTransactionMap(transactionLabel, dsl, transactionWithLocations) - override fun nonVerifiedTransaction(dsl: TransactionDsl>.() -> Unit) = - recordTransactionWithTransactionMap(dsl, nonVerifiedTransactionWithLocations) + override fun nonVerifiedTransaction(transactionLabel: String?, dsl: TransactionDsl.() -> Unit) = + recordTransactionWithTransactionMap(transactionLabel, dsl, nonVerifiedTransactionWithLocations) override fun tweak( - dsl: LedgerDsl, - LedgerDslInterpreter>>.() -> Unit) = + dsl: LedgerDsl>.() -> Unit) = dsl(LedgerDsl(copy())) override fun attachment(attachment: Attachment): SecureHash { - attachments[attachment.id] = attachment + storageService.attachments.importAttachment(attachment.open()) return attachment.id } - override fun _verifies(identityService: IdentityService, storageService: StorageService) { - val transactionGroup = toTransactionGroup(identityService, storageService) + override fun verifies() { + val transactionGroup = toTransactionGroup() try { transactionGroup.verify() } catch (exception: TransactionVerificationException) { throw VerifiesFailed(transactionWithLocations[exception.tx.origHash]?.location ?: "", exception) } } + + override fun retrieveOutputStateAndRef(clazz: Class, label: String): StateAndRef { + val stateAndRef = labelToOutputStateAndRefs[label] + if (stateAndRef == null) { + throw IllegalArgumentException("State with label '$label' was not found") + } else if (!clazz.isAssignableFrom(stateAndRef.state.data.javaClass)) { + throw TypeMismatch(requested = clazz, actual = stateAndRef.state.data.javaClass) + } else { + @Suppress("UNCHECKED_CAST") + return stateAndRef as StateAndRef + } + } +} + +fun signAll(transactionsToSign: List, vararg extraKeys: KeyPair): List { + return transactionsToSign.map { wtx -> + val allPubKeys = wtx.signers.toMutableSet() + val bits = wtx.serialize() + require(bits == wtx.serialized) + val signatures = ArrayList() + for (key in ALL_TEST_KEYS + extraKeys) { + if (allPubKeys.contains(key.public)) { + signatures += key.signWithECDSA(bits) + allPubKeys -= key.public + } + } + SignedTransaction(bits, signatures) + } } fun main(args: Array) { - ledger { + ledger { nonVerifiedTransaction { output("hello") { DummyLinearState() } } diff --git a/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt b/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt index d5148803e6..9266fe1069 100644 --- a/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt +++ b/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt @@ -6,7 +6,6 @@ import com.google.common.base.Throwables import com.google.common.net.HostAndPort import com.r3corda.core.contracts.* import com.r3corda.core.crypto.* -import com.r3corda.core.node.services.IdentityService import com.r3corda.core.node.services.testing.MockIdentityService import com.r3corda.core.node.services.testing.MockStorageService import com.r3corda.core.seconds @@ -219,22 +218,21 @@ open class TransactionForTest : AbstractTransactionForTest() { } fun input(s: ContractState) = input { s } - protected fun runCommandsAndVerify(time: Instant) { + protected fun runCommandsAndVerify() { val cmds = commandsToAuthenticatedObjects() val tx = TransactionForVerification(inStates, outStates.map { it.state }, emptyList(), cmds, SecureHash.Companion.randomSHA256(), signers.toList(), type) tx.verify() } - @JvmOverloads - fun accepts(time: Instant = TEST_TX_TIME): LastLineShouldTestForAcceptOrFailure { - runCommandsAndVerify(time) + fun accepts(): LastLineShouldTestForAcceptOrFailure { + runCommandsAndVerify() return LastLineShouldTestForAcceptOrFailure.Token } @JvmOverloads - fun rejects(withMessage: String? = null, time: Instant = TEST_TX_TIME): LastLineShouldTestForAcceptOrFailure { + fun rejects(withMessage: String? = null): LastLineShouldTestForAcceptOrFailure { val r = try { - runCommandsAndVerify(time) + runCommandsAndVerify() false } catch (e: Exception) { val m = e.message @@ -300,7 +298,7 @@ open class TransactionForTest : AbstractTransactionForTest() { } } -class TransactionGroupDSL(private val stateType: Class) { +class TransactionGroupDSL(private val stateType: Class) { open inner class WireTransactionDSL : AbstractTransactionForTest() { private val inStates = ArrayList() diff --git a/core/src/main/kotlin/com/r3corda/core/testing/TransactionDslInterpreter.kt b/core/src/main/kotlin/com/r3corda/core/testing/TransactionDslInterpreter.kt index ac8eba0adf..2822f830e1 100644 --- a/core/src/main/kotlin/com/r3corda/core/testing/TransactionDslInterpreter.kt +++ b/core/src/main/kotlin/com/r3corda/core/testing/TransactionDslInterpreter.kt @@ -15,50 +15,39 @@ import java.time.Instant * TODO: Move the [State] binding to the primitives' level to allow different State types, use reflection to check types * dynamically, come up with a substitute for primitives relying on early bind */ -interface TransactionDslInterpreter { +interface TransactionDslInterpreter : OutputStateLookup { fun input(stateLabel: String) fun input(stateRef: StateRef) - fun output(label: String?, notary: Party, contractState: State) + fun output(label: String?, notary: Party, contractState: ContractState) fun attachment(attachmentId: SecureHash) fun _command(signers: List, commandData: CommandData) - fun _verifies(identityService: IdentityService) - fun failsWith(expectedMessage: String?, identityService: IdentityService) - fun tweak(dsl: TransactionDsl>.() -> Unit) - fun retrieveOutputStateAndRef(label: String): StateAndRef? - - val String.outputStateAndRef: StateAndRef - get() = retrieveOutputStateAndRef(this) ?: throw IllegalArgumentException("State with label '$this' was not found") - val String.output: TransactionState - get() = outputStateAndRef.state - val String.outputRef: StateRef - get() = outputStateAndRef.ref + fun verifies() + fun failsWith(expectedMessage: String?) + fun tweak(dsl: TransactionDsl.() -> Unit) } class TransactionDsl< - State: ContractState, - out TransactionInterpreter: TransactionDslInterpreter + out TransactionInterpreter: TransactionDslInterpreter > (val interpreter: TransactionInterpreter) - : TransactionDslInterpreter by interpreter { + : TransactionDslInterpreter by interpreter { // Convenience functions - fun output(label: String? = null, notary: Party = DUMMY_NOTARY, contractStateClosure: () -> State) = + fun output(label: String? = null, notary: Party = DUMMY_NOTARY, contractStateClosure: () -> ContractState) = output(label, notary, contractStateClosure()) @JvmOverloads - fun output(label: String? = null, contractState: State) = output(label, DUMMY_NOTARY, contractState) + fun output(label: String? = null, contractState: ContractState) = output(label, DUMMY_NOTARY, contractState) fun command(vararg signers: PublicKey, commandDataClosure: () -> CommandData) = _command(listOf(*signers), commandDataClosure()) fun command(signer: PublicKey, commandData: CommandData) = _command(listOf(signer), commandData) - fun verifies(identityService: IdentityService = MOCK_IDENTITY_SERVICE) = _verifies(identityService) - @JvmOverloads fun timestamp(time: Instant, notary: PublicKey = DUMMY_NOTARY.owningKey) = timestamp(TimestampCommand(time, 30.seconds), notary) @JvmOverloads fun timestamp(data: TimestampCommand, notary: PublicKey = DUMMY_NOTARY.owningKey) = command(notary, data) - fun fails(identityService: IdentityService = MOCK_IDENTITY_SERVICE) = failsWith(null, identityService) - infix fun `fails with`(msg: String) = failsWith(msg, MOCK_IDENTITY_SERVICE) + fun fails() = failsWith(null) + infix fun `fails with`(msg: String) = failsWith(msg) } From cde315aca9209f23d52d059c7190f3d83382b7df Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Mon, 4 Jul 2016 17:15:02 +0100 Subject: [PATCH 077/114] contracts, node: Port CommercialPaperTests, TwoPartyTradeProtocolTests and GroupToGraphConversion to use new dsl --- .../r3corda/contracts/CommercialPaperTests.kt | 165 +++++++++--------- .../messaging/TwoPartyTradeProtocolTests.kt | 65 +++---- .../node/visualiser/GroupToGraphConversion.kt | 17 +- 3 files changed, 122 insertions(+), 125 deletions(-) diff --git a/contracts/src/test/kotlin/com/r3corda/contracts/CommercialPaperTests.kt b/contracts/src/test/kotlin/com/r3corda/contracts/CommercialPaperTests.kt index e7f0fb3083..e9a5f1b136 100644 --- a/contracts/src/test/kotlin/com/r3corda/contracts/CommercialPaperTests.kt +++ b/contracts/src/test/kotlin/com/r3corda/contracts/CommercialPaperTests.kt @@ -17,10 +17,10 @@ import kotlin.test.assertFailsWith import kotlin.test.assertTrue interface ICommercialPaperTestTemplate { - open fun getPaper(): ICommercialPaperState - open fun getIssueCommand(): CommandData - open fun getRedeemCommand(): CommandData - open fun getMoveCommand(): CommandData + fun getPaper(): ICommercialPaperState + fun getIssueCommand(): CommandData + fun getRedeemCommand(): CommandData + fun getMoveCommand(): CommandData } class JavaCommercialPaperTest() : ICommercialPaperTestTemplate { @@ -63,81 +63,122 @@ class CommercialPaperTestsGeneric { val issuer = MEGA_CORP.ref(123) @Test - fun ok() { - trade().verify() - } + fun `trade lifecycle test`() { + val someProfits = 1200.DOLLARS `issued by` issuer + ledger { + nonVerifiedTransaction { + output("alice's $900", 900.DOLLARS.CASH `issued by` issuer `owned by` ALICE_PUBKEY) + output("some profits", someProfits.STATE `owned by` MEGA_CORP_PUBKEY) + } - @Test - fun `not matured at redemption`() { - trade(redemptionTime = TEST_TX_TIME + 2.days).expectFailureOfTx(3, "must have matured") + // Some CP is issued onto the ledger by MegaCorp. + transaction("Issuance") { + output("paper") { thisTest.getPaper() } + command(MEGA_CORP_PUBKEY) { thisTest.getIssueCommand() } + timestamp(TEST_TX_TIME) + } + + // The CP is sold to alice for her $900, $100 less than the face value. At 10% interest after only 7 days, + // that sounds a bit too good to be true! + transaction("Trade") { + input("paper") + input("alice's $900") + output("borrowed $900") { 900.DOLLARS.CASH `issued by` issuer `owned by` MEGA_CORP_PUBKEY } + output("alice's paper") { "paper".output().data `owned by` ALICE_PUBKEY } + command(ALICE_PUBKEY) { Cash.Commands.Move() } + command(MEGA_CORP_PUBKEY) { thisTest.getMoveCommand() } + } + + // Time passes, and Alice redeem's her CP for $1000, netting a $100 profit. MegaCorp has received $1200 + // as a single payment from somewhere and uses it to pay Alice off, keeping the remaining $200 as change. + transaction("Redemption") { + input("alice's paper") + input("some profits") + + fun TransactionDsl.outputs(aliceGetsBack: Amount>) { + output("Alice's profit") { aliceGetsBack.STATE `owned by` ALICE_PUBKEY } + output("Change") { (someProfits - aliceGetsBack).STATE `owned by` MEGA_CORP_PUBKEY } + } + + command(MEGA_CORP_PUBKEY) { Cash.Commands.Move() } + command(ALICE_PUBKEY) { thisTest.getRedeemCommand() } + + tweak { + outputs(700.DOLLARS `issued by` issuer) + timestamp(TEST_TX_TIME + 8.days) + this `fails with` "received amount equals the face value" + } + outputs(1000.DOLLARS `issued by` issuer) + + + tweak { + timestamp(TEST_TX_TIME + 2.days) + this `fails with` "must have matured" + } + timestamp(TEST_TX_TIME + 8.days) + + tweak { + output { "paper".output().data } + this `fails with` "must be destroyed" + } + + verifies() + } + } } @Test fun `key mismatch at issue`() { - transactionGroup { + ledger { transaction { output { thisTest.getPaper() } - arg(DUMMY_PUBKEY_1) { thisTest.getIssueCommand() } + command(DUMMY_PUBKEY_1) { thisTest.getIssueCommand() } timestamp(TEST_TX_TIME) + this `fails with` "signed by the claimed issuer" } - - expectFailureOfTx(1, "signed by the claimed issuer") } } @Test fun `face value is not zero`() { - transactionGroup { + ledger { transaction { output { thisTest.getPaper().withFaceValue(0.DOLLARS `issued by` issuer) } - arg(MEGA_CORP_PUBKEY) { thisTest.getIssueCommand() } + command(MEGA_CORP_PUBKEY) { thisTest.getIssueCommand() } timestamp(TEST_TX_TIME) + this `fails with` "face value is not zero" } - - expectFailureOfTx(1, "face value is not zero") } } @Test fun `maturity date not in the past`() { - transactionGroup { + ledger { transaction { output { thisTest.getPaper().withMaturityDate(TEST_TX_TIME - 10.days) } - arg(MEGA_CORP_PUBKEY) { thisTest.getIssueCommand() } + command(MEGA_CORP_PUBKEY) { thisTest.getIssueCommand() } timestamp(TEST_TX_TIME) + this `fails with` "maturity date is not in the past" } - - expectFailureOfTx(1, "maturity date is not in the past") } } @Test fun `issue cannot replace an existing state`() { - transactionGroup { - roots { - transaction(thisTest.getPaper() `with notary` DUMMY_NOTARY label "paper") + ledger { + nonVerifiedTransaction { + output("paper") { thisTest.getPaper() } } transaction { input("paper") output { thisTest.getPaper() } - arg(MEGA_CORP_PUBKEY) { thisTest.getIssueCommand() } + command(MEGA_CORP_PUBKEY) { thisTest.getIssueCommand() } timestamp(TEST_TX_TIME) + this `fails with` "there is no input state" } - - expectFailureOfTx(1, "there is no input state") } } - @Test - fun `did not receive enough money at redemption`() { - trade(aliceGetsBack = 700.DOLLARS `issued by` issuer).expectFailureOfTx(3, "received amount equals the face value") - } - - @Test - fun `paper must be destroyed by redemption`() { - trade(destroyPaperAtRedemption = false).expectFailureOfTx(3, "must be destroyed") - } - fun cashOutputsToWallet(vararg outputs: TransactionState): Pair>> { val ltx = LedgerTransaction(emptyList(), listOf(*outputs), emptyList(), emptyList(), SecureHash.randomSHA256(), emptyList(), TransactionType.General()) return Pair(ltx, outputs.mapIndexed { index, state -> StateAndRef(state, StateRef(ltx.id, index)) }) @@ -199,52 +240,4 @@ class CommercialPaperTestsGeneric { TransactionGroup(setOf(issueTX, moveTX, validRedemption), setOf(corpWalletTX, alicesWalletTX)).verify() } - - // Generate a trade lifecycle with various parameters. - fun trade(redemptionTime: Instant = TEST_TX_TIME + 8.days, - aliceGetsBack: Amount> = 1000.DOLLARS `issued by` issuer, - destroyPaperAtRedemption: Boolean = true): TransactionGroupDSL { - val someProfits = 1200.DOLLARS `issued by` issuer - return transactionGroupFor() { - roots { - transaction(900.DOLLARS.CASH `issued by` issuer `owned by` ALICE_PUBKEY `with notary` DUMMY_NOTARY label "alice's $900") - transaction(someProfits.STATE `owned by` MEGA_CORP_PUBKEY `with notary` DUMMY_NOTARY label "some profits") - } - - // Some CP is issued onto the ledger by MegaCorp. - transaction("Issuance") { - output("paper") { thisTest.getPaper() } - arg(MEGA_CORP_PUBKEY) { thisTest.getIssueCommand() } - timestamp(TEST_TX_TIME) - } - - // The CP is sold to alice for her $900, $100 less than the face value. At 10% interest after only 7 days, - // that sounds a bit too good to be true! - transaction("Trade") { - input("paper") - input("alice's $900") - output("borrowed $900") { 900.DOLLARS.CASH `issued by` issuer `owned by` MEGA_CORP_PUBKEY } - output("alice's paper") { "paper".output.data `owned by` ALICE_PUBKEY } - arg(ALICE_PUBKEY) { Cash.Commands.Move() } - arg(MEGA_CORP_PUBKEY) { thisTest.getMoveCommand() } - } - - // Time passes, and Alice redeem's her CP for $1000, netting a $100 profit. MegaCorp has received $1200 - // as a single payment from somewhere and uses it to pay Alice off, keeping the remaining $200 as change. - transaction("Redemption") { - input("alice's paper") - input("some profits") - - output("Alice's profit") { aliceGetsBack.STATE `owned by` ALICE_PUBKEY } - output("Change") { (someProfits - aliceGetsBack).STATE `owned by` MEGA_CORP_PUBKEY } - if (!destroyPaperAtRedemption) - output { "paper".output.data } - - arg(MEGA_CORP_PUBKEY) { Cash.Commands.Move() } - arg(ALICE_PUBKEY) { thisTest.getRedeemCommand() } - - timestamp(redemptionTime) - } - } - } } diff --git a/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt b/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt index 1b8de5b263..bdc365d599 100644 --- a/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt +++ b/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt @@ -86,7 +86,9 @@ class TwoPartyTradeProtocolTests { // we run in the unit test thread exclusively to speed things up, ensure deterministic results and // allow interruption half way through. net = MockNetwork(false, true) - transactionGroupFor { + + ledger { + val notaryNode = net.createNotaryNode(DUMMY_NOTARY.name, DUMMY_NOTARY_KEY) val aliceNode = net.createPartyNode(notaryNode.info, ALICE.name, ALICE_KEY) val bobNode = net.createPartyNode(notaryNode.info, BOB.name, BOB_KEY) @@ -113,7 +115,7 @@ class TwoPartyTradeProtocolTests { aliceNode.smm, notaryNode.info, bobNode.info.identity, - lookup("alice's paper"), + "alice's paper".outputStateAndRef(), 1000.DOLLARS `issued by` issuer, ALICE_KEY, buyerSessionID @@ -133,7 +135,8 @@ class TwoPartyTradeProtocolTests { @Test fun `shutdown and restore`() { - transactionGroupFor { + + ledger { val notaryNode = net.createNotaryNode(DUMMY_NOTARY.name, DUMMY_NOTARY_KEY) val aliceNode = net.createPartyNode(notaryNode.info, ALICE.name, ALICE_KEY) var bobNode = net.createPartyNode(notaryNode.info, BOB.name, BOB_KEY) @@ -155,7 +158,7 @@ class TwoPartyTradeProtocolTests { aliceNode.smm, notaryNode.info, bobNode.info.identity, - lookup("alice's paper"), + "alice's paper".outputStateAndRef(), 1000.DOLLARS `issued by` issuer, ALICE_KEY, buyerSessionID @@ -246,7 +249,7 @@ class TwoPartyTradeProtocolTests { @Test fun `check dependencies of sale asset are resolved`() { - transactionGroupFor { + ledger { val notaryNode = net.createNotaryNode(DUMMY_NOTARY.name, DUMMY_NOTARY_KEY) val aliceNode = makeNodeWithTracking(notaryNode.info, ALICE.name, ALICE_KEY) val bobNode = makeNodeWithTracking(notaryNode.info, BOB.name, BOB_KEY) @@ -275,7 +278,7 @@ class TwoPartyTradeProtocolTests { aliceNode.smm, notaryNode.info, bobNode.info.identity, - lookup("alice's paper"), + "alice's paper".outputStateAndRef(), 1000.DOLLARS `issued by` issuer, ALICE_KEY, buyerSessionID @@ -350,19 +353,19 @@ class TwoPartyTradeProtocolTests { @Test fun `dependency with error on buyer side`() { - transactionGroupFor { + ledger { runWithError(true, false, "at least one asset input") } } @Test fun `dependency with error on seller side`() { - transactionGroupFor { + ledger { runWithError(false, true, "must be timestamped") } } - private fun TransactionGroupDSL.runWithError(bobError: Boolean, aliceError: Boolean, + private fun LedgerDsl>.runWithError(bobError: Boolean, aliceError: Boolean, expectedMessageSubstring: String) { val notaryNode = net.createNotaryNode(DUMMY_NOTARY.name, DUMMY_NOTARY_KEY) val aliceNode = net.createPartyNode(notaryNode.info, ALICE.name, ALICE_KEY) @@ -385,7 +388,7 @@ class TwoPartyTradeProtocolTests { aliceNode.smm, notaryNode.info, bobNode.info.identity, - lookup("alice's paper"), + "alice's paper".outputStateAndRef(), 1000.DOLLARS `issued by` issuer, ALICE_KEY, buyerSessionID @@ -411,9 +414,10 @@ class TwoPartyTradeProtocolTests { assertTrue(e.cause!!.cause!!.message!!.contains(expectedMessageSubstring)) } - private fun TransactionGroupDSL.insertFakeTransactions(wtxToSign: List, - services: ServiceHub, - vararg extraKeys: KeyPair): Map { + private fun insertFakeTransactions( + wtxToSign: List, + services: ServiceHub, + vararg extraKeys: KeyPair): Map { val signed: List = signAll(wtxToSign, *extraKeys) services.recordTransactions(signed) val validatedTransactions = services.storageService.validatedTransactions @@ -423,9 +427,10 @@ class TwoPartyTradeProtocolTests { return signed.associateBy { it.id } } - private fun TransactionGroupDSL.fillUpForBuyer(withError: Boolean, - owner: PublicKey = BOB_PUBKEY, - issuer: PartyAndReference = MEGA_CORP.ref(1)): Pair> { + private fun LedgerDsl>.fillUpForBuyer( + withError: Boolean, + owner: PublicKey = BOB_PUBKEY, + issuer: PartyAndReference = MEGA_CORP.ref(1)): Pair> { // Bob (Buyer) has some cash he got from the Bank of Elbonia, Alice (Seller) has some commercial paper she // wants to sell to Bob. @@ -434,7 +439,7 @@ class TwoPartyTradeProtocolTests { output("elbonian money 1") { 800.DOLLARS.CASH `issued by` issuer `owned by` MEGA_CORP_PUBKEY } output("elbonian money 2") { 1000.DOLLARS.CASH `issued by` issuer `owned by` MEGA_CORP_PUBKEY } if (!withError) - arg(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() } + command(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() } timestamp(TEST_TX_TIME) } @@ -442,44 +447,44 @@ class TwoPartyTradeProtocolTests { val bc1 = transaction { input("elbonian money 1") output("bob cash 1") { 800.DOLLARS.CASH `issued by` issuer `owned by` owner } - arg(MEGA_CORP_PUBKEY) { Cash.Commands.Move() } + command(MEGA_CORP_PUBKEY) { Cash.Commands.Move() } } val bc2 = transaction { input("elbonian money 2") output("bob cash 2") { 300.DOLLARS.CASH `issued by` issuer `owned by` owner } output { 700.DOLLARS.CASH `issued by` issuer `owned by` MEGA_CORP_PUBKEY } // Change output. - arg(MEGA_CORP_PUBKEY) { Cash.Commands.Move() } + command(MEGA_CORP_PUBKEY) { Cash.Commands.Move() } } - val wallet = Wallet(listOf>(lookup("bob cash 1"), lookup("bob cash 2"))) + val wallet = Wallet(listOf("bob cash 1".outputStateAndRef(), "bob cash 2".outputStateAndRef())) return Pair(wallet, listOf(eb1, bc1, bc2)) } - private fun TransactionGroupDSL.fillUpForSeller(withError: Boolean, - owner: PublicKey, - amount: Amount>, - notary: Party, - attachmentID: SecureHash?): Pair> { + private fun LedgerDsl>.fillUpForSeller( + withError: Boolean, + owner: PublicKey, + amount: Amount>, + notary: Party, + attachmentID: SecureHash?): Pair> { val ap = transaction { output("alice's paper") { CommercialPaper.State(MEGA_CORP.ref(1, 2, 3), owner, amount, TEST_TX_TIME + 7.days) } - arg(MEGA_CORP_PUBKEY) { CommercialPaper.Commands.Issue() } + command(MEGA_CORP_PUBKEY) { CommercialPaper.Commands.Issue() } if (!withError) - arg(notary.owningKey) { TimestampCommand(TEST_TX_TIME, 30.seconds) } + command(notary.owningKey) { TimestampCommand(TEST_TX_TIME, 30.seconds) } if (attachmentID != null) attachment(attachmentID) } - val wallet = Wallet(listOf>(lookup("alice's paper"))) + val wallet = Wallet(listOf("alice's paper".outputStateAndRef())) return Pair(wallet, listOf(ap)) } - class RecordingTransactionStorage(val delegate: TransactionStorage) : TransactionStorage { - val records = Collections.synchronizedList(ArrayList()) + val records: MutableList = Collections.synchronizedList(ArrayList()) override fun addTransaction(transaction: SignedTransaction) { records.add(TxRecord.Add(transaction)) diff --git a/node/src/test/kotlin/com/r3corda/node/visualiser/GroupToGraphConversion.kt b/node/src/test/kotlin/com/r3corda/node/visualiser/GroupToGraphConversion.kt index 9cb29a4e18..ae7ca111b2 100644 --- a/node/src/test/kotlin/com/r3corda/node/visualiser/GroupToGraphConversion.kt +++ b/node/src/test/kotlin/com/r3corda/node/visualiser/GroupToGraphConversion.kt @@ -2,35 +2,34 @@ package com.r3corda.node.visualiser import com.r3corda.core.contracts.CommandData import com.r3corda.core.contracts.ContractState -import com.r3corda.core.contracts.TransactionState import com.r3corda.core.crypto.SecureHash -import com.r3corda.core.testing.TransactionGroupDSL +import com.r3corda.core.testing.* import org.graphstream.graph.Edge import org.graphstream.graph.Node import org.graphstream.graph.implementations.SingleGraph import kotlin.reflect.memberProperties -class GraphVisualiser(val dsl: TransactionGroupDSL) { +class GraphVisualiser(val dsl: LedgerDsl) { companion object { val css = GraphVisualiser::class.java.getResourceAsStream("graph.css").bufferedReader().readText() } fun convert(): SingleGraph { - val tg = dsl.toTransactionGroup() + val tg = dsl.interpreter.toTransactionGroup() val graph = createGraph("Transaction group", css) // Map all the transactions, including the bogus non-verified ones (with no inputs) to graph nodes. for ((txIndex, tx) in (tg.transactions + tg.nonVerifiedRoots).withIndex()) { val txNode = graph.addNode("tx$txIndex") if (tx !in tg.nonVerifiedRoots) - txNode.label = dsl.labelForTransaction(tx).let { it ?: "TX ${tx.id.prefixChars()}" } + txNode.label = dsl.interpreter.transactionName(tx.id).let { it ?: "TX[${tx.id.prefixChars()}]" } txNode.styleClass = "tx" // Now create a vertex for each output state. for (outIndex in tx.outputs.indices) { val node = graph.addNode(tx.outRef(outIndex).ref.toString()) val state = tx.outputs[outIndex] - node.label = stateToLabel(state) + node.label = stateToLabel(state.data) node.styleClass = stateToCSSClass(state.data) + ",state" node.setAttribute("state", state) val edge = graph.addEdge("tx$txIndex-out$outIndex", txNode, node, true) @@ -56,8 +55,8 @@ class GraphVisualiser(val dsl: TransactionGroupDSL) { return graph } - private fun stateToLabel(state: TransactionState<*>): String { - return dsl.labelForState(state) ?: stateToTypeName(state.data) + private fun stateToLabel(state: ContractState): String { + return dsl.interpreter.outputToLabel(state) ?: stateToTypeName(state) } private fun commandToTypeName(state: CommandData) = state.javaClass.canonicalName.removePrefix("contracts.").replace('$', '.') @@ -73,4 +72,4 @@ class GraphVisualiser(val dsl: TransactionGroupDSL) { } }) } -} \ No newline at end of file +} From cb47e00feb7998c39fefea0ed15c46c641f661f6 Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Mon, 4 Jul 2016 18:48:48 +0100 Subject: [PATCH 078/114] core: Add convenience input(), remove TransactionGroupDSL --- .../core/testing/LedgerDslInterpreter.kt | 8 + .../com/r3corda/core/testing/TestDsl.kt | 14 +- .../com/r3corda/core/testing/TestUtils.kt | 149 ------------------ .../core/testing/TransactionDslInterpreter.kt | 3 +- .../core/contracts/TransactionGroupTests.kt | 17 +- 5 files changed, 21 insertions(+), 170 deletions(-) diff --git a/core/src/main/kotlin/com/r3corda/core/testing/LedgerDslInterpreter.kt b/core/src/main/kotlin/com/r3corda/core/testing/LedgerDslInterpreter.kt index b39b39c19c..6a61b75d17 100644 --- a/core/src/main/kotlin/com/r3corda/core/testing/LedgerDslInterpreter.kt +++ b/core/src/main/kotlin/com/r3corda/core/testing/LedgerDslInterpreter.kt @@ -38,4 +38,12 @@ class LedgerDsl< inline fun String.output(): TransactionState = outputStateAndRef().state fun String.outputRef(): StateRef = outputStateAndRef().ref + + fun TransactionDslInterpreter.input(state: ContractState) { + val transaction = nonVerifiedTransaction { + output { state } + } + input(transaction.outRef(0).ref) + } + fun TransactionDslInterpreter.input(stateClosure: () -> ContractState) = input(stateClosure()) } diff --git a/core/src/main/kotlin/com/r3corda/core/testing/TestDsl.kt b/core/src/main/kotlin/com/r3corda/core/testing/TestDsl.kt index e1b6e70f0a..ea251fe0ca 100644 --- a/core/src/main/kotlin/com/r3corda/core/testing/TestDsl.kt +++ b/core/src/main/kotlin/com/r3corda/core/testing/TestDsl.kt @@ -58,7 +58,7 @@ data class TestTransactionDslInterpreter( ) : TransactionDslInterpreter, OutputStateLookup { private fun copy(): TestTransactionDslInterpreter = TestTransactionDslInterpreter( - ledgerInterpreter = ledgerInterpreter.copy(), + ledgerInterpreter = ledgerInterpreter, inputStateRefs = ArrayList(inputStateRefs), outputStates = ArrayList(outputStates), attachments = ArrayList(attachments), @@ -77,12 +77,6 @@ data class TestTransactionDslInterpreter( type = transactionType ) - override fun input(stateLabel: String) { - val stateAndRef = retrieveOutputStateAndRef(ContractState::class.java, stateLabel) - signers.add(stateAndRef.state.notary.owningKey) - inputStateRefs.add(stateAndRef.ref) - } - override fun input(stateRef: StateRef) { val notary = ledgerInterpreter.resolveStateRef(stateRef).notary signers.add(notary.owningKey) @@ -109,7 +103,7 @@ data class TestTransactionDslInterpreter( override fun failsWith(expectedMessage: String?) { val exceptionThrown = try { - verifies() + this.verifies() false } catch (exception: Exception) { if (expectedMessage != null) { @@ -149,6 +143,8 @@ data class TestLedgerDslInterpreter private constructor ( private val nonVerifiedTransactionWithLocations: HashMap = HashMap() ) : LedgerDslInterpreter { + val wireTransactions: List get() = transactionWithLocations.values.map { it.transaction } + // We specify [labelToOutputStateAndRefs] just so that Kotlin picks the primary constructor instead of cycling constructor(identityService: IdentityService, storageService: StorageService) : this( identityService, storageService, labelToOutputStateAndRefs = HashMap() @@ -344,6 +340,6 @@ fun main(args: Array) { } } - verifies() + this.verifies() } } diff --git a/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt b/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt index 9266fe1069..69f0fbe5df 100644 --- a/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt +++ b/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt @@ -297,152 +297,3 @@ open class TransactionForTest : AbstractTransactionForTest() { return result } } - -class TransactionGroupDSL(private val stateType: Class) { - open inner class WireTransactionDSL : AbstractTransactionForTest() { - private val inStates = ArrayList() - - fun input(label: String) { - val notaryKey = label.output.notary.owningKey - signers.add(notaryKey) - inStates.add(label.outputRef) - } - - fun toWireTransaction() = WireTransaction(inStates, attachments, outStates.map { it.state }, commands, signers.toList(), type) - } - - val String.output: TransactionState - get() = labelToOutputs[this] ?: throw IllegalArgumentException("State with label '$this' was not found") - val String.outputRef: StateRef get() = labelToRefs[this] ?: throw IllegalArgumentException("Unknown label \"$this\"") - - fun lookup(label: String): StateAndRef { - val output = label.output - val newOutput = TransactionState(output.data as C, output.notary) - return StateAndRef(newOutput, label.outputRef) - } - - private inner class InternalWireTransactionDSL : WireTransactionDSL() { - fun finaliseAndInsertLabels(): WireTransaction { - val wtx = toWireTransaction() - for ((index, labelledState) in outStates.withIndex()) { - if (labelledState.label != null) { - labelToRefs[labelledState.label] = StateRef(wtx.id, index) - if (stateType.isInstance(labelledState.state.data)) { - labelToOutputs[labelledState.label] = labelledState.state as TransactionState - } - outputsToLabels[labelledState.state] = labelledState.label - } - } - return wtx - } - } - - private val rootTxns = ArrayList() - private val labelToRefs = HashMap() - private val labelToOutputs = HashMap>() - private val outputsToLabels = HashMap, String>() - - fun labelForState(output: TransactionState<*>): String? = outputsToLabels[output] - - inner class Roots { - fun transaction(vararg outputStates: LabeledOutput): Roots { - val outs = outputStates.map { it.state } - val wtx = WireTransaction(emptyList(), emptyList(), outs, emptyList(), emptyList(), TransactionType.General()) - for ((index, state) in outputStates.withIndex()) { - val label = state.label!! - labelToRefs[label] = StateRef(wtx.id, index) - outputsToLabels[state.state] = label - labelToOutputs[label] = state.state as TransactionState - } - rootTxns.add(wtx) - return this - } - - /** - * Note: Don't delete, this is intended to trigger compiler diagnostic when the DSL primitive is used in the wrong place - */ - @Deprecated("Does not nest ", level = DeprecationLevel.ERROR) - fun roots(body: Roots.() -> Unit) { - } - - /** - * Note: Don't delete, this is intended to trigger compiler diagnostic when the DSL primitive is used in the wrong place - */ - @Deprecated("Use the vararg form of transaction inside roots", level = DeprecationLevel.ERROR) - fun transaction(body: WireTransactionDSL.() -> Unit) { - } - } - - fun roots(body: Roots.() -> Unit) = Roots().apply { body() } - - val txns = ArrayList() - private val txnToLabelMap = HashMap() - - @JvmOverloads - fun transaction(label: String? = null, body: WireTransactionDSL.() -> Unit): WireTransaction { - val forTest = InternalWireTransactionDSL() - forTest.body() - val wtx = forTest.finaliseAndInsertLabels() - txns.add(wtx) - if (label != null) - txnToLabelMap[wtx.id] = label - return wtx - } - - fun labelForTransaction(tx: WireTransaction): String? = txnToLabelMap[tx.id] - fun labelForTransaction(tx: LedgerTransaction): String? = txnToLabelMap[tx.id] - - /** - * Note: Don't delete, this is intended to trigger compiler diagnostic when the DSL primitive is used in the wrong place - */ - @Deprecated("Does not nest ", level = DeprecationLevel.ERROR) - fun transactionGroup(body: TransactionGroupDSL.() -> Unit) { - } - - fun toTransactionGroup() = TransactionGroup( - txns.map { it.toLedgerTransaction(MOCK_IDENTITY_SERVICE, MockStorageService().attachments) }.toSet(), - rootTxns.map { it.toLedgerTransaction(MOCK_IDENTITY_SERVICE, MockStorageService().attachments) }.toSet() - ) - - class Failed(val index: Int, cause: Throwable) : Exception("Transaction $index didn't verify", cause) - - fun verify() { - val group = toTransactionGroup() - try { - group.verify() - } catch (e: TransactionVerificationException) { - // Let the developer know the index of the transaction that failed. - val wtx: WireTransaction = txns.find { it.id == e.tx.origHash }!! - throw Failed(txns.indexOf(wtx) + 1, e) - } - } - - fun expectFailureOfTx(index: Int, message: String): Exception { - val e = assertFailsWith(Failed::class) { - verify() - } - assertEquals(index, e.index) - if (!(e.cause?.message ?: "") .contains(message)) - throw AssertionError("Exception should have said '$message' but was actually: ${e.cause?.message}", e.cause) - return e - } - - fun signAll(txnsToSign: List = txns, vararg extraKeys: KeyPair): List { - return txnsToSign.map { wtx -> - val allPubKeys = wtx.signers.toMutableSet() - val bits = wtx.serialize() - require(bits == wtx.serialized) - val sigs = ArrayList() - for (key in ALL_TEST_KEYS + extraKeys) { - if (allPubKeys.contains(key.public)) { - sigs += key.signWithECDSA(bits) - allPubKeys -= key.public - } - } - SignedTransaction(bits, sigs) - } - } -} - -inline fun transactionGroupFor(body: TransactionGroupDSL.() -> Unit) = TransactionGroupDSL(T::class.java).apply { this.body() } -fun transactionGroup(body: TransactionGroupDSL.() -> Unit) = TransactionGroupDSL(ContractState::class.java).apply { this.body() } diff --git a/core/src/main/kotlin/com/r3corda/core/testing/TransactionDslInterpreter.kt b/core/src/main/kotlin/com/r3corda/core/testing/TransactionDslInterpreter.kt index 2822f830e1..262e69ee25 100644 --- a/core/src/main/kotlin/com/r3corda/core/testing/TransactionDslInterpreter.kt +++ b/core/src/main/kotlin/com/r3corda/core/testing/TransactionDslInterpreter.kt @@ -16,7 +16,6 @@ import java.time.Instant * dynamically, come up with a substitute for primitives relying on early bind */ interface TransactionDslInterpreter : OutputStateLookup { - fun input(stateLabel: String) fun input(stateRef: StateRef) fun output(label: String?, notary: Party, contractState: ContractState) fun attachment(attachmentId: SecureHash) @@ -32,6 +31,8 @@ class TransactionDsl< > (val interpreter: TransactionInterpreter) : TransactionDslInterpreter by interpreter { + fun input(stateLabel: String) = input(retrieveOutputStateAndRef(ContractState::class.java, stateLabel).ref) + // Convenience functions fun output(label: String? = null, notary: Party = DUMMY_NOTARY, contractStateClosure: () -> ContractState) = output(label, notary, contractStateClosure()) diff --git a/core/src/test/kotlin/com/r3corda/core/contracts/TransactionGroupTests.kt b/core/src/test/kotlin/com/r3corda/core/contracts/TransactionGroupTests.kt index c9143a06a6..7aec845442 100644 --- a/core/src/test/kotlin/com/r3corda/core/contracts/TransactionGroupTests.kt +++ b/core/src/test/kotlin/com/r3corda/core/contracts/TransactionGroupTests.kt @@ -120,19 +120,14 @@ class TransactionGroupTests { } } - // We have to do this manually without the DSL because transactionGroup { } won't let us create a tx that - // points nowhere. val input = StateAndRef(A_THOUSAND_POUNDS `with notary` DUMMY_NOTARY, generateStateRef()) - tg.txns += TransactionType.General.Builder().apply { - addInputState(input) - addOutputState(A_THOUSAND_POUNDS `with notary` DUMMY_NOTARY) - addCommand(TestCash.Commands.Move(), BOB_PUBKEY) - }.toWireTransaction() - - val e = assertFailsWith(TransactionResolutionException::class) { - tg.verify() + tg.apply { + transaction { + assertFailsWith(TransactionResolutionException::class) { + input(input.ref) + } + } } - assertEquals(e.hash, input.ref.txhash) } @Test From f4a6a43aa667754155926b80e7f661afaf84e887 Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Mon, 4 Jul 2016 18:49:17 +0100 Subject: [PATCH 079/114] contracts, core: Port CommercialPaperTests, IRSTests, ObligationTests, TransactioGroupTests --- .../r3corda/contracts/CommercialPaperTests.kt | 2 +- .../kotlin/com/r3corda/contracts/IRSTests.kt | 61 +- .../contracts/asset/ObligationTests.kt | 629 +++++++++--------- .../core/contracts/TransactionGroupTests.kt | 52 +- 4 files changed, 387 insertions(+), 357 deletions(-) diff --git a/contracts/src/test/kotlin/com/r3corda/contracts/CommercialPaperTests.kt b/contracts/src/test/kotlin/com/r3corda/contracts/CommercialPaperTests.kt index e9a5f1b136..8ed297d793 100644 --- a/contracts/src/test/kotlin/com/r3corda/contracts/CommercialPaperTests.kt +++ b/contracts/src/test/kotlin/com/r3corda/contracts/CommercialPaperTests.kt @@ -122,7 +122,7 @@ class CommercialPaperTestsGeneric { this `fails with` "must be destroyed" } - verifies() + this.verifies() } } } diff --git a/contracts/src/test/kotlin/com/r3corda/contracts/IRSTests.kt b/contracts/src/test/kotlin/com/r3corda/contracts/IRSTests.kt index 6075cff0ed..59faf91ffa 100644 --- a/contracts/src/test/kotlin/com/r3corda/contracts/IRSTests.kt +++ b/contracts/src/test/kotlin/com/r3corda/contracts/IRSTests.kt @@ -200,12 +200,12 @@ class IRSTests { @Test fun ok() { - trade().verify() + trade().verifies() } @Test fun `ok with groups`() { - tradegroups().verify() + tradegroups().verifies() } /** @@ -360,38 +360,38 @@ class IRSTests { /** * Generates a typical transactional history for an IRS. */ - fun trade(): TransactionGroupDSL { + fun trade(): LedgerDsl { val ld = LocalDate.of(2016, 3, 8) val bd = BigDecimal("0.0063518") - val txgroup: TransactionGroupDSL = transactionGroupFor() { + return ledger { transaction("Agreement") { output("irs post agreement") { singleIRS() } - arg(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } + command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } timestamp(TEST_TX_TIME) } transaction("Fix") { input("irs post agreement") + val postAgreement = "irs post agreement".output() output("irs post first fixing") { - "irs post agreement".output.data.copy( - "irs post agreement".output.data.fixedLeg, - "irs post agreement".output.data.floatingLeg, - "irs post agreement".output.data.calculation.applyFixing(ld, FixedRate(RatioUnit(bd))), - "irs post agreement".output.data.common + postAgreement.data.copy( + postAgreement.data.fixedLeg, + postAgreement.data.floatingLeg, + postAgreement.data.calculation.applyFixing(ld, FixedRate(RatioUnit(bd))), + postAgreement.data.common ) } - arg(ORACLE_PUBKEY) { + command(ORACLE_PUBKEY) { InterestRateSwap.Commands.Fix() } - arg(ORACLE_PUBKEY) { + command(ORACLE_PUBKEY) { Fix(FixOf("ICE LIBOR", ld, Tenor("3M")), bd) } timestamp(TEST_TX_TIME) } } - return txgroup } @Test @@ -652,13 +652,13 @@ class IRSTests { * result and the grouping won't work either. * In reality, the only fields that should be in common will be the next fixing date and the reference rate. */ - fun tradegroups(): TransactionGroupDSL { + fun tradegroups(): LedgerDsl { val ld1 = LocalDate.of(2016, 3, 8) val bd1 = BigDecimal("0.0063518") val irs = singleIRS() - val txgroup: TransactionGroupDSL = transactionGroupFor() { + return ledger { transaction("Agreement") { output("irs post agreement1") { irs.copy( @@ -668,7 +668,7 @@ class IRSTests { irs.common.copy(tradeID = "t1") ) } - arg(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } + command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } timestamp(TEST_TX_TIME) } @@ -681,40 +681,41 @@ class IRSTests { irs.common.copy(tradeID = "t2") ) } - arg(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } + command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } timestamp(TEST_TX_TIME) } transaction("Fix") { input("irs post agreement1") input("irs post agreement2") + val postAgreement1 = "irs post agreement1".output() output("irs post first fixing1") { - "irs post agreement1".output.data.copy( - "irs post agreement1".output.data.fixedLeg, - "irs post agreement1".output.data.floatingLeg, - "irs post agreement1".output.data.calculation.applyFixing(ld1, FixedRate(RatioUnit(bd1))), - "irs post agreement1".output.data.common.copy(tradeID = "t1") + postAgreement1.data.copy( + postAgreement1.data.fixedLeg, + postAgreement1.data.floatingLeg, + postAgreement1.data.calculation.applyFixing(ld1, FixedRate(RatioUnit(bd1))), + postAgreement1.data.common.copy(tradeID = "t1") ) } + val postAgreement2 = "irs post agreement2".output() output("irs post first fixing2") { - "irs post agreement2".output.data.copy( - "irs post agreement2".output.data.fixedLeg, - "irs post agreement2".output.data.floatingLeg, - "irs post agreement2".output.data.calculation.applyFixing(ld1, FixedRate(RatioUnit(bd1))), - "irs post agreement2".output.data.common.copy(tradeID = "t2") + postAgreement2.data.copy( + postAgreement2.data.fixedLeg, + postAgreement2.data.floatingLeg, + postAgreement2.data.calculation.applyFixing(ld1, FixedRate(RatioUnit(bd1))), + postAgreement2.data.common.copy(tradeID = "t2") ) } - arg(ORACLE_PUBKEY) { + command(ORACLE_PUBKEY) { InterestRateSwap.Commands.Fix() } - arg(ORACLE_PUBKEY) { + command(ORACLE_PUBKEY) { Fix(FixOf("ICE LIBOR", ld1, Tenor("3M")), bd1) } timestamp(TEST_TX_TIME) } } - return txgroup } } diff --git a/contracts/src/test/kotlin/com/r3corda/contracts/asset/ObligationTests.kt b/contracts/src/test/kotlin/com/r3corda/contracts/asset/ObligationTests.kt index ea0cd5ea2c..f09a2e55fc 100644 --- a/contracts/src/test/kotlin/com/r3corda/contracts/asset/ObligationTests.kt +++ b/contracts/src/test/kotlin/com/r3corda/contracts/asset/ObligationTests.kt @@ -1,6 +1,5 @@ package com.r3corda.contracts.asset -import com.r3corda.contracts.asset.* import com.r3corda.contracts.asset.Obligation.Lifecycle import com.r3corda.contracts.testing.* import com.r3corda.core.contracts.* @@ -19,11 +18,10 @@ class ObligationTests { val defaultUsd = USD `issued by` defaultIssuer val oneMillionDollars = 1000000.DOLLARS `issued by` defaultIssuer val trustedCashContract = nonEmptySetOf(SecureHash.Companion.randomSHA256() as SecureHash) - val megaIssuedDollars = nonEmptySetOf(Issued(defaultIssuer, USD)) - val megaIssuedPounds = nonEmptySetOf(Issued(defaultIssuer, GBP)) + val megaIssuedDollars = nonEmptySetOf(Issued(defaultIssuer, USD)) + val megaIssuedPounds = nonEmptySetOf(Issued(defaultIssuer, GBP)) val fivePm = Instant.parse("2016-01-01T17:00:00.00Z") val sixPm = Instant.parse("2016-01-01T18:00:00.00Z") - val notary = MEGA_CORP val megaCorpDollarSettlement = Obligation.StateTemplate(trustedCashContract, megaIssuedDollars, fivePm) val megaCorpPoundSettlement = megaCorpDollarSettlement.copy(acceptableIssuedProducts = megaIssuedPounds) val inState = Obligation.State( @@ -35,43 +33,48 @@ class ObligationTests { ) val outState = inState.copy(beneficiary = DUMMY_PUBKEY_2) - private fun obligationTestRoots(group: TransactionGroupDSL>) = group.Roots() - .transaction(oneMillionDollars.OBLIGATION `between` Pair(ALICE, BOB_PUBKEY) `with notary` DUMMY_NOTARY label "Alice's $1,000,000 obligation to Bob") - .transaction(oneMillionDollars.OBLIGATION `between` Pair(BOB, ALICE_PUBKEY) `with notary` DUMMY_NOTARY label "Bob's $1,000,000 obligation to Alice") - .transaction(oneMillionDollars.OBLIGATION `between` Pair(MEGA_CORP, BOB_PUBKEY) `with notary` DUMMY_NOTARY label "MegaCorp's $1,000,000 obligation to Bob") - .transaction(1000000.DOLLARS.CASH `issued by` defaultIssuer `owned by` ALICE_PUBKEY `with notary` DUMMY_NOTARY label "Alice's $1,000,000") + private fun obligationTestRoots(group: LedgerDsl) = group.apply { + nonVerifiedTransaction { + output("Alice's $1,000,000 obligation to Bob", oneMillionDollars.OBLIGATION `between` Pair(ALICE, BOB_PUBKEY)) + output("Bob's $1,000,000 obligation to Alice", oneMillionDollars.OBLIGATION `between` Pair(BOB, ALICE_PUBKEY)) + output("MegaCorp's $1,000,000 obligation to Bob", oneMillionDollars.OBLIGATION `between` Pair(MEGA_CORP, BOB_PUBKEY)) + output("Alice's $1,000,000", 1000000.DOLLARS.CASH `issued by` defaultIssuer `owned by` ALICE_PUBKEY) + } + } @Test fun trivial() { - transaction { - input { inState } - this `fails requirement` "the amounts balance" + ledger { + transaction { + input { inState } + this `fails with` "the amounts balance" - tweak { - output { outState.copy(quantity = 2000.DOLLARS.quantity) } - this `fails requirement` "the amounts balance" - } - tweak { - output { outState } - // No command arguments - this `fails requirement` "required com.r3corda.contracts.asset.Obligation.Commands.Move command" - } - tweak { - output { outState } - arg(DUMMY_PUBKEY_2) { Obligation.Commands.Move(inState.issuanceDef) } - this `fails requirement` "the owning keys are the same as the signing keys" - } - tweak { - output { outState } - output { outState `issued by` MINI_CORP } - arg(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } - this `fails requirement` "at least one obligation input" - } - // Simple reallocation works. - tweak { - output { outState } - arg(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } - this.accepts() + tweak { + output { outState.copy(quantity = 2000.DOLLARS.quantity) } + this `fails with` "the amounts balance" + } + tweak { + output { outState } + // No command commanduments + this `fails with` "required com.r3corda.contracts.asset.Obligation.Commands.Move command" + } + tweak { + output { outState } + command(DUMMY_PUBKEY_2) { Obligation.Commands.Move(inState.issuanceDef) } + this `fails with` "the owning keys are the same as the signing keys" + } + tweak { + output { outState } + output { outState `issued by` MINI_CORP } + command(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } + this `fails with` "at least one obligation input" + } + // Simple reallocation works. + tweak { + output { outState } + command(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } + this.verifies() + } } } } @@ -79,109 +82,111 @@ class ObligationTests { @Test fun `issue debt`() { // Check we can't "move" debt into existence. - transaction { - input { DummyState() } - output { outState } - arg(MINI_CORP_PUBKEY) { Obligation.Commands.Move(outState.issuanceDef) } + ledger { + transaction { + input { DummyState() } + output { outState } + command(MINI_CORP_PUBKEY) { Obligation.Commands.Move(outState.issuanceDef) } - this `fails requirement` "there is at least one obligation input" - } - - // Check we can issue money only as long as the issuer institution is a command signer, i.e. any recognised - // institution is allowed to issue as much cash as they want. - transaction { - output { outState } - arg(DUMMY_PUBKEY_1) { Obligation.Commands.Issue(outState.issuanceDef) } - this `fails requirement` "output deposits are owned by a command signer" - } - transaction { - output { - Obligation.State( - obligor = MINI_CORP, - quantity = 1000.DOLLARS.quantity, - beneficiary = DUMMY_PUBKEY_1, - template = megaCorpDollarSettlement - ) - } - tweak { - arg(MINI_CORP_PUBKEY) { Obligation.Commands.Issue(Obligation.IssuanceDefinition(MINI_CORP, megaCorpDollarSettlement), 0) } - this `fails requirement` "has a nonce" - } - arg(MINI_CORP_PUBKEY) { Obligation.Commands.Issue(Obligation.IssuanceDefinition(MINI_CORP, megaCorpDollarSettlement)) } - this.accepts() - } - - // Test generation works. - val ptx = TransactionType.General.Builder(DUMMY_NOTARY) - Obligation().generateIssue(ptx, MINI_CORP, megaCorpDollarSettlement, 100.DOLLARS.quantity, - beneficiary = DUMMY_PUBKEY_1, notary = DUMMY_NOTARY) - assertTrue(ptx.inputStates().isEmpty()) - val expected = Obligation.State( - obligor = MINI_CORP, - quantity = 100.DOLLARS.quantity, - beneficiary = DUMMY_PUBKEY_1, - template = megaCorpDollarSettlement - ) - assertEquals(ptx.outputStates()[0].data, expected) - assertTrue(ptx.commands()[0].value is Obligation.Commands.Issue<*>) - assertEquals(MINI_CORP_PUBKEY, ptx.commands()[0].signers[0]) - - // We can consume $1000 in a transaction and output $2000 as long as it's signed by an issuer. - transaction { - input { inState } - output { inState.copy(quantity = inState.amount.quantity * 2) } - - // Move fails: not allowed to summon money. - tweak { - arg(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } - this `fails requirement` "at obligor MegaCorp the amounts balance" + this `fails with` "there is at least one obligation input" } - // Issue works. - tweak { - arg(MEGA_CORP_PUBKEY) { Obligation.Commands.Issue(inState.issuanceDef) } - this.accepts() + // Check we can issue money only as long as the issuer institution is a command signer, i.e. any recognised + // institution is allowed to issue as much cash as they want. + transaction { + output { outState } + command(DUMMY_PUBKEY_1) { Obligation.Commands.Issue(outState.issuanceDef) } + this `fails with` "output deposits are owned by a command signer" + } + transaction { + output { + Obligation.State( + obligor = MINI_CORP, + quantity = 1000.DOLLARS.quantity, + beneficiary = DUMMY_PUBKEY_1, + template = megaCorpDollarSettlement + ) + } + tweak { + command(MINI_CORP_PUBKEY) { Obligation.Commands.Issue(Obligation.IssuanceDefinition(MINI_CORP, megaCorpDollarSettlement), 0) } + this `fails with` "has a nonce" + } + command(MINI_CORP_PUBKEY) { Obligation.Commands.Issue(Obligation.IssuanceDefinition(MINI_CORP, megaCorpDollarSettlement)) } + this.verifies() } - } - // Can't use an issue command to lower the amount. - transaction { - input { inState } - output { inState.copy(quantity = inState.amount.quantity / 2) } - arg(MEGA_CORP_PUBKEY) { Obligation.Commands.Issue(inState.issuanceDef) } - this `fails requirement` "output values sum to more than the inputs" - } + // Test generation works. + val ptx = TransactionType.General.Builder(DUMMY_NOTARY) + Obligation().generateIssue(ptx, MINI_CORP, megaCorpDollarSettlement, 100.DOLLARS.quantity, + beneficiary = DUMMY_PUBKEY_1, notary = DUMMY_NOTARY) + assertTrue(ptx.inputStates().isEmpty()) + val expected = Obligation.State( + obligor = MINI_CORP, + quantity = 100.DOLLARS.quantity, + beneficiary = DUMMY_PUBKEY_1, + template = megaCorpDollarSettlement + ) + assertEquals(ptx.outputStates()[0].data, expected) + assertTrue(ptx.commands()[0].value is Obligation.Commands.Issue<*>) + assertEquals(MINI_CORP_PUBKEY, ptx.commands()[0].signers[0]) - // Can't have an issue command that doesn't actually issue money. - transaction { - input { inState } - output { inState } - arg(MEGA_CORP_PUBKEY) { Obligation.Commands.Issue(inState.issuanceDef) } - this `fails requirement` "output values sum to more than the inputs" - } + // We can consume $1000 in a transaction and output $2000 as long as it's signed by an issuer. + transaction { + input { inState } + output { inState.copy(quantity = inState.amount.quantity * 2) } - // Can't have any other commands if we have an issue command (because the issue command overrules them) - transaction { - input { inState } - output { inState.copy(quantity = inState.amount.quantity * 2) } - arg(MEGA_CORP_PUBKEY) { Obligation.Commands.Issue(inState.issuanceDef) } - tweak { - arg(MEGA_CORP_PUBKEY) { Obligation.Commands.Issue(inState.issuanceDef) } - this `fails requirement` "only move/exit commands can be present along with other obligation commands" + // Move fails: not allowed to summon money. + tweak { + command(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } + this `fails with` "at obligor MegaCorp the amounts balance" + } + + // Issue works. + tweak { + command(MEGA_CORP_PUBKEY) { Obligation.Commands.Issue(inState.issuanceDef) } + this.verifies() + } } - tweak { - arg(MEGA_CORP_PUBKEY) { Obligation.Commands.Move(inState.issuanceDef) } - this `fails requirement` "only move/exit commands can be present along with other obligation commands" + + // Can't use an issue command to lower the amount. + transaction { + input { inState } + output { inState.copy(quantity = inState.amount.quantity / 2) } + command(MEGA_CORP_PUBKEY) { Obligation.Commands.Issue(inState.issuanceDef) } + this `fails with` "output values sum to more than the inputs" } - tweak { - arg(MEGA_CORP_PUBKEY) { Obligation.Commands.SetLifecycle(inState.issuanceDef, Lifecycle.DEFAULTED) } - this `fails requirement` "only move/exit commands can be present along with other obligation commands" + + // Can't have an issue command that doesn't actually issue money. + transaction { + input { inState } + output { inState } + command(MEGA_CORP_PUBKEY) { Obligation.Commands.Issue(inState.issuanceDef) } + this `fails with` "output values sum to more than the inputs" } - tweak { - arg(MEGA_CORP_PUBKEY) { Obligation.Commands.Exit(inState.issuanceDef, inState.amount / 2) } - this `fails requirement` "only move/exit commands can be present along with other obligation commands" + + // Can't have any other commands if we have an issue command (because the issue command overrules them) + transaction { + input { inState } + output { inState.copy(quantity = inState.amount.quantity * 2) } + command(MEGA_CORP_PUBKEY) { Obligation.Commands.Issue(inState.issuanceDef) } + tweak { + command(MEGA_CORP_PUBKEY) { Obligation.Commands.Issue(inState.issuanceDef) } + this `fails with` "only move/exit commands can be present along with other obligation commands" + } + tweak { + command(MEGA_CORP_PUBKEY) { Obligation.Commands.Move(inState.issuanceDef) } + this `fails with` "only move/exit commands can be present along with other obligation commands" + } + tweak { + command(MEGA_CORP_PUBKEY) { Obligation.Commands.SetLifecycle(inState.issuanceDef, Lifecycle.DEFAULTED) } + this `fails with` "only move/exit commands can be present along with other obligation commands" + } + tweak { + command(MEGA_CORP_PUBKEY) { Obligation.Commands.Exit(inState.issuanceDef, inState.amount / 2) } + this `fails with` "only move/exit commands can be present along with other obligation commands" + } + this.verifies() } - this.accepts() } } @@ -328,329 +333,353 @@ class ObligationTests { @Test fun `close-out netting`() { // Try netting out two obligations - transactionGroupFor>() { + ledger { obligationTestRoots(this) transaction("Issuance") { input("Alice's $1,000,000 obligation to Bob") input("Bob's $1,000,000 obligation to Alice") // Note we can sign with either key here - arg(ALICE_PUBKEY) { Obligation.Commands.Net(NetType.CLOSE_OUT) } + command(ALICE_PUBKEY) { Obligation.Commands.Net(NetType.CLOSE_OUT) } timestamp(TEST_TX_TIME) } - }.verify() + this.verifies() + } // Try netting out two obligations, with the third uninvolved obligation left // as-is - transactionGroupFor>() { + ledger { obligationTestRoots(this) transaction("Issuance") { input("Alice's $1,000,000 obligation to Bob") input("Bob's $1,000,000 obligation to Alice") input("MegaCorp's $1,000,000 obligation to Bob") output("change") { oneMillionDollars.OBLIGATION `between` Pair(MEGA_CORP, BOB_PUBKEY) } - arg(BOB_PUBKEY, MEGA_CORP_PUBKEY) { Obligation.Commands.Net(NetType.CLOSE_OUT) } + command(BOB_PUBKEY, MEGA_CORP_PUBKEY) { Obligation.Commands.Net(NetType.CLOSE_OUT) } timestamp(TEST_TX_TIME) } - }.verify() + this.verifies() + } // Try having outputs mis-match the inputs - transactionGroupFor>() { + ledger { obligationTestRoots(this) transaction("Issuance") { input("Alice's $1,000,000 obligation to Bob") input("Bob's $1,000,000 obligation to Alice") output("change") { (oneMillionDollars / 2).OBLIGATION `between` Pair(ALICE, BOB_PUBKEY) } - arg(BOB_PUBKEY) { Obligation.Commands.Net(NetType.CLOSE_OUT) } + command(BOB_PUBKEY) { Obligation.Commands.Net(NetType.CLOSE_OUT) } timestamp(TEST_TX_TIME) + this `fails with` "amounts owed on input and output must match" } - }.expectFailureOfTx(1, "amounts owed on input and output must match") + } // Have the wrong signature on the transaction - transactionGroupFor>() { + ledger { obligationTestRoots(this) transaction("Issuance") { input("Alice's $1,000,000 obligation to Bob") input("Bob's $1,000,000 obligation to Alice") - arg(MEGA_CORP_PUBKEY) { Obligation.Commands.Net(NetType.CLOSE_OUT) } + command(MEGA_CORP_PUBKEY) { Obligation.Commands.Net(NetType.CLOSE_OUT) } timestamp(TEST_TX_TIME) + this `fails with` "any involved party has signed" } - }.expectFailureOfTx(1, "any involved party has signed") + } } @Test fun `payment netting`() { // Try netting out two obligations - transactionGroupFor>() { + ledger { obligationTestRoots(this) transaction("Issuance") { input("Alice's $1,000,000 obligation to Bob") input("Bob's $1,000,000 obligation to Alice") - arg(ALICE_PUBKEY, BOB_PUBKEY) { Obligation.Commands.Net(NetType.PAYMENT) } + command(ALICE_PUBKEY, BOB_PUBKEY) { Obligation.Commands.Net(NetType.PAYMENT) } timestamp(TEST_TX_TIME) } - }.verify() + this.verifies() + } // Try netting out two obligations, but only provide one signature. Unlike close-out netting, we need both // signatures for payment netting - transactionGroupFor>() { + ledger { obligationTestRoots(this) transaction("Issuance") { input("Alice's $1,000,000 obligation to Bob") input("Bob's $1,000,000 obligation to Alice") - arg(BOB_PUBKEY) { Obligation.Commands.Net(NetType.PAYMENT) } + command(BOB_PUBKEY) { Obligation.Commands.Net(NetType.PAYMENT) } timestamp(TEST_TX_TIME) + this `fails with` "all involved parties have signed" } - }.expectFailureOfTx(1, "all involved parties have signed") + } // Multilateral netting, A -> B -> C which can net down to A -> C - transactionGroupFor>() { + ledger { obligationTestRoots(this) transaction("Issuance") { input("Bob's $1,000,000 obligation to Alice") input("MegaCorp's $1,000,000 obligation to Bob") output("MegaCorp's $1,000,000 obligation to Alice") { oneMillionDollars.OBLIGATION `between` Pair(MEGA_CORP, ALICE_PUBKEY) } - arg(ALICE_PUBKEY, BOB_PUBKEY, MEGA_CORP_PUBKEY) { Obligation.Commands.Net(NetType.PAYMENT) } + command(ALICE_PUBKEY, BOB_PUBKEY, MEGA_CORP_PUBKEY) { Obligation.Commands.Net(NetType.PAYMENT) } timestamp(TEST_TX_TIME) } - }.verify() + this.verifies() + } // Multilateral netting without the key of the receiving party - transactionGroupFor>() { + ledger { obligationTestRoots(this) transaction("Issuance") { input("Bob's $1,000,000 obligation to Alice") input("MegaCorp's $1,000,000 obligation to Bob") output("MegaCorp's $1,000,000 obligation to Alice") { oneMillionDollars.OBLIGATION `between` Pair(MEGA_CORP, ALICE_PUBKEY) } - arg(ALICE_PUBKEY, BOB_PUBKEY) { Obligation.Commands.Net(NetType.PAYMENT) } + command(ALICE_PUBKEY, BOB_PUBKEY) { Obligation.Commands.Net(NetType.PAYMENT) } timestamp(TEST_TX_TIME) + this `fails with` "all involved parties have signed" } - }.expectFailureOfTx(1, "all involved parties have signed") + } } @Test fun `settlement`() { // Try netting out two obligations - transactionGroupFor>() { + ledger { obligationTestRoots(this) transaction("Settlement") { input("Alice's $1,000,000 obligation to Bob") input("Alice's $1,000,000") output("Bob's $1,000,000") { 1000000.DOLLARS.CASH `issued by` defaultIssuer `owned by` BOB_PUBKEY } - arg(ALICE_PUBKEY) { Obligation.Commands.Settle(Obligation.IssuanceDefinition(ALICE, defaultUsd.OBLIGATION_DEF), Amount(oneMillionDollars.quantity, USD)) } - arg(ALICE_PUBKEY) { Cash.Commands.Move(Obligation().legalContractReference) } + command(ALICE_PUBKEY) { Obligation.Commands.Settle(Obligation.IssuanceDefinition(ALICE, defaultUsd.OBLIGATION_DEF), Amount(oneMillionDollars.quantity, USD)) } + command(ALICE_PUBKEY) { Cash.Commands.Move(Obligation().legalContractReference) } } - }.verify() + this.verifies() + } } @Test fun `payment default`() { // Try defaulting an obligation without a timestamp - transactionGroupFor>() { + ledger { obligationTestRoots(this) transaction("Settlement") { input("Alice's $1,000,000 obligation to Bob") output("Alice's defaulted $1,000,000 obligation to Bob") { (oneMillionDollars.OBLIGATION `between` Pair(ALICE, BOB_PUBKEY)).copy(lifecycle = Lifecycle.DEFAULTED) } - arg(BOB_PUBKEY) { Obligation.Commands.SetLifecycle(Obligation.IssuanceDefinition(ALICE, defaultUsd.OBLIGATION_DEF), Lifecycle.DEFAULTED) } + command(BOB_PUBKEY) { Obligation.Commands.SetLifecycle(Obligation.IssuanceDefinition(ALICE, defaultUsd.OBLIGATION_DEF), Lifecycle.DEFAULTED) } + this `fails with` "there is a timestamp from the authority" } - }.expectFailureOfTx(1, "there is a timestamp from the authority") + } // Try defaulting an obligation due in the future val pastTestTime = TEST_TX_TIME - Duration.ofDays(7) val futureTestTime = TEST_TX_TIME + Duration.ofDays(7) - transactionGroupFor>() { - roots { - transaction(oneMillionDollars.OBLIGATION `between` Pair(ALICE, BOB_PUBKEY) `at` futureTestTime `with notary` DUMMY_NOTARY label "Alice's $1,000,000 obligation to Bob") + ledger { + nonVerifiedTransaction { + output("Alice's $1,000,000 obligation to Bob", oneMillionDollars.OBLIGATION `between` Pair(ALICE, BOB_PUBKEY) `at` futureTestTime) } transaction("Settlement") { input("Alice's $1,000,000 obligation to Bob") output("Alice's defaulted $1,000,000 obligation to Bob") { (oneMillionDollars.OBLIGATION `between` Pair(ALICE, BOB_PUBKEY) `at` futureTestTime).copy(lifecycle = Lifecycle.DEFAULTED) } - arg(BOB_PUBKEY) { Obligation.Commands.SetLifecycle(Obligation.IssuanceDefinition(ALICE, defaultUsd.OBLIGATION_DEF) `at` futureTestTime, Lifecycle.DEFAULTED) } + command(BOB_PUBKEY) { Obligation.Commands.SetLifecycle(Obligation.IssuanceDefinition(ALICE, defaultUsd.OBLIGATION_DEF) `at` futureTestTime, Lifecycle.DEFAULTED) } timestamp(TEST_TX_TIME) + this `fails with` "the due date has passed" } - }.expectFailureOfTx(1, "the due date has passed") + } // Try defaulting an obligation that is now in the past - transactionGroupFor>() { - roots { - transaction(oneMillionDollars.OBLIGATION `between` Pair(ALICE, BOB_PUBKEY) `at` pastTestTime `with notary` DUMMY_NOTARY label "Alice's $1,000,000 obligation to Bob") + ledger { + nonVerifiedTransaction { + output("Alice's $1,000,000 obligation to Bob", oneMillionDollars.OBLIGATION `between` Pair(ALICE, BOB_PUBKEY) `at` pastTestTime) } transaction("Settlement") { input("Alice's $1,000,000 obligation to Bob") output("Alice's defaulted $1,000,000 obligation to Bob") { (oneMillionDollars.OBLIGATION `between` Pair(ALICE, BOB_PUBKEY) `at` pastTestTime).copy(lifecycle = Lifecycle.DEFAULTED) } - arg(BOB_PUBKEY) { Obligation.Commands.SetLifecycle(Obligation.IssuanceDefinition(ALICE, defaultUsd.OBLIGATION_DEF) `at` pastTestTime, Lifecycle.DEFAULTED) } + command(BOB_PUBKEY) { Obligation.Commands.SetLifecycle(Obligation.IssuanceDefinition(ALICE, defaultUsd.OBLIGATION_DEF) `at` pastTestTime, Lifecycle.DEFAULTED) } timestamp(TEST_TX_TIME) } - }.verify() + this.verifies() + } } @Test fun testMergeSplit() { // Splitting value works. - transaction { - arg(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } - tweak { - input { inState } - repeat(4) { output { inState.copy(quantity = inState.quantity / 4) } } - this.accepts() - } - // Merging 4 inputs into 2 outputs works. - tweak { - repeat(4) { input { inState.copy(quantity = inState.quantity / 4) } } - output { inState.copy(quantity = inState.quantity / 2) } - output { inState.copy(quantity = inState.quantity / 2) } - this.accepts() - } - // Merging 2 inputs into 1 works. - tweak { - input { inState.copy(quantity = inState.quantity / 2) } - input { inState.copy(quantity = inState.quantity / 2) } - output { inState } - this.accepts() + ledger { + transaction { + command(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } + tweak { + input { inState } + repeat(4) { output { inState.copy(quantity = inState.quantity / 4) } } + this.verifies() + } + // Merging 4 inputs into 2 outputs works. + tweak { + repeat(4) { input { inState.copy(quantity = inState.quantity / 4) } } + output { inState.copy(quantity = inState.quantity / 2) } + output { inState.copy(quantity = inState.quantity / 2) } + this.verifies() + } + // Merging 2 inputs into 1 works. + tweak { + input { inState.copy(quantity = inState.quantity / 2) } + input { inState.copy(quantity = inState.quantity / 2) } + output { inState } + this.verifies() + } } } } @Test fun zeroSizedValues() { - transaction { - input { inState } - input { inState.copy(quantity = 0L) } - this `fails requirement` "zero sized inputs" - } - transaction { - input { inState } - output { inState } - output { inState.copy(quantity = 0L) } - this `fails requirement` "zero sized outputs" + ledger { + transaction { + input { inState } + input { inState.copy(quantity = 0L) } + this `fails with` "zero sized inputs" + } + transaction { + input { inState } + output { inState } + output { inState.copy(quantity = 0L) } + this `fails with` "zero sized outputs" + } } } @Test fun trivialMismatches() { - // Can't change issuer. - transaction { - input { inState } - output { outState `issued by` MINI_CORP } - this `fails requirement` "at obligor MegaCorp the amounts balance" - } - // Can't mix currencies. - transaction { - input { inState } - output { outState.copy(quantity = 80000, template = megaCorpDollarSettlement) } - output { outState.copy(quantity = 20000, template = megaCorpPoundSettlement) } - this `fails requirement` "the amounts balance" - } - transaction { - input { inState } - input { - inState.copy( - quantity = 15000, - template = megaCorpPoundSettlement, - beneficiary = DUMMY_PUBKEY_2 - ) + ledger { + // Can't change issuer. + transaction { + input { inState } + output { outState `issued by` MINI_CORP } + this `fails with` "at obligor MegaCorp the amounts balance" + } + // Can't mix currencies. + transaction { + input { inState } + output { outState.copy(quantity = 80000, template = megaCorpDollarSettlement) } + output { outState.copy(quantity = 20000, template = megaCorpPoundSettlement) } + this `fails with` "the amounts balance" + } + transaction { + input { inState } + input { + inState.copy( + quantity = 15000, + template = megaCorpPoundSettlement, + beneficiary = DUMMY_PUBKEY_2 + ) + } + output { outState.copy(quantity = 115000) } + this `fails with` "the amounts balance" + } + // Can't have superfluous input states from different issuers. + transaction { + input { inState } + input { inState `issued by` MINI_CORP } + output { outState } + command(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } + command(DUMMY_PUBKEY_1) { Obligation.Commands.Move((inState `issued by` MINI_CORP).issuanceDef) } + this `fails with` "at obligor MiniCorp the amounts balance" } - output { outState.copy(quantity = 115000) } - this `fails requirement` "the amounts balance" - } - // Can't have superfluous input states from different issuers. - transaction { - input { inState } - input { inState `issued by` MINI_CORP } - output { outState } - arg(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } - arg(DUMMY_PUBKEY_1) { Obligation.Commands.Move((inState `issued by` MINI_CORP).issuanceDef) } - this `fails requirement` "at obligor MiniCorp the amounts balance" } } @Test fun exitLedger() { - // Single input/output straightforward case. - transaction { - input { inState } - output { outState.copy(quantity = inState.quantity - 200.DOLLARS.quantity) } - - tweak { - arg(MEGA_CORP_PUBKEY) { Obligation.Commands.Exit(inState.issuanceDef, 100.DOLLARS) } - arg(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } - this `fails requirement` "the amounts balance" - } - - tweak { - arg(MEGA_CORP_PUBKEY) { Obligation.Commands.Exit(inState.issuanceDef, 200.DOLLARS) } - this `fails requirement` "required com.r3corda.contracts.asset.Obligation.Commands.Move command" + ledger { + // Single input/output straightforward case. + transaction { + input { inState } + output { outState.copy(quantity = inState.quantity - 200.DOLLARS.quantity) } tweak { - arg(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } - this.accepts() + command(MEGA_CORP_PUBKEY) { Obligation.Commands.Exit(inState.issuanceDef, 100.DOLLARS) } + command(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } + this `fails with` "the amounts balance" + } + + tweak { + command(MEGA_CORP_PUBKEY) { Obligation.Commands.Exit(inState.issuanceDef, 200.DOLLARS) } + this `fails with` "required com.r3corda.contracts.asset.Obligation.Commands.Move command" + + tweak { + command(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } + this.verifies() + } } } - } - // Multi-issuer case. - transaction { - input { inState } - input { inState `issued by` MINI_CORP } + // Multi-issuer case. + transaction { + input { inState } + input { inState `issued by` MINI_CORP } - output { inState.copy(quantity = inState.quantity - 200.DOLLARS.quantity) `issued by` MINI_CORP } - output { inState.copy(quantity = inState.quantity - 200.DOLLARS.quantity) } + output { inState.copy(quantity = inState.quantity - 200.DOLLARS.quantity) `issued by` MINI_CORP } + output { inState.copy(quantity = inState.quantity - 200.DOLLARS.quantity) } - arg(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } + command(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } - this `fails requirement` "at obligor MegaCorp the amounts balance" + this `fails with` "at obligor MegaCorp the amounts balance" - arg(MEGA_CORP_PUBKEY) { Obligation.Commands.Exit(inState.issuanceDef, 200.DOLLARS) } - tweak { - arg(MINI_CORP_PUBKEY) { Obligation.Commands.Exit((inState `issued by` MINI_CORP).issuanceDef, 0.DOLLARS) } - arg(DUMMY_PUBKEY_1) { Obligation.Commands.Move((inState `issued by` MINI_CORP).issuanceDef) } - this `fails requirement` "at obligor MiniCorp the amounts balance" + command(MEGA_CORP_PUBKEY) { Obligation.Commands.Exit(inState.issuanceDef, 200.DOLLARS) } + tweak { + command(MINI_CORP_PUBKEY) { Obligation.Commands.Exit((inState `issued by` MINI_CORP).issuanceDef, 0.DOLLARS) } + command(DUMMY_PUBKEY_1) { Obligation.Commands.Move((inState `issued by` MINI_CORP).issuanceDef) } + this `fails with` "at obligor MiniCorp the amounts balance" + } + command(MINI_CORP_PUBKEY) { Obligation.Commands.Exit((inState `issued by` MINI_CORP).issuanceDef, 200.DOLLARS) } + command(DUMMY_PUBKEY_1) { Obligation.Commands.Move((inState `issued by` MINI_CORP).issuanceDef) } + this.verifies() } - arg(MINI_CORP_PUBKEY) { Obligation.Commands.Exit((inState `issued by` MINI_CORP).issuanceDef, 200.DOLLARS) } - arg(DUMMY_PUBKEY_1) { Obligation.Commands.Move((inState `issued by` MINI_CORP).issuanceDef) } - this.accepts() } } @Test fun multiIssuer() { - transaction { - // Gather 2000 dollars from two different issuers. - input { inState } - input { inState `issued by` MINI_CORP } + ledger { + transaction { + // Gather 2000 dollars from two different issuers. + input { inState } + input { inState `issued by` MINI_CORP } - // Can't merge them together. - tweak { - output { inState.copy(beneficiary = DUMMY_PUBKEY_2, quantity = 200000L) } - this `fails requirement` "at obligor MegaCorp the amounts balance" - } - // Missing MiniCorp deposit - tweak { - output { inState.copy(beneficiary = DUMMY_PUBKEY_2) } - output { inState.copy(beneficiary = DUMMY_PUBKEY_2) } - this `fails requirement` "at obligor MegaCorp the amounts balance" - } + // Can't merge them together. + tweak { + output { inState.copy(beneficiary = DUMMY_PUBKEY_2, quantity = 200000L) } + this `fails with` "at obligor MegaCorp the amounts balance" + } + // Missing MiniCorp deposit + tweak { + output { inState.copy(beneficiary = DUMMY_PUBKEY_2) } + output { inState.copy(beneficiary = DUMMY_PUBKEY_2) } + this `fails with` "at obligor MegaCorp the amounts balance" + } - // This works. - output { inState.copy(beneficiary = DUMMY_PUBKEY_2) } - output { inState.copy(beneficiary = DUMMY_PUBKEY_2) `issued by` MINI_CORP } - arg(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } - arg(DUMMY_PUBKEY_1) { Obligation.Commands.Move((inState `issued by` MINI_CORP).issuanceDef) } - this.accepts() + // This works. + output { inState.copy(beneficiary = DUMMY_PUBKEY_2) } + output { inState.copy(beneficiary = DUMMY_PUBKEY_2) `issued by` MINI_CORP } + command(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } + command(DUMMY_PUBKEY_1) { Obligation.Commands.Move((inState `issued by` MINI_CORP).issuanceDef) } + this.verifies() + } } } @Test fun multiCurrency() { - // Check we can do an atomic currency trade tx. - transaction { - val pounds = Obligation.State(Lifecycle.NORMAL, MINI_CORP, megaCorpPoundSettlement, 658.POUNDS.quantity, DUMMY_PUBKEY_2) - input { inState `owned by` DUMMY_PUBKEY_1 } - input { pounds } - output { inState `owned by` DUMMY_PUBKEY_2 } - output { pounds `owned by` DUMMY_PUBKEY_1 } - arg(DUMMY_PUBKEY_1, DUMMY_PUBKEY_2) { Obligation.Commands.Move(inState.issuanceDef) } - arg(DUMMY_PUBKEY_1, DUMMY_PUBKEY_2) { Obligation.Commands.Move(pounds.issuanceDef) } + ledger { + // Check we can do an atomic currency trade tx. + transaction { + val pounds = Obligation.State(Lifecycle.NORMAL, MINI_CORP, megaCorpPoundSettlement, 658.POUNDS.quantity, DUMMY_PUBKEY_2) + input { inState `owned by` DUMMY_PUBKEY_1 } + input { pounds } + output { inState `owned by` DUMMY_PUBKEY_2 } + output { pounds `owned by` DUMMY_PUBKEY_1 } + command(DUMMY_PUBKEY_1, DUMMY_PUBKEY_2) { Obligation.Commands.Move(inState.issuanceDef) } + command(DUMMY_PUBKEY_1, DUMMY_PUBKEY_2) { Obligation.Commands.Move(pounds.issuanceDef) } - this.accepts() + this.verifies() + } } } @@ -686,7 +715,7 @@ class ObligationTests { fiveKDollarsFromMegaToMega.copy(template = megaCorpDollarSettlement.copy(acceptableContracts = nonEmptySetOf(SecureHash.Companion.randomSHA256()))).bilateralNetState) // States must not be nettable if the trusted issuers differ - val miniCorpIssuer = nonEmptySetOf(Issued(MINI_CORP.ref(1), USD)) + val miniCorpIssuer = nonEmptySetOf(Issued(MINI_CORP.ref(1), USD)) assertNotEquals(fiveKDollarsFromMegaToMega.bilateralNetState, fiveKDollarsFromMegaToMega.copy(template = megaCorpDollarSettlement.copy(acceptableIssuedProducts = miniCorpIssuer)).bilateralNetState) } @@ -743,7 +772,7 @@ class ObligationTests { val fiveKDollarsFromMegaToMini = Obligation.State(Lifecycle.NORMAL, MEGA_CORP, megaCorpDollarSettlement, 5000.DOLLARS.quantity, MINI_CORP_PUBKEY) val expected = mapOf(Pair(Pair(MEGA_CORP_PUBKEY, MINI_CORP_PUBKEY), fiveKDollarsFromMegaToMini.amount)) - val actual = extractAmountsDue(USD, listOf(fiveKDollarsFromMegaToMini)) + val actual = extractAmountsDue(USD, listOf(fiveKDollarsFromMegaToMini)) assertEquals(expected, actual) } @@ -755,7 +784,7 @@ class ObligationTests { Pair(Pair(BOB_PUBKEY, ALICE_PUBKEY), Amount(100000000, GBP)) ) val expected: Map, Amount> = emptyMap() // Zero balances are stripped before returning - val actual = netAmountsDue(balanced) + val actual = netAmountsDue(balanced) assertEquals(expected, actual) } @@ -769,7 +798,7 @@ class ObligationTests { val expected = mapOf( Pair(Pair(BOB_PUBKEY, ALICE_PUBKEY), Amount(100000000, GBP)) ) - var actual = netAmountsDue(balanced) + val actual = netAmountsDue(balanced) assertEquals(expected, actual) } diff --git a/core/src/test/kotlin/com/r3corda/core/contracts/TransactionGroupTests.kt b/core/src/test/kotlin/com/r3corda/core/contracts/TransactionGroupTests.kt index 7aec845442..fdefad885b 100644 --- a/core/src/test/kotlin/com/r3corda/core/contracts/TransactionGroupTests.kt +++ b/core/src/test/kotlin/com/r3corda/core/contracts/TransactionGroupTests.kt @@ -47,33 +47,33 @@ class TransactionGroupTests { @Test fun success() { - transactionGroup { - roots { - transaction(A_THOUSAND_POUNDS `with notary` DUMMY_NOTARY label "£1000") + ledger { + nonVerifiedTransaction { + output("£1000") { A_THOUSAND_POUNDS } } transaction { input("£1000") output("alice's £1000") { A_THOUSAND_POUNDS `owned by` ALICE_PUBKEY } - arg(MINI_CORP_PUBKEY) { TestCash.Commands.Move() } + command(MINI_CORP_PUBKEY) { TestCash.Commands.Move() } } transaction { input("alice's £1000") - arg(ALICE_PUBKEY) { TestCash.Commands.Move() } - arg(MINI_CORP_PUBKEY) { TestCash.Commands.Exit(1000.POUNDS) } + command(ALICE_PUBKEY) { TestCash.Commands.Move() } + command(MINI_CORP_PUBKEY) { TestCash.Commands.Exit(1000.POUNDS) } } - verify() + verifies() } } @Test fun conflict() { - transactionGroup { + ledger { val t = transaction { output("cash") { A_THOUSAND_POUNDS } - arg(MINI_CORP_PUBKEY) { TestCash.Commands.Issue() } + command(MINI_CORP_PUBKEY) { TestCash.Commands.Issue() } } val conflict1 = transaction { @@ -81,10 +81,10 @@ class TransactionGroupTests { val HALF = A_THOUSAND_POUNDS.copy(amount = 500.POUNDS) `owned by` BOB_PUBKEY output { HALF } output { HALF } - arg(MINI_CORP_PUBKEY) { TestCash.Commands.Move() } + command(MINI_CORP_PUBKEY) { TestCash.Commands.Move() } } - verify() + verifies() // Alice tries to double spend back to herself. val conflict2 = transaction { @@ -92,13 +92,13 @@ class TransactionGroupTests { val HALF = A_THOUSAND_POUNDS.copy(amount = 500.POUNDS) `owned by` ALICE_PUBKEY output { HALF } output { HALF } - arg(MINI_CORP_PUBKEY) { TestCash.Commands.Move() } + command(MINI_CORP_PUBKEY) { TestCash.Commands.Move() } } assertNotEquals(conflict1, conflict2) val e = assertFailsWith(TransactionConflictException::class) { - verify() + verifies() } assertEquals(StateRef(t.id, 0), e.conflictRef) assertEquals(setOf(conflict1.id, conflict2.id), setOf(e.tx1.id, e.tx2.id)) @@ -108,10 +108,10 @@ class TransactionGroupTests { @Test fun disconnected() { // Check that if we have a transaction in the group that doesn't connect to anything else, it's rejected. - val tg = transactionGroup { + val tg = ledger { transaction { output("cash") { A_THOUSAND_POUNDS } - arg(MINI_CORP_PUBKEY) { TestCash.Commands.Issue() } + command(MINI_CORP_PUBKEY) { TestCash.Commands.Issue() } } transaction { @@ -133,44 +133,44 @@ class TransactionGroupTests { @Test fun duplicatedInputs() { // Check that a transaction cannot refer to the same input more than once. - transactionGroup { - roots { - transaction(A_THOUSAND_POUNDS `with notary` DUMMY_NOTARY label "£1000") + ledger { + nonVerifiedTransaction { + output("£1000") { A_THOUSAND_POUNDS } } transaction { input("£1000") input("£1000") output { A_THOUSAND_POUNDS.copy(amount = A_THOUSAND_POUNDS.amount * 2) } - arg(MINI_CORP_PUBKEY) { TestCash.Commands.Move() } + command(MINI_CORP_PUBKEY) { TestCash.Commands.Move() } } assertFailsWith(TransactionConflictException::class) { - verify() + verifies() } } } @Test fun signGroup() { - val signedTxns: List = transactionGroup { + val signedTxns: List = ledger { transaction { output("£1000") { A_THOUSAND_POUNDS } - arg(MINI_CORP_PUBKEY) { TestCash.Commands.Issue() } + command(MINI_CORP_PUBKEY) { TestCash.Commands.Issue() } } transaction { input("£1000") output("alice's £1000") { A_THOUSAND_POUNDS `owned by` ALICE_PUBKEY } - arg(MINI_CORP_PUBKEY) { TestCash.Commands.Move() } + command(MINI_CORP_PUBKEY) { TestCash.Commands.Move() } } transaction { input("alice's £1000") - arg(ALICE_PUBKEY) { TestCash.Commands.Move() } - arg(MINI_CORP_PUBKEY) { TestCash.Commands.Exit(1000.POUNDS) } + command(ALICE_PUBKEY) { TestCash.Commands.Move() } + command(MINI_CORP_PUBKEY) { TestCash.Commands.Exit(1000.POUNDS) } } - }.signAll() + }.interpreter.wireTransactions.let { signAll(it) } // Now go through the conversion -> verification path with them. val ltxns = signedTxns.map { From 7634331f68fcddb94306299df5907c6c1b8c805a Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Tue, 5 Jul 2016 10:01:10 +0100 Subject: [PATCH 080/114] contracts: Port CashTests to new dsl --- .../com/r3corda/contracts/asset/CashTests.kt | 520 +++++++++--------- 1 file changed, 268 insertions(+), 252 deletions(-) diff --git a/contracts/src/test/kotlin/com/r3corda/contracts/asset/CashTests.kt b/contracts/src/test/kotlin/com/r3corda/contracts/asset/CashTests.kt index 72f0cde8ab..a384315b2c 100644 --- a/contracts/src/test/kotlin/com/r3corda/contracts/asset/CashTests.kt +++ b/contracts/src/test/kotlin/com/r3corda/contracts/asset/CashTests.kt @@ -29,142 +29,146 @@ class CashTests { @Test fun trivial() { - transaction { - input { inState } - this `fails requirement` "the amounts balance" + ledger { + transaction { + input { inState } + this `fails with` "the amounts balance" - tweak { - output { outState.copy(amount = 2000.DOLLARS `issued by` defaultIssuer) } - this `fails requirement` "the amounts balance" - } - tweak { - output { outState } - // No command arguments - this `fails requirement` "required com.r3corda.contracts.asset.FungibleAsset.Commands.Move command" - } - tweak { - output { outState } - arg(DUMMY_PUBKEY_2) { Cash.Commands.Move() } - this `fails requirement` "the owning keys are the same as the signing keys" - } - tweak { - output { outState } - output { outState `issued by` MINI_CORP } - arg(DUMMY_PUBKEY_1) { Cash.Commands.Move() } - this `fails requirement` "at least one asset input" - } - // Simple reallocation works. - tweak { - output { outState } - arg(DUMMY_PUBKEY_1) { Cash.Commands.Move() } - this.accepts() + tweak { + output { outState.copy(amount = 2000.DOLLARS `issued by` defaultIssuer) } + this `fails with` "the amounts balance" + } + tweak { + output { outState } + // No command commanduments + this `fails with` "required com.r3corda.contracts.asset.FungibleAsset.Commands.Move command" + } + tweak { + output { outState } + command(DUMMY_PUBKEY_2) { Cash.Commands.Move() } + this `fails with` "the owning keys are the same as the signing keys" + } + tweak { + output { outState } + output { outState `issued by` MINI_CORP } + command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } + this `fails with` "at least one asset input" + } + // Simple reallocation works. + tweak { + output { outState } + command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } + this.verifies() + } } } } @Test fun issueMoney() { - // Check we can't "move" money into existence. - transaction { - input { DummyState() } - output { outState } - arg(MINI_CORP_PUBKEY) { Cash.Commands.Move() } + ledger { + // Check we can't "move" money into existence. + transaction { + input { DummyState() } + output { outState } + command(MINI_CORP_PUBKEY) { Cash.Commands.Move() } - this `fails requirement` "there is at least one asset input" - } - - // Check we can issue money only as long as the issuer institution is a command signer, i.e. any recognised - // institution is allowed to issue as much cash as they want. - transaction { - output { outState } - arg(DUMMY_PUBKEY_1) { Cash.Commands.Issue() } - this `fails requirement` "output deposits are owned by a command signer" - } - transaction { - output { - Cash.State( - amount = 1000.DOLLARS `issued by` MINI_CORP.ref(12, 34), - owner = DUMMY_PUBKEY_1 - ) - } - tweak { - arg(MINI_CORP_PUBKEY) { Cash.Commands.Issue(0) } - this `fails requirement` "has a nonce" - } - arg(MINI_CORP_PUBKEY) { Cash.Commands.Issue() } - this.accepts() - } - - // Test generation works. - val ptx = TransactionType.General.Builder() - Cash().generateIssue(ptx, 100.DOLLARS `issued by` MINI_CORP.ref(12, 34), owner = DUMMY_PUBKEY_1, notary = DUMMY_NOTARY) - assertTrue(ptx.inputStates().isEmpty()) - val s = ptx.outputStates()[0].data as Cash.State - assertEquals(100.DOLLARS `issued by` MINI_CORP.ref(12, 34), s.amount) - assertEquals(MINI_CORP, s.deposit.party) - assertEquals(DUMMY_PUBKEY_1, s.owner) - assertTrue(ptx.commands()[0].value is Cash.Commands.Issue) - assertEquals(MINI_CORP_PUBKEY, ptx.commands()[0].signers[0]) - - // Test issuance from the issuance definition - val amount = 100.DOLLARS `issued by` MINI_CORP.ref(12, 34) - val templatePtx = TransactionType.General.Builder() - Cash().generateIssue(templatePtx, amount, owner = DUMMY_PUBKEY_1, notary = DUMMY_NOTARY) - assertTrue(templatePtx.inputStates().isEmpty()) - assertEquals(ptx.outputStates()[0], templatePtx.outputStates()[0]) - - // We can consume $1000 in a transaction and output $2000 as long as it's signed by an issuer. - transaction { - input { inState } - output { inState.copy(amount = inState.amount * 2) } - - // Move fails: not allowed to summon money. - tweak { - arg(DUMMY_PUBKEY_1) { Cash.Commands.Move() } - this `fails requirement` "at issuer MegaCorp the amounts balance" + this `fails with` "there is at least one asset input" } - // Issue works. - tweak { - arg(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() } - this.accepts() + // Check we can issue money only as long as the issuer institution is a command signer, i.e. any recognised + // institution is allowed to issue as much cash as they want. + transaction { + output { outState } + command(DUMMY_PUBKEY_1) { Cash.Commands.Issue() } + this `fails with` "output deposits are owned by a command signer" + } + transaction { + output { + Cash.State( + amount = 1000.DOLLARS `issued by` MINI_CORP.ref(12, 34), + owner = DUMMY_PUBKEY_1 + ) + } + tweak { + command(MINI_CORP_PUBKEY) { Cash.Commands.Issue(0) } + this `fails with` "has a nonce" + } + command(MINI_CORP_PUBKEY) { Cash.Commands.Issue() } + this.verifies() } - } - // Can't use an issue command to lower the amount. - transaction { - input { inState } - output { inState.copy(amount = inState.amount / 2) } - arg(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() } - this `fails requirement` "output values sum to more than the inputs" - } + // Test generation works. + val ptx = TransactionType.General.Builder() + Cash().generateIssue(ptx, 100.DOLLARS `issued by` MINI_CORP.ref(12, 34), owner = DUMMY_PUBKEY_1, notary = DUMMY_NOTARY) + assertTrue(ptx.inputStates().isEmpty()) + val s = ptx.outputStates()[0].data as Cash.State + assertEquals(100.DOLLARS `issued by` MINI_CORP.ref(12, 34), s.amount) + assertEquals(MINI_CORP, s.deposit.party) + assertEquals(DUMMY_PUBKEY_1, s.owner) + assertTrue(ptx.commands()[0].value is Cash.Commands.Issue) + assertEquals(MINI_CORP_PUBKEY, ptx.commands()[0].signers[0]) - // Can't have an issue command that doesn't actually issue money. - transaction { - input { inState } - output { inState } - arg(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() } - this `fails requirement` "output values sum to more than the inputs" - } + // Test issuance from the issuance definition + val amount = 100.DOLLARS `issued by` MINI_CORP.ref(12, 34) + val templatePtx = TransactionType.General.Builder() + Cash().generateIssue(templatePtx, amount, owner = DUMMY_PUBKEY_1, notary = DUMMY_NOTARY) + assertTrue(templatePtx.inputStates().isEmpty()) + assertEquals(ptx.outputStates()[0], templatePtx.outputStates()[0]) - // Can't have any other commands if we have an issue command (because the issue command overrules them) - transaction { - input { inState } - output { inState.copy(amount = inState.amount * 2) } - arg(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() } - tweak { - arg(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() } - this `fails requirement` "there is only a single issue command" + // We can consume $1000 in a transaction and output $2000 as long as it's signed by an issuer. + transaction { + input { inState } + output { inState.copy(amount = inState.amount * 2) } + + // Move fails: not allowed to summon money. + tweak { + command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } + this `fails with` "at issuer MegaCorp the amounts balance" + } + + // Issue works. + tweak { + command(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() } + this.verifies() + } } - tweak { - arg(MEGA_CORP_PUBKEY) { Cash.Commands.Move() } - this `fails requirement` "there is only a single issue command" + + // Can't use an issue command to lower the amount. + transaction { + input { inState } + output { inState.copy(amount = inState.amount / 2) } + command(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() } + this `fails with` "output values sum to more than the inputs" } - tweak { - arg(MEGA_CORP_PUBKEY) { Cash.Commands.Exit(inState.amount / 2) } - this `fails requirement` "there is only a single issue command" + + // Can't have an issue command that doesn't actually issue money. + transaction { + input { inState } + output { inState } + command(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() } + this `fails with` "output values sum to more than the inputs" + } + + // Can't have any other commands if we have an issue command (because the issue command overrules them) + transaction { + input { inState } + output { inState.copy(amount = inState.amount * 2) } + command(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() } + tweak { + command(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() } + this `fails with` "there is only a single issue command" + } + tweak { + command(MEGA_CORP_PUBKEY) { Cash.Commands.Move() } + this `fails with` "there is only a single issue command" + } + tweak { + command(MEGA_CORP_PUBKEY) { Cash.Commands.Exit(inState.amount / 2) } + this `fails with` "there is only a single issue command" + } + this.verifies() } - this.accepts() } } @@ -189,178 +193,190 @@ class CashTests { @Test fun testMergeSplit() { - // Splitting value works. - transaction { - arg(DUMMY_PUBKEY_1) { Cash.Commands.Move() } - tweak { - input { inState } - for (i in 1..4) output { inState.copy(amount = inState.amount / 4) } - this.accepts() - } - // Merging 4 inputs into 2 outputs works. - tweak { - for (i in 1..4) input { inState.copy(amount = inState.amount / 4) } - output { inState.copy(amount = inState.amount / 2) } - output { inState.copy(amount = inState.amount / 2) } - this.accepts() - } - // Merging 2 inputs into 1 works. - tweak { - input { inState.copy(amount = inState.amount / 2) } - input { inState.copy(amount = inState.amount / 2) } - output { inState } - this.accepts() + ledger { + // Splitting value works. + transaction { + command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } + tweak { + input { inState } + for (i in 1..4) output { inState.copy(amount = inState.amount / 4) } + this.verifies() + } + // Merging 4 inputs into 2 outputs works. + tweak { + for (i in 1..4) input { inState.copy(amount = inState.amount / 4) } + output { inState.copy(amount = inState.amount / 2) } + output { inState.copy(amount = inState.amount / 2) } + this.verifies() + } + // Merging 2 inputs into 1 works. + tweak { + input { inState.copy(amount = inState.amount / 2) } + input { inState.copy(amount = inState.amount / 2) } + output { inState } + this.verifies() + } } } } @Test fun zeroSizedValues() { - transaction { - input { inState } - input { inState.copy(amount = 0.DOLLARS `issued by` defaultIssuer) } - this `fails requirement` "zero sized inputs" - } - transaction { - input { inState } - output { inState } - output { inState.copy(amount = 0.DOLLARS `issued by` defaultIssuer) } - this `fails requirement` "zero sized outputs" + ledger { + transaction { + input { inState } + input { inState.copy(amount = 0.DOLLARS `issued by` defaultIssuer) } + this `fails with` "zero sized inputs" + } + transaction { + input { inState } + output { inState } + output { inState.copy(amount = 0.DOLLARS `issued by` defaultIssuer) } + this `fails with` "zero sized outputs" + } } } @Test fun trivialMismatches() { - // Can't change issuer. - transaction { - input { inState } - output { outState `issued by` MINI_CORP } - this `fails requirement` "at issuer MegaCorp the amounts balance" - } - // Can't change deposit reference when splitting. - transaction { - input { inState } - output { outState.copy(amount = inState.amount / 2).editDepositRef(0) } - output { outState.copy(amount = inState.amount / 2).editDepositRef(1) } - this `fails requirement` "for deposit [01] at issuer MegaCorp the amounts balance" - } - // Can't mix currencies. - transaction { - input { inState } - output { outState.copy(amount = 800.DOLLARS `issued by` defaultIssuer) } - output { outState.copy(amount = 200.POUNDS `issued by` defaultIssuer) } - this `fails requirement` "the amounts balance" - } - transaction { - input { inState } - input { - inState.copy( - amount = 150.POUNDS `issued by` defaultIssuer, - owner = DUMMY_PUBKEY_2 - ) + ledger { + // Can't change issuer. + transaction { + input { inState } + output { outState `issued by` MINI_CORP } + this `fails with` "at issuer MegaCorp the amounts balance" + } + // Can't change deposit reference when splitting. + transaction { + input { inState } + output { outState.copy(amount = inState.amount / 2).editDepositRef(0) } + output { outState.copy(amount = inState.amount / 2).editDepositRef(1) } + this `fails with` "for deposit [01] at issuer MegaCorp the amounts balance" + } + // Can't mix currencies. + transaction { + input { inState } + output { outState.copy(amount = 800.DOLLARS `issued by` defaultIssuer) } + output { outState.copy(amount = 200.POUNDS `issued by` defaultIssuer) } + this `fails with` "the amounts balance" + } + transaction { + input { inState } + input { + inState.copy( + amount = 150.POUNDS `issued by` defaultIssuer, + owner = DUMMY_PUBKEY_2 + ) + } + output { outState.copy(amount = 1150.DOLLARS `issued by` defaultIssuer) } + this `fails with` "the amounts balance" + } + // Can't have superfluous input states from different issuers. + transaction { + input { inState } + input { inState `issued by` MINI_CORP } + output { outState } + command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } + this `fails with` "at issuer MiniCorp the amounts balance" + } + // Can't combine two different deposits at the same issuer. + transaction { + input { inState } + input { inState.editDepositRef(3) } + output { outState.copy(amount = inState.amount * 2).editDepositRef(3) } + this `fails with` "for deposit [01]" } - output { outState.copy(amount = 1150.DOLLARS `issued by` defaultIssuer) } - this `fails requirement` "the amounts balance" - } - // Can't have superfluous input states from different issuers. - transaction { - input { inState } - input { inState `issued by` MINI_CORP } - output { outState } - arg(DUMMY_PUBKEY_1) { Cash.Commands.Move() } - this `fails requirement` "at issuer MiniCorp the amounts balance" - } - // Can't combine two different deposits at the same issuer. - transaction { - input { inState } - input { inState.editDepositRef(3) } - output { outState.copy(amount = inState.amount * 2).editDepositRef(3) } - this `fails requirement` "for deposit [01]" } } @Test fun exitLedger() { - // Single input/output straightforward case. - transaction { - input { inState } - output { outState.copy(amount = inState.amount - (200.DOLLARS `issued by` defaultIssuer)) } - - tweak { - arg(MEGA_CORP_PUBKEY) { Cash.Commands.Exit(100.DOLLARS `issued by` defaultIssuer) } - arg(DUMMY_PUBKEY_1) { Cash.Commands.Move() } - this `fails requirement` "the amounts balance" - } - - tweak { - arg(MEGA_CORP_PUBKEY) { Cash.Commands.Exit(200.DOLLARS `issued by` defaultIssuer) } - this `fails requirement` "required com.r3corda.contracts.asset.FungibleAsset.Commands.Move command" + ledger { + // Single input/output straightforward case. + transaction { + input { inState } + output { outState.copy(amount = inState.amount - (200.DOLLARS `issued by` defaultIssuer)) } tweak { - arg(DUMMY_PUBKEY_1) { Cash.Commands.Move() } - this.accepts() + command(MEGA_CORP_PUBKEY) { Cash.Commands.Exit(100.DOLLARS `issued by` defaultIssuer) } + command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } + this `fails with` "the amounts balance" + } + + tweak { + command(MEGA_CORP_PUBKEY) { Cash.Commands.Exit(200.DOLLARS `issued by` defaultIssuer) } + this `fails with` "required com.r3corda.contracts.asset.FungibleAsset.Commands.Move command" + + tweak { + command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } + this.verifies() + } } } - } - // Multi-issuer case. - transaction { - input { inState } - input { inState `issued by` MINI_CORP } + // Multi-issuer case. + transaction { + input { inState } + input { inState `issued by` MINI_CORP } - output { inState.copy(amount = inState.amount - (200.DOLLARS `issued by` defaultIssuer)) `issued by` MINI_CORP } - output { inState.copy(amount = inState.amount - (200.DOLLARS `issued by` defaultIssuer)) } + output { inState.copy(amount = inState.amount - (200.DOLLARS `issued by` defaultIssuer)) `issued by` MINI_CORP } + output { inState.copy(amount = inState.amount - (200.DOLLARS `issued by` defaultIssuer)) } - arg(DUMMY_PUBKEY_1) { Cash.Commands.Move() } + command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } - this `fails requirement` "at issuer MegaCorp the amounts balance" + this `fails with` "at issuer MegaCorp the amounts balance" - arg(MEGA_CORP_PUBKEY) { Cash.Commands.Exit(200.DOLLARS `issued by` defaultIssuer) } - this `fails requirement` "at issuer MiniCorp the amounts balance" + command(MEGA_CORP_PUBKEY) { Cash.Commands.Exit(200.DOLLARS `issued by` defaultIssuer) } + this `fails with` "at issuer MiniCorp the amounts balance" - arg(MINI_CORP_PUBKEY) { Cash.Commands.Exit(200.DOLLARS `issued by` MINI_CORP.ref(defaultRef)) } - this.accepts() + command(MINI_CORP_PUBKEY) { Cash.Commands.Exit(200.DOLLARS `issued by` MINI_CORP.ref(defaultRef)) } + this.verifies() + } } } @Test fun multiIssuer() { - transaction { - // Gather 2000 dollars from two different issuers. - input { inState } - input { inState `issued by` MINI_CORP } + ledger { + transaction { + // Gather 2000 dollars from two different issuers. + input { inState } + input { inState `issued by` MINI_CORP } - // Can't merge them together. - tweak { - output { inState.copy(owner = DUMMY_PUBKEY_2, amount = 2000.DOLLARS `issued by` defaultIssuer) } - this `fails requirement` "at issuer MegaCorp the amounts balance" - } - // Missing MiniCorp deposit - tweak { - output { inState.copy(owner = DUMMY_PUBKEY_2) } - output { inState.copy(owner = DUMMY_PUBKEY_2) } - this `fails requirement` "at issuer MegaCorp the amounts balance" - } + // Can't merge them together. + tweak { + output { inState.copy(owner = DUMMY_PUBKEY_2, amount = 2000.DOLLARS `issued by` defaultIssuer) } + this `fails with` "at issuer MegaCorp the amounts balance" + } + // Missing MiniCorp deposit + tweak { + output { inState.copy(owner = DUMMY_PUBKEY_2) } + output { inState.copy(owner = DUMMY_PUBKEY_2) } + this `fails with` "at issuer MegaCorp the amounts balance" + } - // This works. - output { inState.copy(owner = DUMMY_PUBKEY_2) } - output { inState.copy(owner = DUMMY_PUBKEY_2) `issued by` MINI_CORP } - arg(DUMMY_PUBKEY_1) { Cash.Commands.Move() } - this.accepts() + // This works. + output { inState.copy(owner = DUMMY_PUBKEY_2) } + output { inState.copy(owner = DUMMY_PUBKEY_2) `issued by` MINI_CORP } + command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } + this.verifies() + } } } @Test fun multiCurrency() { - // Check we can do an atomic currency trade tx. - transaction { - val pounds = Cash.State(658.POUNDS `issued by` MINI_CORP.ref(3, 4, 5), DUMMY_PUBKEY_2) - input { inState `owned by` DUMMY_PUBKEY_1 } - input { pounds } - output { inState `owned by` DUMMY_PUBKEY_2 } - output { pounds `owned by` DUMMY_PUBKEY_1 } - arg(DUMMY_PUBKEY_1, DUMMY_PUBKEY_2) { Cash.Commands.Move() } + ledger { + // Check we can do an atomic currency trade tx. + transaction { + val pounds = Cash.State(658.POUNDS `issued by` MINI_CORP.ref(3, 4, 5), DUMMY_PUBKEY_2) + input { inState `owned by` DUMMY_PUBKEY_1 } + input { pounds } + output { inState `owned by` DUMMY_PUBKEY_2 } + output { pounds `owned by` DUMMY_PUBKEY_1 } + command(DUMMY_PUBKEY_1, DUMMY_PUBKEY_2) { Cash.Commands.Move() } - this.accepts() + this.verifies() + } } } From bdda3d239abc90303e387d9a1d5a41e0cf5474ff Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Tue, 5 Jul 2016 12:01:59 +0100 Subject: [PATCH 081/114] contracts: Port Java CashTests to new DSL --- .../contracts/asset/CashTestsJava.java | 61 ++++++++++--------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/contracts/src/test/java/com/r3corda/contracts/asset/CashTestsJava.java b/contracts/src/test/java/com/r3corda/contracts/asset/CashTestsJava.java index 4d62148f70..36fced1951 100644 --- a/contracts/src/test/java/com/r3corda/contracts/asset/CashTestsJava.java +++ b/contracts/src/test/java/com/r3corda/contracts/asset/CashTestsJava.java @@ -2,6 +2,7 @@ package com.r3corda.contracts.asset; import com.r3corda.core.contracts.PartyAndReference; import com.r3corda.core.serialization.OpaqueBytes; +import kotlin.Unit; import org.junit.Test; import static com.r3corda.core.testing.JavaTestHelpers.*; @@ -20,39 +21,41 @@ public class CashTestsJava { @Test public void trivial() { + ledger(lg -> { + lg.transaction(tx -> { + tx.input(inState); + tx.failsWith("the amounts balance"); - transaction(tx -> { - tx.input(inState); - tx.failsRequirement("the amounts balance"); + tx.tweak(tw -> { + tw.output(new Cash.State(issuedBy(DOLLARS(2000), defaultIssuer), getDUMMY_PUBKEY_2())); + return tw.failsWith("the amounts balance"); + }); - tx.tweak(tw -> { - tw.output(new Cash.State(issuedBy(DOLLARS(2000), defaultIssuer), getDUMMY_PUBKEY_2())); - return tw.failsRequirement("the amounts balance"); - }); + tx.tweak(tw -> { + tw.output(outState); + // No command arguments + return tw.failsWith("required com.r3corda.contracts.asset.FungibleAsset.Commands.Move command"); + }); + tx.tweak(tw -> { + tw.output(outState); + tw.command(getDUMMY_PUBKEY_2(), new Cash.Commands.Move()); + return tw.failsWith("the owning keys are the same as the signing keys"); + }); + tx.tweak(tw -> { + tw.output(outState); + tw.output(issuedBy(outState, getMINI_CORP())); + tw.command(getDUMMY_PUBKEY_1(), new Cash.Commands.Move()); + return tw.failsWith("at least one asset input"); + }); - tx.tweak(tw -> { - tw.output(outState); - // No command arguments - return tw.failsRequirement("required com.r3corda.contracts.asset.FungibleAsset.Commands.Move command"); - }); - tx.tweak(tw -> { - tw.output(outState); - tw.arg(getDUMMY_PUBKEY_2(), new Cash.Commands.Move()); - return tw.failsRequirement("the owning keys are the same as the signing keys"); - }); - tx.tweak(tw -> { - tw.output(outState); - tw.output(issuedBy(outState, getMINI_CORP())); - tw.arg(getDUMMY_PUBKEY_1(), new Cash.Commands.Move()); - return tw.failsRequirement("at least one asset input"); - }); - - // Simple reallocation works. - return tx.tweak(tw -> { - tw.output(outState); - tw.arg(getDUMMY_PUBKEY_1(), new Cash.Commands.Move()); - return tw.accepts(); + // Simple reallocation works. + return tx.tweak(tw -> { + tw.output(outState); + tw.command(getDUMMY_PUBKEY_1(), new Cash.Commands.Move()); + return tw.verifies(); + }); }); + return Unit.INSTANCE; }); } } From a27f195b4f5780aded40e665ffc811e388604c13 Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Tue, 5 Jul 2016 12:05:19 +0100 Subject: [PATCH 082/114] core: Add LastLineShouldBeVerifiesOrFails, fix attachment primitive, Java interop --- .../core/testing/LedgerDslInterpreter.kt | 41 +++++----- .../com/r3corda/core/testing/TestDsl.kt | 82 +++++++++++-------- .../com/r3corda/core/testing/TestUtils.kt | 13 ++- .../core/testing/TransactionDslInterpreter.kt | 71 ++++++++++++---- 4 files changed, 134 insertions(+), 73 deletions(-) diff --git a/core/src/main/kotlin/com/r3corda/core/testing/LedgerDslInterpreter.kt b/core/src/main/kotlin/com/r3corda/core/testing/LedgerDslInterpreter.kt index 6a61b75d17..df999f6e5e 100644 --- a/core/src/main/kotlin/com/r3corda/core/testing/LedgerDslInterpreter.kt +++ b/core/src/main/kotlin/com/r3corda/core/testing/LedgerDslInterpreter.kt @@ -2,19 +2,24 @@ package com.r3corda.core.testing import com.r3corda.core.contracts.* import com.r3corda.core.crypto.SecureHash +import java.io.InputStream interface OutputStateLookup { fun retrieveOutputStateAndRef(clazz: Class, label: String): StateAndRef } - - -interface LedgerDslInterpreter : +interface LedgerDslInterpreter> : OutputStateLookup { - fun transaction(transactionLabel: String?, dsl: TransactionDsl.() -> Unit): WireTransaction - fun nonVerifiedTransaction(transactionLabel: String?, dsl: TransactionDsl.() -> Unit): WireTransaction - fun tweak(dsl: LedgerDsl>.() -> Unit) - fun attachment(attachment: Attachment): SecureHash + fun transaction( + transactionLabel: String?, + dsl: TransactionDsl.() -> Return + ): WireTransaction + fun nonVerifiedTransaction( + transactionLabel: String?, + dsl: TransactionDsl.() -> Unit + ): WireTransaction + fun tweak(dsl: LedgerDsl>.() -> Unit) + fun attachment(attachment: InputStream): SecureHash fun verifies() } @@ -24,13 +29,15 @@ interface LedgerDslInterpreter - > (val interpreter: LedgerInterpreter) - : LedgerDslInterpreter by interpreter { + Return, + out TransactionInterpreter: TransactionDslInterpreter, + out LedgerInterpreter: LedgerDslInterpreter + > (val interpreter: LedgerInterpreter +) : LedgerDslInterpreter> by interpreter { - fun transaction(dsl: TransactionDsl.() -> Unit) = transaction(null, dsl) - fun nonVerifiedTransaction(dsl: TransactionDsl.() -> Unit) = + fun transaction(dsl: TransactionDsl>.() -> Return) = + transaction(null, dsl) + fun nonVerifiedTransaction(dsl: TransactionDsl>.() -> Unit) = nonVerifiedTransaction(null, dsl) inline fun String.outputStateAndRef(): StateAndRef = @@ -38,12 +45,4 @@ class LedgerDsl< inline fun String.output(): TransactionState = outputStateAndRef().state fun String.outputRef(): StateRef = outputStateAndRef().ref - - fun TransactionDslInterpreter.input(state: ContractState) { - val transaction = nonVerifiedTransaction { - output { state } - } - input(transaction.outRef(0).ref) - } - fun TransactionDslInterpreter.input(stateClosure: () -> ContractState) = input(stateClosure()) } diff --git a/core/src/main/kotlin/com/r3corda/core/testing/TestDsl.kt b/core/src/main/kotlin/com/r3corda/core/testing/TestDsl.kt index ea251fe0ca..7c205b76ee 100644 --- a/core/src/main/kotlin/com/r3corda/core/testing/TestDsl.kt +++ b/core/src/main/kotlin/com/r3corda/core/testing/TestDsl.kt @@ -9,26 +9,23 @@ import com.r3corda.core.node.services.IdentityService import com.r3corda.core.node.services.StorageService import com.r3corda.core.node.services.testing.MockStorageService import com.r3corda.core.serialization.serialize +import java.io.InputStream import java.security.KeyPair import java.security.PublicKey import java.util.* -inline fun ledger( +fun ledger( identityService: IdentityService = MOCK_IDENTITY_SERVICE, storageService: StorageService = MockStorageService(), - dsl: LedgerDsl.() -> Unit -): LedgerDsl { - val ledgerDsl = LedgerDsl(TestLedgerDslInterpreter(identityService, storageService)) - dsl(ledgerDsl) - return ledgerDsl -} + dsl: LedgerDsl.() -> Unit +) = JavaTestHelpers.ledger(identityService, storageService, dsl) @Deprecated( message = "ledger doesn't nest, use tweak", replaceWith = ReplaceWith("tweak"), level = DeprecationLevel.ERROR) -fun TransactionDslInterpreter.ledger( - dsl: LedgerDsl.() -> Unit) { +fun TransactionDslInterpreter.ledger( + dsl: LedgerDsl.() -> Unit) { this.toString() dsl.toString() } @@ -37,25 +34,34 @@ fun TransactionDslInterpreter.ledger( message = "ledger doesn't nest, use tweak", replaceWith = ReplaceWith("tweak"), level = DeprecationLevel.ERROR) -fun LedgerDslInterpreter.ledger( - dsl: LedgerDsl.() -> Unit) { +fun LedgerDslInterpreter>.ledger( + dsl: LedgerDsl.() -> Unit) { this.toString() dsl.toString() } +/** If you jumped here from a compiler error make sure the last line of your test tests for a transaction verify or fail + * This is a dummy type that can only be instantiated by functions in this module. This way we can ensure that all tests + * will have as the last line either an accept or a failure test. The name is deliberately long to help make sense of + * the triggered diagnostic + */ +sealed class LastLineShouldTestForVerifiesOrFails { + internal object Token: LastLineShouldTestForVerifiesOrFails() +} + /** * This interpreter builds a transaction, and [TransactionDsl.verifies] that the resolved transaction is correct. Note * that transactions corresponding to input states are not verified. Use [LedgerDsl.verifies] for that. */ data class TestTransactionDslInterpreter( - private val ledgerInterpreter: TestLedgerDslInterpreter, + override val ledgerInterpreter: TestLedgerDslInterpreter, private val inputStateRefs: ArrayList = arrayListOf(), internal val outputStates: ArrayList = arrayListOf(), private val attachments: ArrayList = arrayListOf(), private val commands: ArrayList = arrayListOf(), private val signers: LinkedHashSet = LinkedHashSet(), private val transactionType: TransactionType = TransactionType.General() -) : TransactionDslInterpreter, OutputStateLookup { +) : TransactionDslInterpreter, OutputStateLookup by ledgerInterpreter { private fun copy(): TestTransactionDslInterpreter = TestTransactionDslInterpreter( ledgerInterpreter = ledgerInterpreter, @@ -83,7 +89,7 @@ data class TestTransactionDslInterpreter( inputStateRefs.add(stateRef) } - override fun output(label: String?, notary: Party, contractState: ContractState) { + override fun _output(label: String?, notary: Party, contractState: ContractState) { outputStates.add(LabeledOutput(label, TransactionState(contractState, notary))) } @@ -96,12 +102,13 @@ data class TestTransactionDslInterpreter( commands.add(Command(commandData, signers)) } - override fun verifies() { + override fun verifies(): LastLineShouldTestForVerifiesOrFails { val resolvedTransaction = ledgerInterpreter.resolveWireTransaction(toWireTransaction()) resolvedTransaction.verify() + return LastLineShouldTestForVerifiesOrFails.Token } - override fun failsWith(expectedMessage: String?) { + override fun failsWith(expectedMessage: String?): LastLineShouldTestForVerifiesOrFails { val exceptionThrown = try { this.verifies() false @@ -124,12 +131,16 @@ data class TestTransactionDslInterpreter( if (!exceptionThrown) { throw AssertionError("Expected exception but didn't get one") } + + return LastLineShouldTestForVerifiesOrFails.Token } - override fun tweak(dsl: TransactionDsl.() -> Unit) = - dsl(TransactionDsl(copy())) - - override fun retrieveOutputStateAndRef(clazz: Class, label: String) = ledgerInterpreter.retrieveOutputStateAndRef(clazz, label) + override fun tweak( + dsl: TransactionDsl< + LastLineShouldTestForVerifiesOrFails, + TransactionDslInterpreter + >.() -> LastLineShouldTestForVerifiesOrFails + ) = dsl(TransactionDsl(copy())) } class AttachmentResolutionException(attachmentId: SecureHash) : @@ -141,7 +152,7 @@ data class TestLedgerDslInterpreter private constructor ( internal val labelToOutputStateAndRefs: HashMap> = HashMap(), private val transactionWithLocations: HashMap = HashMap(), private val nonVerifiedTransactionWithLocations: HashMap = HashMap() -) : LedgerDslInterpreter { +) : LedgerDslInterpreter { val wireTransactions: List get() = transactionWithLocations.values.map { it.transaction } @@ -212,8 +223,9 @@ data class TestLedgerDslInterpreter private constructor ( internal fun resolveAttachment(attachmentId: SecureHash): Attachment = storageService.attachments.openAttachment(attachmentId) ?: throw AttachmentResolutionException(attachmentId) - private fun interpretTransactionDsl(dsl: TransactionDsl.() -> Unit): - TestTransactionDslInterpreter { + private fun interpretTransactionDsl( + dsl: TransactionDsl.() -> Return + ): TestTransactionDslInterpreter { val transactionInterpreter = TestTransactionDslInterpreter(this) dsl(TransactionDsl(transactionInterpreter)) return transactionInterpreter @@ -241,9 +253,9 @@ data class TestLedgerDslInterpreter private constructor ( fun outputToLabel(state: ContractState): String? = labelToOutputStateAndRefs.filter { it.value.state.data == state }.keys.firstOrNull() - private fun recordTransactionWithTransactionMap( + private fun recordTransactionWithTransactionMap( transactionLabel: String?, - dsl: TransactionDsl.() -> Unit, + dsl: TransactionDsl.() -> Return, transactionMap: HashMap = HashMap() ): WireTransaction { val transactionLocation = getCallerLocation(3) @@ -263,20 +275,24 @@ data class TestLedgerDslInterpreter private constructor ( return wireTransaction } - override fun transaction(transactionLabel: String?, dsl: TransactionDsl.() -> Unit) = - recordTransactionWithTransactionMap(transactionLabel, dsl, transactionWithLocations) + override fun transaction( + transactionLabel: String?, + dsl: TransactionDsl.() -> LastLineShouldTestForVerifiesOrFails + ) = recordTransactionWithTransactionMap(transactionLabel, dsl, transactionWithLocations) - override fun nonVerifiedTransaction(transactionLabel: String?, dsl: TransactionDsl.() -> Unit) = + override fun nonVerifiedTransaction( + transactionLabel: String?, + dsl: TransactionDsl.() -> Unit + ) = recordTransactionWithTransactionMap(transactionLabel, dsl, nonVerifiedTransactionWithLocations) override fun tweak( - dsl: LedgerDsl>.() -> Unit) = + dsl: LedgerDsl>.() -> Unit) = dsl(LedgerDsl(copy())) - override fun attachment(attachment: Attachment): SecureHash { - storageService.attachments.importAttachment(attachment.open()) - return attachment.id + override fun attachment(attachment: InputStream): SecureHash { + return storageService.attachments.importAttachment(attachment) } override fun verifies() { diff --git a/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt b/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt index 69f0fbe5df..65a4e9ae5b 100644 --- a/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt +++ b/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt @@ -6,6 +6,8 @@ import com.google.common.base.Throwables import com.google.common.net.HostAndPort import com.r3corda.core.contracts.* import com.r3corda.core.crypto.* +import com.r3corda.core.node.services.IdentityService +import com.r3corda.core.node.services.StorageService import com.r3corda.core.node.services.testing.MockIdentityService import com.r3corda.core.node.services.testing.MockStorageService import com.r3corda.core.seconds @@ -94,9 +96,16 @@ object JavaTestHelpers { @JvmStatic fun generateStateRef() = StateRef(SecureHash.randomSHA256(), 0) - @JvmStatic fun transaction(body: TransactionForTest.() -> LastLineShouldTestForAcceptOrFailure): LastLineShouldTestForAcceptOrFailure { - return body(TransactionForTest()) + @JvmStatic @JvmOverloads fun ledger( + identityService: IdentityService = MOCK_IDENTITY_SERVICE, + storageService: StorageService = MockStorageService(), + dsl: LedgerDsl.() -> Unit + ): LedgerDsl { + val ledgerDsl = LedgerDsl(TestLedgerDslInterpreter(identityService, storageService)) + dsl(ledgerDsl) + return ledgerDsl } + } val TEST_TX_TIME = JavaTestHelpers.TEST_TX_TIME diff --git a/core/src/main/kotlin/com/r3corda/core/testing/TransactionDslInterpreter.kt b/core/src/main/kotlin/com/r3corda/core/testing/TransactionDslInterpreter.kt index 262e69ee25..85cb312839 100644 --- a/core/src/main/kotlin/com/r3corda/core/testing/TransactionDslInterpreter.kt +++ b/core/src/main/kotlin/com/r3corda/core/testing/TransactionDslInterpreter.kt @@ -3,41 +3,78 @@ package com.r3corda.core.testing import com.r3corda.core.contracts.* import com.r3corda.core.crypto.Party import com.r3corda.core.crypto.SecureHash -import com.r3corda.core.node.services.IdentityService import com.r3corda.core.seconds import java.security.PublicKey import java.time.Instant +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Defines a simple DSL for building pseudo-transactions (not the same as the wire protocol) for testing purposes. +// +// Define a transaction like this: +// +// ledger { +// transaction { +// input { someExpression } +// output { someExpression } +// command { someExpression } +// +// tweak { +// ... same thing but works with a copy of the parent, can add inputs/outputs/commands just within this scope. +// } +// +// contract.verifies() -> verify() should pass +// contract `fails with` "some substring of the error message" +// } +// } +// /** - * [State] is bound at the top level. This allows the definition of e.g. [String.output], however it also means that we - * cannot mix different types of states in the same transaction. - * TODO: Move the [State] binding to the primitives' level to allow different State types, use reflection to check types - * dynamically, come up with a substitute for primitives relying on early bind + * The [TransactionDslInterpreter] defines the interface DSL interpreters should satisfy. No + * overloading/default valuing should be done here, only the basic functions that are required to implement everything. + * Same goes for functions requiring reflection e.g. [OutputStateLookup.retrieveOutputStateAndRef] + * Put convenience functions in [TransactionDsl] instead. There are some cases where the overloads would clash with the + * Interpreter interface, in these cases define a "backing" function in the interface instead (e.g. [_command]). + * + * This way the responsibility of providing a nice frontend DSL and the implementation(s) are separated */ -interface TransactionDslInterpreter : OutputStateLookup { +interface TransactionDslInterpreter : OutputStateLookup { + val ledgerInterpreter: LedgerDslInterpreter> fun input(stateRef: StateRef) - fun output(label: String?, notary: Party, contractState: ContractState) + fun _output(label: String?, notary: Party, contractState: ContractState) fun attachment(attachmentId: SecureHash) fun _command(signers: List, commandData: CommandData) - fun verifies() - fun failsWith(expectedMessage: String?) - fun tweak(dsl: TransactionDsl.() -> Unit) + fun verifies(): Return + fun failsWith(expectedMessage: String?): Return + fun tweak( + dsl: TransactionDsl>.() -> Return + ): Return } - class TransactionDsl< - out TransactionInterpreter: TransactionDslInterpreter + Return, + out TransactionInterpreter: TransactionDslInterpreter > (val interpreter: TransactionInterpreter) - : TransactionDslInterpreter by interpreter { + : TransactionDslInterpreter by interpreter { fun input(stateLabel: String) = input(retrieveOutputStateAndRef(ContractState::class.java, stateLabel).ref) + /** + * Adds the passed in state as a non-verified transaction output to the ledger and adds that as an input + */ + fun input(state: ContractState) { + val transaction = ledgerInterpreter.nonVerifiedTransaction(null) { + output { state } + } + input(transaction.outRef(0).ref) + } + fun input(stateClosure: () -> ContractState) = input(stateClosure()) - // Convenience functions - fun output(label: String? = null, notary: Party = DUMMY_NOTARY, contractStateClosure: () -> ContractState) = - output(label, notary, contractStateClosure()) @JvmOverloads - fun output(label: String? = null, contractState: ContractState) = output(label, DUMMY_NOTARY, contractState) + fun output(label: String? = null, notary: Party = DUMMY_NOTARY, contractStateClosure: () -> ContractState) = + _output(label, notary, contractStateClosure()) + @JvmOverloads + fun output(label: String? = null, contractState: ContractState) = + _output(label, DUMMY_NOTARY, contractState) fun command(vararg signers: PublicKey, commandDataClosure: () -> CommandData) = _command(listOf(*signers), commandDataClosure()) From e3d6f51049996161e84e732d8a7aec3281d1c8b4 Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Tue, 5 Jul 2016 12:10:38 +0100 Subject: [PATCH 083/114] contracts, core, node: Port TransactionForTest tests to new DSL --- .../r3corda/contracts/CommercialPaperTests.kt | 4 +- .../kotlin/com/r3corda/contracts/IRSTests.kt | 367 ++++++++++-------- .../contracts/asset/ObligationTests.kt | 10 +- .../com/r3corda/core/testing/TestUtils.kt | 172 -------- .../core/contracts/TransactionGroupTests.kt | 14 +- .../messaging/TwoPartyTradeProtocolTests.kt | 35 +- .../node/visualiser/GroupToGraphConversion.kt | 2 +- 7 files changed, 248 insertions(+), 356 deletions(-) diff --git a/contracts/src/test/kotlin/com/r3corda/contracts/CommercialPaperTests.kt b/contracts/src/test/kotlin/com/r3corda/contracts/CommercialPaperTests.kt index 8ed297d793..5073ef374e 100644 --- a/contracts/src/test/kotlin/com/r3corda/contracts/CommercialPaperTests.kt +++ b/contracts/src/test/kotlin/com/r3corda/contracts/CommercialPaperTests.kt @@ -76,6 +76,7 @@ class CommercialPaperTestsGeneric { output("paper") { thisTest.getPaper() } command(MEGA_CORP_PUBKEY) { thisTest.getIssueCommand() } timestamp(TEST_TX_TIME) + this.verifies() } // The CP is sold to alice for her $900, $100 less than the face value. At 10% interest after only 7 days, @@ -87,6 +88,7 @@ class CommercialPaperTestsGeneric { output("alice's paper") { "paper".output().data `owned by` ALICE_PUBKEY } command(ALICE_PUBKEY) { Cash.Commands.Move() } command(MEGA_CORP_PUBKEY) { thisTest.getMoveCommand() } + this.verifies() } // Time passes, and Alice redeem's her CP for $1000, netting a $100 profit. MegaCorp has received $1200 @@ -95,7 +97,7 @@ class CommercialPaperTestsGeneric { input("alice's paper") input("some profits") - fun TransactionDsl.outputs(aliceGetsBack: Amount>) { + fun TransactionDsl>.outputs(aliceGetsBack: Amount>) { output("Alice's profit") { aliceGetsBack.STATE `owned by` ALICE_PUBKEY } output("Change") { (someProfits - aliceGetsBack).STATE `owned by` MEGA_CORP_PUBKEY } } diff --git a/contracts/src/test/kotlin/com/r3corda/contracts/IRSTests.kt b/contracts/src/test/kotlin/com/r3corda/contracts/IRSTests.kt index 59faf91ffa..08b5f54411 100644 --- a/contracts/src/test/kotlin/com/r3corda/contracts/IRSTests.kt +++ b/contracts/src/test/kotlin/com/r3corda/contracts/IRSTests.kt @@ -360,7 +360,7 @@ class IRSTests { /** * Generates a typical transactional history for an IRS. */ - fun trade(): LedgerDsl { + fun trade(): LedgerDsl { val ld = LocalDate.of(2016, 3, 8) val bd = BigDecimal("0.0063518") @@ -370,6 +370,7 @@ class IRSTests { output("irs post agreement") { singleIRS() } command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } timestamp(TEST_TX_TIME) + this.verifies() } transaction("Fix") { @@ -390,82 +391,93 @@ class IRSTests { Fix(FixOf("ICE LIBOR", ld, Tenor("3M")), bd) } timestamp(TEST_TX_TIME) + this.verifies() } } } @Test fun `ensure failure occurs when there are inbound states for an agreement command`() { - transaction { - input() { singleIRS() } - output("irs post agreement") { singleIRS() } - arg(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) - this `fails requirement` "There are no in states for an agreement" + ledger { + transaction { + input() { singleIRS() } + output("irs post agreement") { singleIRS() } + command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } + timestamp(TEST_TX_TIME) + this `fails with` "There are no in states for an agreement" + } } } @Test fun `ensure failure occurs when no events in fix schedule`() { - val irs = singleIRS() - val emptySchedule = HashMap() - transaction { - output() { - irs.copy(calculation = irs.calculation.copy(fixedLegPaymentSchedule = emptySchedule)) + ledger { + val irs = singleIRS() + val emptySchedule = HashMap() + transaction { + output() { + irs.copy(calculation = irs.calculation.copy(fixedLegPaymentSchedule = emptySchedule)) + } + command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } + timestamp(TEST_TX_TIME) + this `fails with` "There are events in the fix schedule" } - arg(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) - this `fails requirement` "There are events in the fix schedule" } } @Test fun `ensure failure occurs when no events in floating schedule`() { - val irs = singleIRS() - val emptySchedule = HashMap() - transaction { - output() { - irs.copy(calculation = irs.calculation.copy(floatingLegPaymentSchedule = emptySchedule)) + ledger { + val irs = singleIRS() + val emptySchedule = HashMap() + transaction { + output() { + irs.copy(calculation = irs.calculation.copy(floatingLegPaymentSchedule = emptySchedule)) + } + command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } + timestamp(TEST_TX_TIME) + this `fails with` "There are events in the float schedule" } - arg(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) - this `fails requirement` "There are events in the float schedule" } } @Test fun `ensure notionals are non zero`() { - val irs = singleIRS() - transaction { - output() { - irs.copy(irs.fixedLeg.copy(notional = irs.fixedLeg.notional.copy(quantity = 0))) + ledger { + val irs = singleIRS() + transaction { + output() { + irs.copy(irs.fixedLeg.copy(notional = irs.fixedLeg.notional.copy(quantity = 0))) + } + command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } + timestamp(TEST_TX_TIME) + this `fails with` "All notionals must be non zero" } - arg(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) - this `fails requirement` "All notionals must be non zero" - } - transaction { - output() { - irs.copy(irs.fixedLeg.copy(notional = irs.floatingLeg.notional.copy(quantity = 0))) + transaction { + output() { + irs.copy(irs.fixedLeg.copy(notional = irs.floatingLeg.notional.copy(quantity = 0))) + } + command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } + timestamp(TEST_TX_TIME) + this `fails with` "All notionals must be non zero" } - arg(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) - this `fails requirement` "All notionals must be non zero" } } @Test fun `ensure positive rate on fixed leg`() { - val irs = singleIRS() - val modifiedIRS = irs.copy(fixedLeg = irs.fixedLeg.copy(fixedRate = FixedRate(PercentageRatioUnit("-0.1")))) - transaction { - output() { - modifiedIRS + ledger { + val irs = singleIRS() + val modifiedIRS = irs.copy(fixedLeg = irs.fixedLeg.copy(fixedRate = FixedRate(PercentageRatioUnit("-0.1")))) + transaction { + output() { + modifiedIRS + } + command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } + timestamp(TEST_TX_TIME) + this `fails with` "The fixed leg rate must be positive" } - arg(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) - this `fails requirement` "The fixed leg rate must be positive" } } @@ -474,173 +486,183 @@ class IRSTests { */ @Test fun `ensure same currency notionals`() { - val irs = singleIRS() - val modifiedIRS = irs.copy(fixedLeg = irs.fixedLeg.copy(notional = Amount(irs.fixedLeg.notional.quantity, Currency.getInstance("JPY")))) - transaction { - output() { - modifiedIRS + ledger { + val irs = singleIRS() + val modifiedIRS = irs.copy(fixedLeg = irs.fixedLeg.copy(notional = Amount(irs.fixedLeg.notional.quantity, Currency.getInstance("JPY")))) + transaction { + output() { + modifiedIRS + } + command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } + timestamp(TEST_TX_TIME) + this `fails with` "The currency of the notionals must be the same" } - arg(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) - this `fails requirement` "The currency of the notionals must be the same" } } @Test fun `ensure notional amounts are equal`() { - val irs = singleIRS() - val modifiedIRS = irs.copy(fixedLeg = irs.fixedLeg.copy(notional = Amount(irs.floatingLeg.notional.quantity + 1, irs.floatingLeg.notional.token))) - transaction { - output() { - modifiedIRS + ledger { + val irs = singleIRS() + val modifiedIRS = irs.copy(fixedLeg = irs.fixedLeg.copy(notional = Amount(irs.floatingLeg.notional.quantity + 1, irs.floatingLeg.notional.token))) + transaction { + output() { + modifiedIRS + } + command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } + timestamp(TEST_TX_TIME) + this `fails with` "All leg notionals must be the same" } - arg(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) - this `fails requirement` "All leg notionals must be the same" } } @Test fun `ensure trade date and termination date checks are done pt1`() { - val irs = singleIRS() - val modifiedIRS1 = irs.copy(fixedLeg = irs.fixedLeg.copy(terminationDate = irs.fixedLeg.effectiveDate.minusDays(1))) - transaction { - output() { - modifiedIRS1 + ledger { + val irs = singleIRS() + val modifiedIRS1 = irs.copy(fixedLeg = irs.fixedLeg.copy(terminationDate = irs.fixedLeg.effectiveDate.minusDays(1))) + transaction { + output() { + modifiedIRS1 + } + command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } + timestamp(TEST_TX_TIME) + this `fails with` "The effective date is before the termination date for the fixed leg" } - arg(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) - this `fails requirement` "The effective date is before the termination date for the fixed leg" - } - val modifiedIRS2 = irs.copy(floatingLeg = irs.floatingLeg.copy(terminationDate = irs.floatingLeg.effectiveDate.minusDays(1))) - transaction { - output() { - modifiedIRS2 + val modifiedIRS2 = irs.copy(floatingLeg = irs.floatingLeg.copy(terminationDate = irs.floatingLeg.effectiveDate.minusDays(1))) + transaction { + output() { + modifiedIRS2 + } + command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } + timestamp(TEST_TX_TIME) + this `fails with` "The effective date is before the termination date for the floating leg" } - arg(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) - this `fails requirement` "The effective date is before the termination date for the floating leg" } } @Test fun `ensure trade date and termination date checks are done pt2`() { - val irs = singleIRS() + ledger { + val irs = singleIRS() - val modifiedIRS3 = irs.copy(floatingLeg = irs.floatingLeg.copy(terminationDate = irs.fixedLeg.terminationDate.minusDays(1))) - transaction { - output() { - modifiedIRS3 + val modifiedIRS3 = irs.copy(floatingLeg = irs.floatingLeg.copy(terminationDate = irs.fixedLeg.terminationDate.minusDays(1))) + transaction { + output() { + modifiedIRS3 + } + command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } + timestamp(TEST_TX_TIME) + this `fails with` "The termination dates are aligned" } - arg(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) - this `fails requirement` "The termination dates are aligned" - } - val modifiedIRS4 = irs.copy(floatingLeg = irs.floatingLeg.copy(effectiveDate = irs.fixedLeg.effectiveDate.minusDays(1))) - transaction { - output() { - modifiedIRS4 + val modifiedIRS4 = irs.copy(floatingLeg = irs.floatingLeg.copy(effectiveDate = irs.fixedLeg.effectiveDate.minusDays(1))) + transaction { + output() { + modifiedIRS4 + } + command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } + timestamp(TEST_TX_TIME) + this `fails with` "The effective dates are aligned" } - arg(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) - this `fails requirement` "The effective dates are aligned" } } @Test fun `various fixing tests`() { + ledger { - val ld = LocalDate.of(2016, 3, 8) - val bd = BigDecimal("0.0063518") - - transaction { - output("irs post agreement") { singleIRS() } - arg(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) - this.accepts() - } - - val oldIRS = singleIRS(1) - val newIRS = oldIRS.copy(oldIRS.fixedLeg, - oldIRS.floatingLeg, - oldIRS.calculation.applyFixing(ld, FixedRate(RatioUnit(bd))), - oldIRS.common) - - transaction { - input() { - oldIRS + val ld = LocalDate.of(2016, 3, 8) + val bd = BigDecimal("0.0063518") + transaction { + output("irs post agreement") { singleIRS() } + command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } + timestamp(TEST_TX_TIME) + this.verifies() } - // Templated tweak for reference. A corrent fixing applied should be ok - tweak { - arg(ORACLE_PUBKEY) { - InterestRateSwap.Commands.Fix() - } - timestamp(TEST_TX_TIME) - arg(ORACLE_PUBKEY) { - Fix(FixOf("ICE LIBOR", ld, Tenor("3M")), bd) - } - output() { newIRS } - this.accepts() - } + val oldIRS = singleIRS(1) + val newIRS = oldIRS.copy(oldIRS.fixedLeg, + oldIRS.floatingLeg, + oldIRS.calculation.applyFixing(ld, FixedRate(RatioUnit(bd))), + oldIRS.common) - // This test makes sure that verify confirms the fixing was applied and there is a difference in the old and new - tweak { - arg(ORACLE_PUBKEY) { InterestRateSwap.Commands.Fix() } - timestamp(TEST_TX_TIME) - arg(ORACLE_PUBKEY) { Fix(FixOf("ICE LIBOR", ld, Tenor("3M")), bd) } - output() { oldIRS } - this`fails requirement` "There is at least one difference in the IRS floating leg payment schedules" - } + transaction { + input() { + oldIRS - // This tests tries to sneak in a change to another fixing (which may or may not be the latest one) - tweak { - arg(ORACLE_PUBKEY) { InterestRateSwap.Commands.Fix() } - timestamp(TEST_TX_TIME) - arg(ORACLE_PUBKEY) { - Fix(FixOf("ICE LIBOR", ld, Tenor("3M")), bd) } - val firstResetKey = newIRS.calculation.floatingLegPaymentSchedule.keys.first() - val firstResetValue = newIRS.calculation.floatingLegPaymentSchedule[firstResetKey] - val modifiedFirstResetValue = firstResetValue!!.copy(notional = Amount(firstResetValue.notional.quantity, Currency.getInstance("JPY"))) - - output() { - newIRS.copy( - newIRS.fixedLeg, - newIRS.floatingLeg, - newIRS.calculation.copy(floatingLegPaymentSchedule = newIRS.calculation.floatingLegPaymentSchedule.plus( - Pair(firstResetKey, modifiedFirstResetValue))), - newIRS.common - ) + // Templated tweak for reference. A corrent fixing applied should be ok + tweak { + command(ORACLE_PUBKEY) { + InterestRateSwap.Commands.Fix() + } + timestamp(TEST_TX_TIME) + command(ORACLE_PUBKEY) { + Fix(FixOf("ICE LIBOR", ld, Tenor("3M")), bd) + } + output() { newIRS } + this.verifies() } - this`fails requirement` "There is only one change in the IRS floating leg payment schedule" - } - // This tests modifies the payment currency for the fixing - tweak { - arg(ORACLE_PUBKEY) { InterestRateSwap.Commands.Fix() } - timestamp(TEST_TX_TIME) - arg(ORACLE_PUBKEY) { Fix(FixOf("ICE LIBOR", ld, Tenor("3M")), bd) } - - val latestReset = newIRS.calculation.floatingLegPaymentSchedule.filter { it.value.rate is FixedRate }.maxBy { it.key } - val modifiedLatestResetValue = latestReset!!.value.copy(notional = Amount(latestReset.value.notional.quantity, Currency.getInstance("JPY"))) - - output() { - newIRS.copy( - newIRS.fixedLeg, - newIRS.floatingLeg, - newIRS.calculation.copy(floatingLegPaymentSchedule = newIRS.calculation.floatingLegPaymentSchedule.plus( - Pair(latestReset.key, modifiedLatestResetValue))), - newIRS.common - ) + // This test makes sure that verify confirms the fixing was applied and there is a difference in the old and new + tweak { + command(ORACLE_PUBKEY) { InterestRateSwap.Commands.Fix() } + timestamp(TEST_TX_TIME) + command(ORACLE_PUBKEY) { Fix(FixOf("ICE LIBOR", ld, Tenor("3M")), bd) } + output() { oldIRS } + this `fails with` "There is at least one difference in the IRS floating leg payment schedules" + } + + // This tests tries to sneak in a change to another fixing (which may or may not be the latest one) + tweak { + command(ORACLE_PUBKEY) { InterestRateSwap.Commands.Fix() } + timestamp(TEST_TX_TIME) + command(ORACLE_PUBKEY) { + Fix(FixOf("ICE LIBOR", ld, Tenor("3M")), bd) + } + + val firstResetKey = newIRS.calculation.floatingLegPaymentSchedule.keys.first() + val firstResetValue = newIRS.calculation.floatingLegPaymentSchedule[firstResetKey] + val modifiedFirstResetValue = firstResetValue!!.copy(notional = Amount(firstResetValue.notional.quantity, Currency.getInstance("JPY"))) + + output() { + newIRS.copy( + newIRS.fixedLeg, + newIRS.floatingLeg, + newIRS.calculation.copy(floatingLegPaymentSchedule = newIRS.calculation.floatingLegPaymentSchedule.plus( + Pair(firstResetKey, modifiedFirstResetValue))), + newIRS.common + ) + } + this `fails with` "There is only one change in the IRS floating leg payment schedule" + } + + // This tests modifies the payment currency for the fixing + tweak { + command(ORACLE_PUBKEY) { InterestRateSwap.Commands.Fix() } + timestamp(TEST_TX_TIME) + command(ORACLE_PUBKEY) { Fix(FixOf("ICE LIBOR", ld, Tenor("3M")), bd) } + + val latestReset = newIRS.calculation.floatingLegPaymentSchedule.filter { it.value.rate is FixedRate }.maxBy { it.key } + val modifiedLatestResetValue = latestReset!!.value.copy(notional = Amount(latestReset.value.notional.quantity, Currency.getInstance("JPY"))) + + output() { + newIRS.copy( + newIRS.fixedLeg, + newIRS.floatingLeg, + newIRS.calculation.copy(floatingLegPaymentSchedule = newIRS.calculation.floatingLegPaymentSchedule.plus( + Pair(latestReset.key, modifiedLatestResetValue))), + newIRS.common + ) + } + this `fails with` "The fix payment has the same currency as the notional" } - this`fails requirement` "The fix payment has the same currency as the notional" } } } @@ -652,7 +674,7 @@ class IRSTests { * result and the grouping won't work either. * In reality, the only fields that should be in common will be the next fixing date and the reference rate. */ - fun tradegroups(): LedgerDsl { + fun tradegroups(): LedgerDsl { val ld1 = LocalDate.of(2016, 3, 8) val bd1 = BigDecimal("0.0063518") @@ -670,6 +692,7 @@ class IRSTests { } command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } timestamp(TEST_TX_TIME) + this.verifies() } transaction("Agreement") { @@ -683,6 +706,7 @@ class IRSTests { } command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } timestamp(TEST_TX_TIME) + this.verifies() } transaction("Fix") { @@ -714,6 +738,7 @@ class IRSTests { Fix(FixOf("ICE LIBOR", ld1, Tenor("3M")), bd1) } timestamp(TEST_TX_TIME) + this.verifies() } } } diff --git a/contracts/src/test/kotlin/com/r3corda/contracts/asset/ObligationTests.kt b/contracts/src/test/kotlin/com/r3corda/contracts/asset/ObligationTests.kt index f09a2e55fc..6cc13e440b 100644 --- a/contracts/src/test/kotlin/com/r3corda/contracts/asset/ObligationTests.kt +++ b/contracts/src/test/kotlin/com/r3corda/contracts/asset/ObligationTests.kt @@ -33,7 +33,9 @@ class ObligationTests { ) val outState = inState.copy(beneficiary = DUMMY_PUBKEY_2) - private fun obligationTestRoots(group: LedgerDsl) = group.apply { + private fun obligationTestRoots( + group: LedgerDsl + ) = group.apply { nonVerifiedTransaction { output("Alice's $1,000,000 obligation to Bob", oneMillionDollars.OBLIGATION `between` Pair(ALICE, BOB_PUBKEY)) output("Bob's $1,000,000 obligation to Alice", oneMillionDollars.OBLIGATION `between` Pair(BOB, ALICE_PUBKEY)) @@ -341,6 +343,7 @@ class ObligationTests { // Note we can sign with either key here command(ALICE_PUBKEY) { Obligation.Commands.Net(NetType.CLOSE_OUT) } timestamp(TEST_TX_TIME) + this.verifies() } this.verifies() } @@ -356,6 +359,7 @@ class ObligationTests { output("change") { oneMillionDollars.OBLIGATION `between` Pair(MEGA_CORP, BOB_PUBKEY) } command(BOB_PUBKEY, MEGA_CORP_PUBKEY) { Obligation.Commands.Net(NetType.CLOSE_OUT) } timestamp(TEST_TX_TIME) + this.verifies() } this.verifies() } @@ -397,6 +401,7 @@ class ObligationTests { input("Bob's $1,000,000 obligation to Alice") command(ALICE_PUBKEY, BOB_PUBKEY) { Obligation.Commands.Net(NetType.PAYMENT) } timestamp(TEST_TX_TIME) + this.verifies() } this.verifies() } @@ -423,6 +428,7 @@ class ObligationTests { output("MegaCorp's $1,000,000 obligation to Alice") { oneMillionDollars.OBLIGATION `between` Pair(MEGA_CORP, ALICE_PUBKEY) } command(ALICE_PUBKEY, BOB_PUBKEY, MEGA_CORP_PUBKEY) { Obligation.Commands.Net(NetType.PAYMENT) } timestamp(TEST_TX_TIME) + this.verifies() } this.verifies() } @@ -452,6 +458,7 @@ class ObligationTests { output("Bob's $1,000,000") { 1000000.DOLLARS.CASH `issued by` defaultIssuer `owned by` BOB_PUBKEY } command(ALICE_PUBKEY) { Obligation.Commands.Settle(Obligation.IssuanceDefinition(ALICE, defaultUsd.OBLIGATION_DEF), Amount(oneMillionDollars.quantity, USD)) } command(ALICE_PUBKEY) { Cash.Commands.Move(Obligation().legalContractReference) } + this.verifies() } this.verifies() } @@ -496,6 +503,7 @@ class ObligationTests { output("Alice's defaulted $1,000,000 obligation to Bob") { (oneMillionDollars.OBLIGATION `between` Pair(ALICE, BOB_PUBKEY) `at` pastTestTime).copy(lifecycle = Lifecycle.DEFAULTED) } command(BOB_PUBKEY) { Obligation.Commands.SetLifecycle(Obligation.IssuanceDefinition(ALICE, defaultUsd.OBLIGATION_DEF) `at` pastTestTime, Lifecycle.DEFAULTED) } timestamp(TEST_TX_TIME) + this.verifies() } this.verifies() } diff --git a/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt b/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt index 65a4e9ae5b..bb57eec96f 100644 --- a/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt +++ b/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt @@ -10,16 +10,10 @@ import com.r3corda.core.node.services.IdentityService import com.r3corda.core.node.services.StorageService import com.r3corda.core.node.services.testing.MockIdentityService import com.r3corda.core.node.services.testing.MockStorageService -import com.r3corda.core.seconds -import com.r3corda.core.serialization.serialize import java.net.ServerSocket import java.security.KeyPair import java.security.PublicKey import java.time.Instant -import java.util.* -import kotlin.test.assertEquals -import kotlin.test.assertFailsWith -import kotlin.test.fail /** If an exception is thrown by the body, rethrows the root cause exception. */ inline fun rootCauseExceptions(body: () -> R): R { @@ -132,27 +126,6 @@ val MOCK_IDENTITY_SERVICE = JavaTestHelpers.MOCK_IDENTITY_SERVICE fun generateStateRef() = JavaTestHelpers.generateStateRef() -fun transaction(body: TransactionForTest.() -> LastLineShouldTestForAcceptOrFailure) = JavaTestHelpers.transaction(body) - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// -// Defines a simple DSL for building pseudo-transactions (not the same as the wire protocol) for testing purposes. -// -// Define a transaction like this: -// -// transaction { -// input { someExpression } -// output { someExpression } -// arg { someExpression } -// -// tweak { -// ... same thing but works with a copy of the parent, can add inputs/outputs/args just within this scope. -// } -// -// contract.accepts() -> should pass -// contract `fails requirement` "some substring of the error message" -// } -// class LabeledOutput(val label: String?, val state: TransactionState<*>) { override fun toString() = state.toString() + (if (label != null) " ($label)" else "") override fun equals(other: Any?) = other is LabeledOutput && state.equals(other.state) @@ -161,148 +134,3 @@ class LabeledOutput(val label: String?, val state: TransactionState<*>) { infix fun TransactionState<*>.label(label: String) = LabeledOutput(label, this) -abstract class AbstractTransactionForTest { - protected val attachments = ArrayList() - protected val outStates = ArrayList() - protected val commands = ArrayList() - protected val signers = LinkedHashSet() - protected val type = TransactionType.General() - - @JvmOverloads - open fun output(label: String? = null, s: () -> ContractState) = LabeledOutput(label, TransactionState(s(), DUMMY_NOTARY)).apply { outStates.add(this) } - @JvmOverloads - open fun output(label: String? = null, s: ContractState) = output(label) { s } - - protected fun commandsToAuthenticatedObjects(): List> { - return commands.map { AuthenticatedObject(it.signers, it.signers.mapNotNull { MOCK_IDENTITY_SERVICE.partyFromKey(it) }, it.value) } - } - - fun attachment(attachmentID: SecureHash) { - attachments.add(attachmentID) - } - - fun arg(vararg keys: PublicKey, c: () -> CommandData) { - val keysList = listOf(*keys) - addCommand(Command(c(), keysList)) - } - fun arg(key: PublicKey, c: CommandData) = arg(key) { c } - - fun timestamp(time: Instant) { - val data = TimestampCommand(time, 30.seconds) - timestamp(data) - } - - fun timestamp(data: TimestampCommand) { - addCommand(Command(data, DUMMY_NOTARY.owningKey)) - } - - fun addCommand(cmd: Command) { - signers.addAll(cmd.signers) - commands.add(cmd) - } - - // Forbid patterns like: transaction { ... transaction { ... } } - @Deprecated("Cannot nest transactions, use tweak", level = DeprecationLevel.ERROR) - fun transaction(body: TransactionForTest.() -> LastLineShouldTestForAcceptOrFailure) { - } -} - -/** If you jumped here from a compiler error make sure the last line of your test tests for a transaction accept or fail - * This is a dummy type that can only be instantiated by functions in this module. This way we can ensure that all tests - * will have as the last line either an accept or a failure test. The name is deliberately long to help make sense of - * the triggered diagnostic - */ -sealed class LastLineShouldTestForAcceptOrFailure { - internal object Token: LastLineShouldTestForAcceptOrFailure() -} - -// Corresponds to the args to Contract.verify -// Note on defaults: try to avoid Kotlin defaults as they don't work from Java. Instead define overloads -open class TransactionForTest : AbstractTransactionForTest() { - private val inStates = arrayListOf>() - - fun input(s: () -> ContractState) { - signers.add(DUMMY_NOTARY.owningKey) - inStates.add(TransactionState(s(), DUMMY_NOTARY)) - } - fun input(s: ContractState) = input { s } - - protected fun runCommandsAndVerify() { - val cmds = commandsToAuthenticatedObjects() - val tx = TransactionForVerification(inStates, outStates.map { it.state }, emptyList(), cmds, SecureHash.Companion.randomSHA256(), signers.toList(), type) - tx.verify() - } - - fun accepts(): LastLineShouldTestForAcceptOrFailure { - runCommandsAndVerify() - return LastLineShouldTestForAcceptOrFailure.Token - } - - @JvmOverloads - fun rejects(withMessage: String? = null): LastLineShouldTestForAcceptOrFailure { - val r = try { - runCommandsAndVerify() - false - } catch (e: Exception) { - val m = e.message - if (m == null) - fail("Threw exception without a message") - else - if (withMessage != null && !m.toLowerCase().contains(withMessage.toLowerCase())) throw AssertionError("Error was actually: $m", e) - true - } - if (!r) throw AssertionError("Expected exception but didn't get one") - return LastLineShouldTestForAcceptOrFailure.Token - } - - /** - * Used to confirm that the test, when (implicitly) run against the .verify() method, fails with the text of the message - */ - infix fun `fails requirement`(msg: String): LastLineShouldTestForAcceptOrFailure = rejects(msg) - fun failsRequirement(msg: String) = this.`fails requirement`(msg) - - // Use this to create transactions where the output of this transaction is automatically used as an input of - // the next. - fun chain(vararg outputLabels: String, body: TransactionForTest.() -> LastLineShouldTestForAcceptOrFailure): TransactionForTest { - val states = outStates.mapNotNull { - val l = it.label - if (l != null && outputLabels.contains(l)) - it.state - else - null - } - val tx = TransactionForTest() - tx.inStates.addAll(states) - tx.body() - return tx - } - - // Allow customisation of partial transactions. - fun tweak(body: TransactionForTest.() -> LastLineShouldTestForAcceptOrFailure): LastLineShouldTestForAcceptOrFailure { - val tx = TransactionForTest() - tx.inStates.addAll(inStates) - tx.outStates.addAll(outStates) - tx.commands.addAll(commands) - - tx.signers.addAll(tx.inStates.map { it.notary.owningKey }) - tx.signers.addAll(commands.flatMap { it.signers }) - return tx.body() - } - - override fun toString(): String { - return """transaction { - inputs: $inStates - outputs: $outStates - commands $commands - }""" - } - - override fun equals(other: Any?) = this === other || (other is TransactionForTest && inStates == other.inStates && outStates == other.outStates && commands == other.commands) - - override fun hashCode(): Int { - var result = inStates.hashCode() - result += 31 * result + outStates.hashCode() - result += 31 * result + commands.hashCode() - return result - } -} diff --git a/core/src/test/kotlin/com/r3corda/core/contracts/TransactionGroupTests.kt b/core/src/test/kotlin/com/r3corda/core/contracts/TransactionGroupTests.kt index fdefad885b..e8548db65d 100644 --- a/core/src/test/kotlin/com/r3corda/core/contracts/TransactionGroupTests.kt +++ b/core/src/test/kotlin/com/r3corda/core/contracts/TransactionGroupTests.kt @@ -56,15 +56,17 @@ class TransactionGroupTests { input("£1000") output("alice's £1000") { A_THOUSAND_POUNDS `owned by` ALICE_PUBKEY } command(MINI_CORP_PUBKEY) { TestCash.Commands.Move() } + this.verifies() } transaction { input("alice's £1000") command(ALICE_PUBKEY) { TestCash.Commands.Move() } command(MINI_CORP_PUBKEY) { TestCash.Commands.Exit(1000.POUNDS) } + this.verifies() } - verifies() + this.verifies() } } @@ -74,6 +76,7 @@ class TransactionGroupTests { val t = transaction { output("cash") { A_THOUSAND_POUNDS } command(MINI_CORP_PUBKEY) { TestCash.Commands.Issue() } + this.verifies() } val conflict1 = transaction { @@ -82,6 +85,7 @@ class TransactionGroupTests { output { HALF } output { HALF } command(MINI_CORP_PUBKEY) { TestCash.Commands.Move() } + this.verifies() } verifies() @@ -93,6 +97,7 @@ class TransactionGroupTests { output { HALF } output { HALF } command(MINI_CORP_PUBKEY) { TestCash.Commands.Move() } + this.verifies() } assertNotEquals(conflict1, conflict2) @@ -112,11 +117,13 @@ class TransactionGroupTests { transaction { output("cash") { A_THOUSAND_POUNDS } command(MINI_CORP_PUBKEY) { TestCash.Commands.Issue() } + this.verifies() } transaction { input("cash") output { A_THOUSAND_POUNDS `owned by` BOB_PUBKEY } + this.verifies() } } @@ -126,6 +133,7 @@ class TransactionGroupTests { assertFailsWith(TransactionResolutionException::class) { input(input.ref) } + this.verifies() } } } @@ -143,6 +151,7 @@ class TransactionGroupTests { input("£1000") output { A_THOUSAND_POUNDS.copy(amount = A_THOUSAND_POUNDS.amount * 2) } command(MINI_CORP_PUBKEY) { TestCash.Commands.Move() } + this.verifies() } assertFailsWith(TransactionConflictException::class) { @@ -157,18 +166,21 @@ class TransactionGroupTests { transaction { output("£1000") { A_THOUSAND_POUNDS } command(MINI_CORP_PUBKEY) { TestCash.Commands.Issue() } + this.verifies() } transaction { input("£1000") output("alice's £1000") { A_THOUSAND_POUNDS `owned by` ALICE_PUBKEY } command(MINI_CORP_PUBKEY) { TestCash.Commands.Move() } + this.verifies() } transaction { input("alice's £1000") command(ALICE_PUBKEY) { TestCash.Commands.Move() } command(MINI_CORP_PUBKEY) { TestCash.Commands.Exit(1000.POUNDS) } + this.verifies() } }.interpreter.wireTransactions.let { signAll(it) } diff --git a/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt b/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt index bdc365d599..e703d9306b 100644 --- a/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt +++ b/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt @@ -17,6 +17,7 @@ import com.r3corda.core.node.services.ServiceType import com.r3corda.core.node.services.TransactionStorage import com.r3corda.core.node.services.Wallet import com.r3corda.core.random63BitValue +import com.r3corda.core.contracts.Attachment import com.r3corda.core.seconds import com.r3corda.core.testing.* import com.r3corda.core.utilities.BriefLogFormatter @@ -249,10 +250,11 @@ class TwoPartyTradeProtocolTests { @Test fun `check dependencies of sale asset are resolved`() { - ledger { - val notaryNode = net.createNotaryNode(DUMMY_NOTARY.name, DUMMY_NOTARY_KEY) - val aliceNode = makeNodeWithTracking(notaryNode.info, ALICE.name, ALICE_KEY) - val bobNode = makeNodeWithTracking(notaryNode.info, BOB.name, BOB_KEY) + val notaryNode = net.createNotaryNode(DUMMY_NOTARY.name, DUMMY_NOTARY_KEY) + val aliceNode = makeNodeWithTracking(notaryNode.info, ALICE.name, ALICE_KEY) + val bobNode = makeNodeWithTracking(notaryNode.info, BOB.name, BOB_KEY) + + ledger(storageService = aliceNode.storage) { // Insert a prospectus type attachment into the commercial paper transaction. val stream = ByteArrayOutputStream() @@ -261,7 +263,7 @@ class TwoPartyTradeProtocolTests { it.write("Our commercial paper is top notch stuff".toByteArray()) it.closeEntry() } - val attachmentID = aliceNode.storage.attachments.importAttachment(ByteArrayInputStream(stream.toByteArray())) + val attachmentID = attachment(ByteArrayInputStream(stream.toByteArray())) val issuer = MEGA_CORP.ref(1) val bobsFakeCash = fillUpForBuyer(false, bobNode.keyManagement.freshKey().public, issuer).second @@ -365,8 +367,11 @@ class TwoPartyTradeProtocolTests { } } - private fun LedgerDsl>.runWithError(bobError: Boolean, aliceError: Boolean, - expectedMessageSubstring: String) { + private fun LedgerDsl.runWithError( + bobError: Boolean, + aliceError: Boolean, + expectedMessageSubstring: String + ) { val notaryNode = net.createNotaryNode(DUMMY_NOTARY.name, DUMMY_NOTARY_KEY) val aliceNode = net.createPartyNode(notaryNode.info, ALICE.name, ALICE_KEY) val bobNode = net.createPartyNode(notaryNode.info, BOB.name, BOB_KEY) @@ -427,7 +432,7 @@ class TwoPartyTradeProtocolTests { return signed.associateBy { it.id } } - private fun LedgerDsl>.fillUpForBuyer( + private fun LedgerDsl.fillUpForBuyer( withError: Boolean, owner: PublicKey = BOB_PUBKEY, issuer: PartyAndReference = MEGA_CORP.ref(1)): Pair> { @@ -441,6 +446,11 @@ class TwoPartyTradeProtocolTests { if (!withError) command(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() } timestamp(TEST_TX_TIME) + if (withError) { + this.fails() + } else { + this.verifies() + } } // Bob gets some cash onto the ledger from BoE @@ -448,6 +458,7 @@ class TwoPartyTradeProtocolTests { input("elbonian money 1") output("bob cash 1") { 800.DOLLARS.CASH `issued by` issuer `owned by` owner } command(MEGA_CORP_PUBKEY) { Cash.Commands.Move() } + this.verifies() } val bc2 = transaction { @@ -455,13 +466,14 @@ class TwoPartyTradeProtocolTests { output("bob cash 2") { 300.DOLLARS.CASH `issued by` issuer `owned by` owner } output { 700.DOLLARS.CASH `issued by` issuer `owned by` MEGA_CORP_PUBKEY } // Change output. command(MEGA_CORP_PUBKEY) { Cash.Commands.Move() } + this.verifies() } val wallet = Wallet(listOf("bob cash 1".outputStateAndRef(), "bob cash 2".outputStateAndRef())) return Pair(wallet, listOf(eb1, bc1, bc2)) } - private fun LedgerDsl>.fillUpForSeller( + private fun LedgerDsl.fillUpForSeller( withError: Boolean, owner: PublicKey, amount: Amount>, @@ -476,6 +488,11 @@ class TwoPartyTradeProtocolTests { command(notary.owningKey) { TimestampCommand(TEST_TX_TIME, 30.seconds) } if (attachmentID != null) attachment(attachmentID) + if (withError) { + this.fails() + } else { + this.verifies() + } } val wallet = Wallet(listOf("alice's paper".outputStateAndRef())) diff --git a/node/src/test/kotlin/com/r3corda/node/visualiser/GroupToGraphConversion.kt b/node/src/test/kotlin/com/r3corda/node/visualiser/GroupToGraphConversion.kt index ae7ca111b2..1285522a62 100644 --- a/node/src/test/kotlin/com/r3corda/node/visualiser/GroupToGraphConversion.kt +++ b/node/src/test/kotlin/com/r3corda/node/visualiser/GroupToGraphConversion.kt @@ -9,7 +9,7 @@ import org.graphstream.graph.Node import org.graphstream.graph.implementations.SingleGraph import kotlin.reflect.memberProperties -class GraphVisualiser(val dsl: LedgerDsl) { +class GraphVisualiser(val dsl: LedgerDsl) { companion object { val css = GraphVisualiser::class.java.getResourceAsStream("graph.css").bufferedReader().readText() } From e31b769fefd3fa0f1f34116cd6344b2ccf9fdc6d Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Tue, 5 Jul 2016 18:43:49 +0100 Subject: [PATCH 084/114] test dsl: Dsl->DSL, add top-level transaction primitive, add ledger-embedded signAll, other cosmetics --- .../r3corda/contracts/CommercialPaperTests.kt | 57 +- .../kotlin/com/r3corda/contracts/IRSTests.kt | 206 +++---- .../contracts/asset/ObligationTests.kt | 547 +++++++++--------- .../core/testing/LedgerDSLInterpreter.kt | 37 ++ .../core/testing/LedgerDslInterpreter.kt | 48 -- .../core/testing/{TestDsl.kt => TestDSL.kt} | 163 +++--- .../com/r3corda/core/testing/TestUtils.kt | 13 +- ...preter.kt => TransactionDSLInterpreter.kt} | 25 +- .../core/contracts/TransactionGroupTests.kt | 20 +- .../messaging/TwoPartyTradeProtocolTests.kt | 9 +- .../node/visualiser/GroupToGraphConversion.kt | 2 +- 11 files changed, 531 insertions(+), 596 deletions(-) create mode 100644 core/src/main/kotlin/com/r3corda/core/testing/LedgerDSLInterpreter.kt delete mode 100644 core/src/main/kotlin/com/r3corda/core/testing/LedgerDslInterpreter.kt rename core/src/main/kotlin/com/r3corda/core/testing/{TestDsl.kt => TestDSL.kt} (70%) rename core/src/main/kotlin/com/r3corda/core/testing/{TransactionDslInterpreter.kt => TransactionDSLInterpreter.kt} (80%) diff --git a/contracts/src/test/kotlin/com/r3corda/contracts/CommercialPaperTests.kt b/contracts/src/test/kotlin/com/r3corda/contracts/CommercialPaperTests.kt index 5073ef374e..44a6d12700 100644 --- a/contracts/src/test/kotlin/com/r3corda/contracts/CommercialPaperTests.kt +++ b/contracts/src/test/kotlin/com/r3corda/contracts/CommercialPaperTests.kt @@ -66,7 +66,7 @@ class CommercialPaperTestsGeneric { fun `trade lifecycle test`() { val someProfits = 1200.DOLLARS `issued by` issuer ledger { - nonVerifiedTransaction { + unverifiedTransaction { output("alice's $900", 900.DOLLARS.CASH `issued by` issuer `owned by` ALICE_PUBKEY) output("some profits", someProfits.STATE `owned by` MEGA_CORP_PUBKEY) } @@ -97,7 +97,7 @@ class CommercialPaperTestsGeneric { input("alice's paper") input("some profits") - fun TransactionDsl>.outputs(aliceGetsBack: Amount>) { + fun TransactionDSL>.outputs(aliceGetsBack: Amount>) { output("Alice's profit") { aliceGetsBack.STATE `owned by` ALICE_PUBKEY } output("Change") { (someProfits - aliceGetsBack).STATE `owned by` MEGA_CORP_PUBKEY } } @@ -131,53 +131,42 @@ class CommercialPaperTestsGeneric { @Test fun `key mismatch at issue`() { - ledger { - transaction { - output { thisTest.getPaper() } - command(DUMMY_PUBKEY_1) { thisTest.getIssueCommand() } - timestamp(TEST_TX_TIME) - this `fails with` "signed by the claimed issuer" - } + transaction { + output { thisTest.getPaper() } + command(DUMMY_PUBKEY_1) { thisTest.getIssueCommand() } + timestamp(TEST_TX_TIME) + this `fails with` "signed by the claimed issuer" } } @Test fun `face value is not zero`() { - ledger { - transaction { - output { thisTest.getPaper().withFaceValue(0.DOLLARS `issued by` issuer) } - command(MEGA_CORP_PUBKEY) { thisTest.getIssueCommand() } - timestamp(TEST_TX_TIME) - this `fails with` "face value is not zero" - } + transaction { + output { thisTest.getPaper().withFaceValue(0.DOLLARS `issued by` issuer) } + command(MEGA_CORP_PUBKEY) { thisTest.getIssueCommand() } + timestamp(TEST_TX_TIME) + this `fails with` "face value is not zero" } } @Test fun `maturity date not in the past`() { - ledger { - transaction { - output { thisTest.getPaper().withMaturityDate(TEST_TX_TIME - 10.days) } - command(MEGA_CORP_PUBKEY) { thisTest.getIssueCommand() } - timestamp(TEST_TX_TIME) - this `fails with` "maturity date is not in the past" - } + transaction { + output { thisTest.getPaper().withMaturityDate(TEST_TX_TIME - 10.days) } + command(MEGA_CORP_PUBKEY) { thisTest.getIssueCommand() } + timestamp(TEST_TX_TIME) + this `fails with` "maturity date is not in the past" } } @Test fun `issue cannot replace an existing state`() { - ledger { - nonVerifiedTransaction { - output("paper") { thisTest.getPaper() } - } - transaction { - input("paper") - output { thisTest.getPaper() } - command(MEGA_CORP_PUBKEY) { thisTest.getIssueCommand() } - timestamp(TEST_TX_TIME) - this `fails with` "there is no input state" - } + transaction { + input(thisTest.getPaper()) + output { thisTest.getPaper() } + command(MEGA_CORP_PUBKEY) { thisTest.getIssueCommand() } + timestamp(TEST_TX_TIME) + this `fails with` "there is no input state" } } diff --git a/contracts/src/test/kotlin/com/r3corda/contracts/IRSTests.kt b/contracts/src/test/kotlin/com/r3corda/contracts/IRSTests.kt index 08b5f54411..6d10560a42 100644 --- a/contracts/src/test/kotlin/com/r3corda/contracts/IRSTests.kt +++ b/contracts/src/test/kotlin/com/r3corda/contracts/IRSTests.kt @@ -360,7 +360,7 @@ class IRSTests { /** * Generates a typical transactional history for an IRS. */ - fun trade(): LedgerDsl { + fun trade(): LedgerDSL { val ld = LocalDate.of(2016, 3, 8) val bd = BigDecimal("0.0063518") @@ -398,86 +398,76 @@ class IRSTests { @Test fun `ensure failure occurs when there are inbound states for an agreement command`() { - ledger { - transaction { - input() { singleIRS() } - output("irs post agreement") { singleIRS() } - command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) - this `fails with` "There are no in states for an agreement" - } + transaction { + input() { singleIRS() } + output("irs post agreement") { singleIRS() } + command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } + timestamp(TEST_TX_TIME) + this `fails with` "There are no in states for an agreement" } } @Test fun `ensure failure occurs when no events in fix schedule`() { - ledger { - val irs = singleIRS() - val emptySchedule = HashMap() - transaction { - output() { - irs.copy(calculation = irs.calculation.copy(fixedLegPaymentSchedule = emptySchedule)) - } - command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) - this `fails with` "There are events in the fix schedule" + val irs = singleIRS() + val emptySchedule = HashMap() + transaction { + output() { + irs.copy(calculation = irs.calculation.copy(fixedLegPaymentSchedule = emptySchedule)) } + command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } + timestamp(TEST_TX_TIME) + this `fails with` "There are events in the fix schedule" } } @Test fun `ensure failure occurs when no events in floating schedule`() { - ledger { - val irs = singleIRS() - val emptySchedule = HashMap() - transaction { - output() { - irs.copy(calculation = irs.calculation.copy(floatingLegPaymentSchedule = emptySchedule)) - } - command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) - this `fails with` "There are events in the float schedule" + val irs = singleIRS() + val emptySchedule = HashMap() + transaction { + output() { + irs.copy(calculation = irs.calculation.copy(floatingLegPaymentSchedule = emptySchedule)) } + command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } + timestamp(TEST_TX_TIME) + this `fails with` "There are events in the float schedule" } } @Test fun `ensure notionals are non zero`() { - ledger { - val irs = singleIRS() - transaction { - output() { - irs.copy(irs.fixedLeg.copy(notional = irs.fixedLeg.notional.copy(quantity = 0))) - } - command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) - this `fails with` "All notionals must be non zero" + val irs = singleIRS() + transaction { + output() { + irs.copy(irs.fixedLeg.copy(notional = irs.fixedLeg.notional.copy(quantity = 0))) } + command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } + timestamp(TEST_TX_TIME) + this `fails with` "All notionals must be non zero" + } - transaction { - output() { - irs.copy(irs.fixedLeg.copy(notional = irs.floatingLeg.notional.copy(quantity = 0))) - } - command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) - this `fails with` "All notionals must be non zero" + transaction { + output() { + irs.copy(irs.fixedLeg.copy(notional = irs.floatingLeg.notional.copy(quantity = 0))) } + command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } + timestamp(TEST_TX_TIME) + this `fails with` "All notionals must be non zero" } } @Test fun `ensure positive rate on fixed leg`() { - ledger { - val irs = singleIRS() - val modifiedIRS = irs.copy(fixedLeg = irs.fixedLeg.copy(fixedRate = FixedRate(PercentageRatioUnit("-0.1")))) - transaction { - output() { - modifiedIRS - } - command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) - this `fails with` "The fixed leg rate must be positive" + val irs = singleIRS() + val modifiedIRS = irs.copy(fixedLeg = irs.fixedLeg.copy(fixedRate = FixedRate(PercentageRatioUnit("-0.1")))) + transaction { + output() { + modifiedIRS } + command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } + timestamp(TEST_TX_TIME) + this `fails with` "The fixed leg rate must be positive" } } @@ -486,87 +476,79 @@ class IRSTests { */ @Test fun `ensure same currency notionals`() { - ledger { - val irs = singleIRS() - val modifiedIRS = irs.copy(fixedLeg = irs.fixedLeg.copy(notional = Amount(irs.fixedLeg.notional.quantity, Currency.getInstance("JPY")))) - transaction { - output() { - modifiedIRS - } - command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) - this `fails with` "The currency of the notionals must be the same" + val irs = singleIRS() + val modifiedIRS = irs.copy(fixedLeg = irs.fixedLeg.copy(notional = Amount(irs.fixedLeg.notional.quantity, Currency.getInstance("JPY")))) + transaction { + output() { + modifiedIRS } + command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } + timestamp(TEST_TX_TIME) + this `fails with` "The currency of the notionals must be the same" } } @Test fun `ensure notional amounts are equal`() { - ledger { - val irs = singleIRS() - val modifiedIRS = irs.copy(fixedLeg = irs.fixedLeg.copy(notional = Amount(irs.floatingLeg.notional.quantity + 1, irs.floatingLeg.notional.token))) - transaction { - output() { - modifiedIRS - } - command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) - this `fails with` "All leg notionals must be the same" + val irs = singleIRS() + val modifiedIRS = irs.copy(fixedLeg = irs.fixedLeg.copy(notional = Amount(irs.floatingLeg.notional.quantity + 1, irs.floatingLeg.notional.token))) + transaction { + output() { + modifiedIRS } + command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } + timestamp(TEST_TX_TIME) + this `fails with` "All leg notionals must be the same" } } @Test fun `ensure trade date and termination date checks are done pt1`() { - ledger { - val irs = singleIRS() - val modifiedIRS1 = irs.copy(fixedLeg = irs.fixedLeg.copy(terminationDate = irs.fixedLeg.effectiveDate.minusDays(1))) - transaction { - output() { - modifiedIRS1 - } - command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) - this `fails with` "The effective date is before the termination date for the fixed leg" + val irs = singleIRS() + val modifiedIRS1 = irs.copy(fixedLeg = irs.fixedLeg.copy(terminationDate = irs.fixedLeg.effectiveDate.minusDays(1))) + transaction { + output() { + modifiedIRS1 } + command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } + timestamp(TEST_TX_TIME) + this `fails with` "The effective date is before the termination date for the fixed leg" + } - val modifiedIRS2 = irs.copy(floatingLeg = irs.floatingLeg.copy(terminationDate = irs.floatingLeg.effectiveDate.minusDays(1))) - transaction { - output() { - modifiedIRS2 - } - command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) - this `fails with` "The effective date is before the termination date for the floating leg" + val modifiedIRS2 = irs.copy(floatingLeg = irs.floatingLeg.copy(terminationDate = irs.floatingLeg.effectiveDate.minusDays(1))) + transaction { + output() { + modifiedIRS2 } + command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } + timestamp(TEST_TX_TIME) + this `fails with` "The effective date is before the termination date for the floating leg" } } @Test fun `ensure trade date and termination date checks are done pt2`() { - ledger { - val irs = singleIRS() + val irs = singleIRS() - val modifiedIRS3 = irs.copy(floatingLeg = irs.floatingLeg.copy(terminationDate = irs.fixedLeg.terminationDate.minusDays(1))) - transaction { - output() { - modifiedIRS3 - } - command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) - this `fails with` "The termination dates are aligned" + val modifiedIRS3 = irs.copy(floatingLeg = irs.floatingLeg.copy(terminationDate = irs.fixedLeg.terminationDate.minusDays(1))) + transaction { + output() { + modifiedIRS3 } + command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } + timestamp(TEST_TX_TIME) + this `fails with` "The termination dates are aligned" + } - val modifiedIRS4 = irs.copy(floatingLeg = irs.floatingLeg.copy(effectiveDate = irs.fixedLeg.effectiveDate.minusDays(1))) - transaction { - output() { - modifiedIRS4 - } - command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } - timestamp(TEST_TX_TIME) - this `fails with` "The effective dates are aligned" + val modifiedIRS4 = irs.copy(floatingLeg = irs.floatingLeg.copy(effectiveDate = irs.fixedLeg.effectiveDate.minusDays(1))) + transaction { + output() { + modifiedIRS4 } + command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } + timestamp(TEST_TX_TIME) + this `fails with` "The effective dates are aligned" } } @@ -674,7 +656,7 @@ class IRSTests { * result and the grouping won't work either. * In reality, the only fields that should be in common will be the next fixing date and the reference rate. */ - fun tradegroups(): LedgerDsl { + fun tradegroups(): LedgerDSL { val ld1 = LocalDate.of(2016, 3, 8) val bd1 = BigDecimal("0.0063518") diff --git a/contracts/src/test/kotlin/com/r3corda/contracts/asset/ObligationTests.kt b/contracts/src/test/kotlin/com/r3corda/contracts/asset/ObligationTests.kt index 6cc13e440b..d6f8a6c1d6 100644 --- a/contracts/src/test/kotlin/com/r3corda/contracts/asset/ObligationTests.kt +++ b/contracts/src/test/kotlin/com/r3corda/contracts/asset/ObligationTests.kt @@ -5,6 +5,7 @@ import com.r3corda.contracts.testing.* import com.r3corda.core.contracts.* import com.r3corda.core.crypto.SecureHash import com.r3corda.core.testing.* +import com.r3corda.core.testing.JavaTestHelpers import com.r3corda.core.utilities.nonEmptySetOf import org.junit.Test import java.security.PublicKey @@ -34,9 +35,9 @@ class ObligationTests { val outState = inState.copy(beneficiary = DUMMY_PUBKEY_2) private fun obligationTestRoots( - group: LedgerDsl + group: LedgerDSL ) = group.apply { - nonVerifiedTransaction { + unverifiedTransaction { output("Alice's $1,000,000 obligation to Bob", oneMillionDollars.OBLIGATION `between` Pair(ALICE, BOB_PUBKEY)) output("Bob's $1,000,000 obligation to Alice", oneMillionDollars.OBLIGATION `between` Pair(BOB, ALICE_PUBKEY)) output("MegaCorp's $1,000,000 obligation to Bob", oneMillionDollars.OBLIGATION `between` Pair(MEGA_CORP, BOB_PUBKEY)) @@ -46,37 +47,35 @@ class ObligationTests { @Test fun trivial() { - ledger { - transaction { - input { inState } - this `fails with` "the amounts balance" + transaction { + input { inState } + this `fails with` "the amounts balance" - tweak { - output { outState.copy(quantity = 2000.DOLLARS.quantity) } - this `fails with` "the amounts balance" - } - tweak { - output { outState } - // No command commanduments - this `fails with` "required com.r3corda.contracts.asset.Obligation.Commands.Move command" - } - tweak { - output { outState } - command(DUMMY_PUBKEY_2) { Obligation.Commands.Move(inState.issuanceDef) } - this `fails with` "the owning keys are the same as the signing keys" - } - tweak { - output { outState } - output { outState `issued by` MINI_CORP } - command(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } - this `fails with` "at least one obligation input" - } - // Simple reallocation works. - tweak { - output { outState } - command(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } - this.verifies() - } + tweak { + output { outState.copy(quantity = 2000.DOLLARS.quantity) } + this `fails with` "the amounts balance" + } + tweak { + output { outState } + // No command commanduments + this `fails with` "required com.r3corda.contracts.asset.Obligation.Commands.Move command" + } + tweak { + output { outState } + command(DUMMY_PUBKEY_2) { Obligation.Commands.Move(inState.issuanceDef) } + this `fails with` "the owning keys are the same as the signing keys" + } + tweak { + output { outState } + output { outState `issued by` MINI_CORP } + command(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } + this `fails with` "at least one obligation input" + } + // Simple reallocation works. + tweak { + output { outState } + command(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } + this.verifies() } } } @@ -84,111 +83,109 @@ class ObligationTests { @Test fun `issue debt`() { // Check we can't "move" debt into existence. - ledger { - transaction { - input { DummyState() } - output { outState } - command(MINI_CORP_PUBKEY) { Obligation.Commands.Move(outState.issuanceDef) } + transaction { + input { DummyState() } + output { outState } + command(MINI_CORP_PUBKEY) { Obligation.Commands.Move(outState.issuanceDef) } - this `fails with` "there is at least one obligation input" + this `fails with` "there is at least one obligation input" + } + + // Check we can issue money only as long as the issuer institution is a command signer, i.e. any recognised + // institution is allowed to issue as much cash as they want. + transaction { + output { outState } + command(DUMMY_PUBKEY_1) { Obligation.Commands.Issue(outState.issuanceDef) } + this `fails with` "output deposits are owned by a command signer" + } + transaction { + output { + Obligation.State( + obligor = MINI_CORP, + quantity = 1000.DOLLARS.quantity, + beneficiary = DUMMY_PUBKEY_1, + template = megaCorpDollarSettlement + ) + } + tweak { + command(MINI_CORP_PUBKEY) { Obligation.Commands.Issue(Obligation.IssuanceDefinition(MINI_CORP, megaCorpDollarSettlement), 0) } + this `fails with` "has a nonce" + } + command(MINI_CORP_PUBKEY) { Obligation.Commands.Issue(Obligation.IssuanceDefinition(MINI_CORP, megaCorpDollarSettlement)) } + this.verifies() + } + + // Test generation works. + val ptx = TransactionType.General.Builder(DUMMY_NOTARY) + Obligation().generateIssue(ptx, MINI_CORP, megaCorpDollarSettlement, 100.DOLLARS.quantity, + beneficiary = DUMMY_PUBKEY_1, notary = DUMMY_NOTARY) + assertTrue(ptx.inputStates().isEmpty()) + val expected = Obligation.State( + obligor = MINI_CORP, + quantity = 100.DOLLARS.quantity, + beneficiary = DUMMY_PUBKEY_1, + template = megaCorpDollarSettlement + ) + assertEquals(ptx.outputStates()[0].data, expected) + assertTrue(ptx.commands()[0].value is Obligation.Commands.Issue<*>) + assertEquals(MINI_CORP_PUBKEY, ptx.commands()[0].signers[0]) + + // We can consume $1000 in a transaction and output $2000 as long as it's signed by an issuer. + transaction { + input { inState } + output { inState.copy(quantity = inState.amount.quantity * 2) } + + // Move fails: not allowed to summon money. + tweak { + command(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } + this `fails with` "at obligor MegaCorp the amounts balance" } - // Check we can issue money only as long as the issuer institution is a command signer, i.e. any recognised - // institution is allowed to issue as much cash as they want. - transaction { - output { outState } - command(DUMMY_PUBKEY_1) { Obligation.Commands.Issue(outState.issuanceDef) } - this `fails with` "output deposits are owned by a command signer" - } - transaction { - output { - Obligation.State( - obligor = MINI_CORP, - quantity = 1000.DOLLARS.quantity, - beneficiary = DUMMY_PUBKEY_1, - template = megaCorpDollarSettlement - ) - } - tweak { - command(MINI_CORP_PUBKEY) { Obligation.Commands.Issue(Obligation.IssuanceDefinition(MINI_CORP, megaCorpDollarSettlement), 0) } - this `fails with` "has a nonce" - } - command(MINI_CORP_PUBKEY) { Obligation.Commands.Issue(Obligation.IssuanceDefinition(MINI_CORP, megaCorpDollarSettlement)) } + // Issue works. + tweak { + command(MEGA_CORP_PUBKEY) { Obligation.Commands.Issue(inState.issuanceDef) } this.verifies() } + } - // Test generation works. - val ptx = TransactionType.General.Builder(DUMMY_NOTARY) - Obligation().generateIssue(ptx, MINI_CORP, megaCorpDollarSettlement, 100.DOLLARS.quantity, - beneficiary = DUMMY_PUBKEY_1, notary = DUMMY_NOTARY) - assertTrue(ptx.inputStates().isEmpty()) - val expected = Obligation.State( - obligor = MINI_CORP, - quantity = 100.DOLLARS.quantity, - beneficiary = DUMMY_PUBKEY_1, - template = megaCorpDollarSettlement - ) - assertEquals(ptx.outputStates()[0].data, expected) - assertTrue(ptx.commands()[0].value is Obligation.Commands.Issue<*>) - assertEquals(MINI_CORP_PUBKEY, ptx.commands()[0].signers[0]) + // Can't use an issue command to lower the amount. + transaction { + input { inState } + output { inState.copy(quantity = inState.amount.quantity / 2) } + command(MEGA_CORP_PUBKEY) { Obligation.Commands.Issue(inState.issuanceDef) } + this `fails with` "output values sum to more than the inputs" + } - // We can consume $1000 in a transaction and output $2000 as long as it's signed by an issuer. - transaction { - input { inState } - output { inState.copy(quantity = inState.amount.quantity * 2) } + // Can't have an issue command that doesn't actually issue money. + transaction { + input { inState } + output { inState } + command(MEGA_CORP_PUBKEY) { Obligation.Commands.Issue(inState.issuanceDef) } + this `fails with` "output values sum to more than the inputs" + } - // Move fails: not allowed to summon money. - tweak { - command(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } - this `fails with` "at obligor MegaCorp the amounts balance" - } - - // Issue works. - tweak { - command(MEGA_CORP_PUBKEY) { Obligation.Commands.Issue(inState.issuanceDef) } - this.verifies() - } - } - - // Can't use an issue command to lower the amount. - transaction { - input { inState } - output { inState.copy(quantity = inState.amount.quantity / 2) } + // Can't have any other commands if we have an issue command (because the issue command overrules them) + transaction { + input { inState } + output { inState.copy(quantity = inState.amount.quantity * 2) } + command(MEGA_CORP_PUBKEY) { Obligation.Commands.Issue(inState.issuanceDef) } + tweak { command(MEGA_CORP_PUBKEY) { Obligation.Commands.Issue(inState.issuanceDef) } - this `fails with` "output values sum to more than the inputs" + this `fails with` "only move/exit commands can be present along with other obligation commands" } - - // Can't have an issue command that doesn't actually issue money. - transaction { - input { inState } - output { inState } - command(MEGA_CORP_PUBKEY) { Obligation.Commands.Issue(inState.issuanceDef) } - this `fails with` "output values sum to more than the inputs" + tweak { + command(MEGA_CORP_PUBKEY) { Obligation.Commands.Move(inState.issuanceDef) } + this `fails with` "only move/exit commands can be present along with other obligation commands" } - - // Can't have any other commands if we have an issue command (because the issue command overrules them) - transaction { - input { inState } - output { inState.copy(quantity = inState.amount.quantity * 2) } - command(MEGA_CORP_PUBKEY) { Obligation.Commands.Issue(inState.issuanceDef) } - tweak { - command(MEGA_CORP_PUBKEY) { Obligation.Commands.Issue(inState.issuanceDef) } - this `fails with` "only move/exit commands can be present along with other obligation commands" - } - tweak { - command(MEGA_CORP_PUBKEY) { Obligation.Commands.Move(inState.issuanceDef) } - this `fails with` "only move/exit commands can be present along with other obligation commands" - } - tweak { - command(MEGA_CORP_PUBKEY) { Obligation.Commands.SetLifecycle(inState.issuanceDef, Lifecycle.DEFAULTED) } - this `fails with` "only move/exit commands can be present along with other obligation commands" - } - tweak { - command(MEGA_CORP_PUBKEY) { Obligation.Commands.Exit(inState.issuanceDef, inState.amount / 2) } - this `fails with` "only move/exit commands can be present along with other obligation commands" - } - this.verifies() + tweak { + command(MEGA_CORP_PUBKEY) { Obligation.Commands.SetLifecycle(inState.issuanceDef, Lifecycle.DEFAULTED) } + this `fails with` "only move/exit commands can be present along with other obligation commands" } + tweak { + command(MEGA_CORP_PUBKEY) { Obligation.Commands.Exit(inState.issuanceDef, inState.amount / 2) } + this `fails with` "only move/exit commands can be present along with other obligation commands" + } + this.verifies() } } @@ -388,7 +385,6 @@ class ObligationTests { this `fails with` "any involved party has signed" } } - } @Test @@ -480,26 +476,18 @@ class ObligationTests { // Try defaulting an obligation due in the future val pastTestTime = TEST_TX_TIME - Duration.ofDays(7) val futureTestTime = TEST_TX_TIME + Duration.ofDays(7) - ledger { - nonVerifiedTransaction { - output("Alice's $1,000,000 obligation to Bob", oneMillionDollars.OBLIGATION `between` Pair(ALICE, BOB_PUBKEY) `at` futureTestTime) - } - transaction("Settlement") { - input("Alice's $1,000,000 obligation to Bob") - output("Alice's defaulted $1,000,000 obligation to Bob") { (oneMillionDollars.OBLIGATION `between` Pair(ALICE, BOB_PUBKEY) `at` futureTestTime).copy(lifecycle = Lifecycle.DEFAULTED) } - command(BOB_PUBKEY) { Obligation.Commands.SetLifecycle(Obligation.IssuanceDefinition(ALICE, defaultUsd.OBLIGATION_DEF) `at` futureTestTime, Lifecycle.DEFAULTED) } - timestamp(TEST_TX_TIME) - this `fails with` "the due date has passed" - } + transaction("Settlement") { + input(oneMillionDollars.OBLIGATION `between` Pair(ALICE, BOB_PUBKEY) `at` futureTestTime) + output("Alice's defaulted $1,000,000 obligation to Bob") { (oneMillionDollars.OBLIGATION `between` Pair(ALICE, BOB_PUBKEY) `at` futureTestTime).copy(lifecycle = Lifecycle.DEFAULTED) } + command(BOB_PUBKEY) { Obligation.Commands.SetLifecycle(Obligation.IssuanceDefinition(ALICE, defaultUsd.OBLIGATION_DEF) `at` futureTestTime, Lifecycle.DEFAULTED) } + timestamp(TEST_TX_TIME) + this `fails with` "the due date has passed" } // Try defaulting an obligation that is now in the past ledger { - nonVerifiedTransaction { - output("Alice's $1,000,000 obligation to Bob", oneMillionDollars.OBLIGATION `between` Pair(ALICE, BOB_PUBKEY) `at` pastTestTime) - } transaction("Settlement") { - input("Alice's $1,000,000 obligation to Bob") + input(oneMillionDollars.OBLIGATION `between` Pair(ALICE, BOB_PUBKEY) `at` pastTestTime) output("Alice's defaulted $1,000,000 obligation to Bob") { (oneMillionDollars.OBLIGATION `between` Pair(ALICE, BOB_PUBKEY) `at` pastTestTime).copy(lifecycle = Lifecycle.DEFAULTED) } command(BOB_PUBKEY) { Obligation.Commands.SetLifecycle(Obligation.IssuanceDefinition(ALICE, defaultUsd.OBLIGATION_DEF) `at` pastTestTime, Lifecycle.DEFAULTED) } timestamp(TEST_TX_TIME) @@ -512,182 +500,171 @@ class ObligationTests { @Test fun testMergeSplit() { // Splitting value works. - ledger { - transaction { - command(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } - tweak { - input { inState } - repeat(4) { output { inState.copy(quantity = inState.quantity / 4) } } - this.verifies() - } - // Merging 4 inputs into 2 outputs works. - tweak { - repeat(4) { input { inState.copy(quantity = inState.quantity / 4) } } - output { inState.copy(quantity = inState.quantity / 2) } - output { inState.copy(quantity = inState.quantity / 2) } - this.verifies() - } - // Merging 2 inputs into 1 works. - tweak { - input { inState.copy(quantity = inState.quantity / 2) } - input { inState.copy(quantity = inState.quantity / 2) } - output { inState } - this.verifies() - } + transaction { + command(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } + tweak { + input { inState } + repeat(4) { output { inState.copy(quantity = inState.quantity / 4) } } + this.verifies() + } + // Merging 4 inputs into 2 outputs works. + tweak { + repeat(4) { input { inState.copy(quantity = inState.quantity / 4) } } + output { inState.copy(quantity = inState.quantity / 2) } + output { inState.copy(quantity = inState.quantity / 2) } + this.verifies() + } + // Merging 2 inputs into 1 works. + tweak { + input { inState.copy(quantity = inState.quantity / 2) } + input { inState.copy(quantity = inState.quantity / 2) } + output { inState } + this.verifies() } } } @Test fun zeroSizedValues() { - ledger { - transaction { - input { inState } - input { inState.copy(quantity = 0L) } - this `fails with` "zero sized inputs" - } - transaction { - input { inState } - output { inState } - output { inState.copy(quantity = 0L) } - this `fails with` "zero sized outputs" - } + transaction { + input { inState } + input { inState.copy(quantity = 0L) } + this `fails with` "zero sized inputs" + } + transaction { + input { inState } + output { inState } + output { inState.copy(quantity = 0L) } + this `fails with` "zero sized outputs" } } + @Test fun trivialMismatches() { - ledger { - // Can't change issuer. - transaction { - input { inState } - output { outState `issued by` MINI_CORP } - this `fails with` "at obligor MegaCorp the amounts balance" - } - // Can't mix currencies. - transaction { - input { inState } - output { outState.copy(quantity = 80000, template = megaCorpDollarSettlement) } - output { outState.copy(quantity = 20000, template = megaCorpPoundSettlement) } - this `fails with` "the amounts balance" - } - transaction { - input { inState } - input { - inState.copy( - quantity = 15000, - template = megaCorpPoundSettlement, - beneficiary = DUMMY_PUBKEY_2 - ) - } - output { outState.copy(quantity = 115000) } - this `fails with` "the amounts balance" - } - // Can't have superfluous input states from different issuers. - transaction { - input { inState } - input { inState `issued by` MINI_CORP } - output { outState } - command(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } - command(DUMMY_PUBKEY_1) { Obligation.Commands.Move((inState `issued by` MINI_CORP).issuanceDef) } - this `fails with` "at obligor MiniCorp the amounts balance" + // Can't change issuer. + transaction { + input { inState } + output { outState `issued by` MINI_CORP } + this `fails with` "at obligor MegaCorp the amounts balance" + } + // Can't mix currencies. + transaction { + input { inState } + output { outState.copy(quantity = 80000, template = megaCorpDollarSettlement) } + output { outState.copy(quantity = 20000, template = megaCorpPoundSettlement) } + this `fails with` "the amounts balance" + } + transaction { + input { inState } + input { + inState.copy( + quantity = 15000, + template = megaCorpPoundSettlement, + beneficiary = DUMMY_PUBKEY_2 + ) } + output { outState.copy(quantity = 115000) } + this `fails with` "the amounts balance" + } + // Can't have superfluous input states from different issuers. + transaction { + input { inState } + input { inState `issued by` MINI_CORP } + output { outState } + command(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } + command(DUMMY_PUBKEY_1) { Obligation.Commands.Move((inState `issued by` MINI_CORP).issuanceDef) } + this `fails with` "at obligor MiniCorp the amounts balance" } } @Test fun exitLedger() { - ledger { - // Single input/output straightforward case. - transaction { - input { inState } - output { outState.copy(quantity = inState.quantity - 200.DOLLARS.quantity) } - - tweak { - command(MEGA_CORP_PUBKEY) { Obligation.Commands.Exit(inState.issuanceDef, 100.DOLLARS) } - command(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } - this `fails with` "the amounts balance" - } - - tweak { - command(MEGA_CORP_PUBKEY) { Obligation.Commands.Exit(inState.issuanceDef, 200.DOLLARS) } - this `fails with` "required com.r3corda.contracts.asset.Obligation.Commands.Move command" - - tweak { - command(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } - this.verifies() - } - } - } - // Multi-issuer case. - transaction { - input { inState } - input { inState `issued by` MINI_CORP } - - output { inState.copy(quantity = inState.quantity - 200.DOLLARS.quantity) `issued by` MINI_CORP } - output { inState.copy(quantity = inState.quantity - 200.DOLLARS.quantity) } + // Single input/output straightforward case. + transaction { + input { inState } + output { outState.copy(quantity = inState.quantity - 200.DOLLARS.quantity) } + tweak { + command(MEGA_CORP_PUBKEY) { Obligation.Commands.Exit(inState.issuanceDef, 100.DOLLARS) } command(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } - - this `fails with` "at obligor MegaCorp the amounts balance" - - command(MEGA_CORP_PUBKEY) { Obligation.Commands.Exit(inState.issuanceDef, 200.DOLLARS) } - tweak { - command(MINI_CORP_PUBKEY) { Obligation.Commands.Exit((inState `issued by` MINI_CORP).issuanceDef, 0.DOLLARS) } - command(DUMMY_PUBKEY_1) { Obligation.Commands.Move((inState `issued by` MINI_CORP).issuanceDef) } - this `fails with` "at obligor MiniCorp the amounts balance" - } - command(MINI_CORP_PUBKEY) { Obligation.Commands.Exit((inState `issued by` MINI_CORP).issuanceDef, 200.DOLLARS) } - command(DUMMY_PUBKEY_1) { Obligation.Commands.Move((inState `issued by` MINI_CORP).issuanceDef) } - this.verifies() + this `fails with` "the amounts balance" } + + tweak { + command(MEGA_CORP_PUBKEY) { Obligation.Commands.Exit(inState.issuanceDef, 200.DOLLARS) } + this `fails with` "required com.r3corda.contracts.asset.Obligation.Commands.Move command" + + tweak { + command(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } + this.verifies() + } + } + } + // Multi-issuer case. + transaction { + input { inState } + input { inState `issued by` MINI_CORP } + + output { inState.copy(quantity = inState.quantity - 200.DOLLARS.quantity) `issued by` MINI_CORP } + output { inState.copy(quantity = inState.quantity - 200.DOLLARS.quantity) } + + command(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } + + this `fails with` "at obligor MegaCorp the amounts balance" + + command(MEGA_CORP_PUBKEY) { Obligation.Commands.Exit(inState.issuanceDef, 200.DOLLARS) } + tweak { + command(MINI_CORP_PUBKEY) { Obligation.Commands.Exit((inState `issued by` MINI_CORP).issuanceDef, 0.DOLLARS) } + command(DUMMY_PUBKEY_1) { Obligation.Commands.Move((inState `issued by` MINI_CORP).issuanceDef) } + this `fails with` "at obligor MiniCorp the amounts balance" + } + command(MINI_CORP_PUBKEY) { Obligation.Commands.Exit((inState `issued by` MINI_CORP).issuanceDef, 200.DOLLARS) } + command(DUMMY_PUBKEY_1) { Obligation.Commands.Move((inState `issued by` MINI_CORP).issuanceDef) } + this.verifies() } } @Test fun multiIssuer() { - ledger { - transaction { - // Gather 2000 dollars from two different issuers. - input { inState } - input { inState `issued by` MINI_CORP } + transaction { + // Gather 2000 dollars from two different issuers. + input { inState } + input { inState `issued by` MINI_CORP } - // Can't merge them together. - tweak { - output { inState.copy(beneficiary = DUMMY_PUBKEY_2, quantity = 200000L) } - this `fails with` "at obligor MegaCorp the amounts balance" - } - // Missing MiniCorp deposit - tweak { - output { inState.copy(beneficiary = DUMMY_PUBKEY_2) } - output { inState.copy(beneficiary = DUMMY_PUBKEY_2) } - this `fails with` "at obligor MegaCorp the amounts balance" - } - - // This works. - output { inState.copy(beneficiary = DUMMY_PUBKEY_2) } - output { inState.copy(beneficiary = DUMMY_PUBKEY_2) `issued by` MINI_CORP } - command(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } - command(DUMMY_PUBKEY_1) { Obligation.Commands.Move((inState `issued by` MINI_CORP).issuanceDef) } - this.verifies() + // Can't merge them together. + tweak { + output { inState.copy(beneficiary = DUMMY_PUBKEY_2, quantity = 200000L) } + this `fails with` "at obligor MegaCorp the amounts balance" } + // Missing MiniCorp deposit + tweak { + output { inState.copy(beneficiary = DUMMY_PUBKEY_2) } + output { inState.copy(beneficiary = DUMMY_PUBKEY_2) } + this `fails with` "at obligor MegaCorp the amounts balance" + } + + // This works. + output { inState.copy(beneficiary = DUMMY_PUBKEY_2) } + output { inState.copy(beneficiary = DUMMY_PUBKEY_2) `issued by` MINI_CORP } + command(DUMMY_PUBKEY_1) { Obligation.Commands.Move(inState.issuanceDef) } + command(DUMMY_PUBKEY_1) { Obligation.Commands.Move((inState `issued by` MINI_CORP).issuanceDef) } + this.verifies() } } @Test fun multiCurrency() { - ledger { - // Check we can do an atomic currency trade tx. - transaction { - val pounds = Obligation.State(Lifecycle.NORMAL, MINI_CORP, megaCorpPoundSettlement, 658.POUNDS.quantity, DUMMY_PUBKEY_2) - input { inState `owned by` DUMMY_PUBKEY_1 } - input { pounds } - output { inState `owned by` DUMMY_PUBKEY_2 } - output { pounds `owned by` DUMMY_PUBKEY_1 } - command(DUMMY_PUBKEY_1, DUMMY_PUBKEY_2) { Obligation.Commands.Move(inState.issuanceDef) } - command(DUMMY_PUBKEY_1, DUMMY_PUBKEY_2) { Obligation.Commands.Move(pounds.issuanceDef) } + // Check we can do an atomic currency trade tx. + transaction { + val pounds = Obligation.State(Lifecycle.NORMAL, MINI_CORP, megaCorpPoundSettlement, 658.POUNDS.quantity, DUMMY_PUBKEY_2) + input { inState `owned by` DUMMY_PUBKEY_1 } + input { pounds } + output { inState `owned by` DUMMY_PUBKEY_2 } + output { pounds `owned by` DUMMY_PUBKEY_1 } + command(DUMMY_PUBKEY_1, DUMMY_PUBKEY_2) { Obligation.Commands.Move(inState.issuanceDef) } + command(DUMMY_PUBKEY_1, DUMMY_PUBKEY_2) { Obligation.Commands.Move(pounds.issuanceDef) } - this.verifies() - } + this.verifies() } } diff --git a/core/src/main/kotlin/com/r3corda/core/testing/LedgerDSLInterpreter.kt b/core/src/main/kotlin/com/r3corda/core/testing/LedgerDSLInterpreter.kt new file mode 100644 index 0000000000..eb1aea76e1 --- /dev/null +++ b/core/src/main/kotlin/com/r3corda/core/testing/LedgerDSLInterpreter.kt @@ -0,0 +1,37 @@ +package com.r3corda.core.testing + +import com.r3corda.core.contracts.* +import com.r3corda.core.crypto.SecureHash +import java.io.InputStream + +interface OutputStateLookup { + fun retrieveOutputStateAndRef(clazz: Class, label: String): StateAndRef +} + +interface LedgerDSLInterpreter> : OutputStateLookup { + fun transaction(transactionLabel: String?, dsl: TransactionDSL.() -> R): WireTransaction + fun unverifiedTransaction(transactionLabel: String?, dsl: TransactionDSL.() -> Unit): WireTransaction + fun tweak(dsl: LedgerDSL>.() -> Unit) + fun attachment(attachment: InputStream): SecureHash + fun verifies() +} + +/** + * This is the class the top-level primitives deal with. It delegates all other primitives to the contained interpreter. + * This way we have a decoupling of the DSL "AST" and the interpretation(s) of it. Note how the delegation forces + * covariance of the TransactionInterpreter parameter + */ +class LedgerDSL, out L : LedgerDSLInterpreter> (val interpreter: L) : + LedgerDSLInterpreter> by interpreter { + + fun transaction(dsl: TransactionDSL>.() -> R) = + transaction(null, dsl) + fun unverifiedTransaction(dsl: TransactionDSL>.() -> Unit) = + unverifiedTransaction(null, dsl) + + inline fun String.outputStateAndRef(): StateAndRef = + retrieveOutputStateAndRef(S::class.java, this) + inline fun String.output(): TransactionState = + outputStateAndRef().state + fun String.outputRef(): StateRef = outputStateAndRef().ref +} diff --git a/core/src/main/kotlin/com/r3corda/core/testing/LedgerDslInterpreter.kt b/core/src/main/kotlin/com/r3corda/core/testing/LedgerDslInterpreter.kt deleted file mode 100644 index df999f6e5e..0000000000 --- a/core/src/main/kotlin/com/r3corda/core/testing/LedgerDslInterpreter.kt +++ /dev/null @@ -1,48 +0,0 @@ -package com.r3corda.core.testing - -import com.r3corda.core.contracts.* -import com.r3corda.core.crypto.SecureHash -import java.io.InputStream - -interface OutputStateLookup { - fun retrieveOutputStateAndRef(clazz: Class, label: String): StateAndRef -} - -interface LedgerDslInterpreter> : - OutputStateLookup { - fun transaction( - transactionLabel: String?, - dsl: TransactionDsl.() -> Return - ): WireTransaction - fun nonVerifiedTransaction( - transactionLabel: String?, - dsl: TransactionDsl.() -> Unit - ): WireTransaction - fun tweak(dsl: LedgerDsl>.() -> Unit) - fun attachment(attachment: InputStream): SecureHash - fun verifies() -} - -/** - * This is the class the top-level primitives deal with. It delegates all other primitives to the contained interpreter. - * This way we have a decoupling of the DSL "AST" and the interpretation(s) of it. Note how the delegation forces - * covariance of the TransactionInterpreter parameter - */ -class LedgerDsl< - Return, - out TransactionInterpreter: TransactionDslInterpreter, - out LedgerInterpreter: LedgerDslInterpreter - > (val interpreter: LedgerInterpreter -) : LedgerDslInterpreter> by interpreter { - - fun transaction(dsl: TransactionDsl>.() -> Return) = - transaction(null, dsl) - fun nonVerifiedTransaction(dsl: TransactionDsl>.() -> Unit) = - nonVerifiedTransaction(null, dsl) - - inline fun String.outputStateAndRef(): StateAndRef = - retrieveOutputStateAndRef(State::class.java, this) - inline fun String.output(): TransactionState = - outputStateAndRef().state - fun String.outputRef(): StateRef = outputStateAndRef().ref -} diff --git a/core/src/main/kotlin/com/r3corda/core/testing/TestDsl.kt b/core/src/main/kotlin/com/r3corda/core/testing/TestDSL.kt similarity index 70% rename from core/src/main/kotlin/com/r3corda/core/testing/TestDsl.kt rename to core/src/main/kotlin/com/r3corda/core/testing/TestDSL.kt index 7c205b76ee..9415e30811 100644 --- a/core/src/main/kotlin/com/r3corda/core/testing/TestDsl.kt +++ b/core/src/main/kotlin/com/r3corda/core/testing/TestDSL.kt @@ -14,56 +14,75 @@ import java.security.KeyPair import java.security.PublicKey import java.util.* +fun transaction( + transactionLabel: String? = null, + dsl: TransactionDSL< + LastLineShouldTestForVerifiesOrFails, + TransactionDSLInterpreter + >.() -> LastLineShouldTestForVerifiesOrFails +) = JavaTestHelpers.transaction(transactionLabel, dsl) + fun ledger( identityService: IdentityService = MOCK_IDENTITY_SERVICE, storageService: StorageService = MockStorageService(), - dsl: LedgerDsl.() -> Unit + dsl: LedgerDSL.() -> Unit ) = JavaTestHelpers.ledger(identityService, storageService, dsl) @Deprecated( message = "ledger doesn't nest, use tweak", replaceWith = ReplaceWith("tweak"), level = DeprecationLevel.ERROR) -fun TransactionDslInterpreter.ledger( - dsl: LedgerDsl.() -> Unit) { - this.toString() - dsl.toString() +@Suppress("UNUSED_PARAMETER") +fun TransactionDSLInterpreter.ledger( + dsl: LedgerDSL.() -> Unit) { +} + +@Deprecated( + message = "transaction doesn't nest, use tweak", + replaceWith = ReplaceWith("tweak"), + level = DeprecationLevel.ERROR) +@Suppress("UNUSED_PARAMETER") +fun TransactionDSLInterpreter.transaction( + dsl: TransactionDSL< + LastLineShouldTestForVerifiesOrFails, + TransactionDSLInterpreter + >.() -> LastLineShouldTestForVerifiesOrFails) { } @Deprecated( message = "ledger doesn't nest, use tweak", replaceWith = ReplaceWith("tweak"), level = DeprecationLevel.ERROR) -fun LedgerDslInterpreter>.ledger( - dsl: LedgerDsl.() -> Unit) { - this.toString() - dsl.toString() +@Suppress("UNUSED_PARAMETER") +fun LedgerDSLInterpreter>.ledger( + dsl: LedgerDSL.() -> Unit) { } -/** If you jumped here from a compiler error make sure the last line of your test tests for a transaction verify or fail - * This is a dummy type that can only be instantiated by functions in this module. This way we can ensure that all tests - * will have as the last line either an accept or a failure test. The name is deliberately long to help make sense of - * the triggered diagnostic +/** + * If you jumped here from a compiler error make sure the last line of your test tests for a transaction verify or fail + * This is a dummy type that can only be instantiated by functions in this module. This way we can ensure that all tests + * will have as the last line either an accept or a failure test. The name is deliberately long to help make sense of + * the triggered diagnostic. */ sealed class LastLineShouldTestForVerifiesOrFails { internal object Token: LastLineShouldTestForVerifiesOrFails() } /** - * This interpreter builds a transaction, and [TransactionDsl.verifies] that the resolved transaction is correct. Note - * that transactions corresponding to input states are not verified. Use [LedgerDsl.verifies] for that. + * This interpreter builds a transaction, and [TransactionDSL.verifies] that the resolved transaction is correct. Note + * that transactions corresponding to input states are not verified. Use [LedgerDSL.verifies] for that. */ -data class TestTransactionDslInterpreter( - override val ledgerInterpreter: TestLedgerDslInterpreter, +data class TestTransactionDSLInterpreter( + override val ledgerInterpreter: TestLedgerDSLInterpreter, private val inputStateRefs: ArrayList = arrayListOf(), internal val outputStates: ArrayList = arrayListOf(), private val attachments: ArrayList = arrayListOf(), private val commands: ArrayList = arrayListOf(), private val signers: LinkedHashSet = LinkedHashSet(), private val transactionType: TransactionType = TransactionType.General() -) : TransactionDslInterpreter, OutputStateLookup by ledgerInterpreter { - private fun copy(): TestTransactionDslInterpreter = - TestTransactionDslInterpreter( +) : TransactionDSLInterpreter, OutputStateLookup by ledgerInterpreter { + private fun copy(): TestTransactionDSLInterpreter = + TestTransactionDSLInterpreter( ledgerInterpreter = ledgerInterpreter, inputStateRefs = ArrayList(inputStateRefs), outputStates = ArrayList(outputStates), @@ -136,23 +155,23 @@ data class TestTransactionDslInterpreter( } override fun tweak( - dsl: TransactionDsl< + dsl: TransactionDSL< LastLineShouldTestForVerifiesOrFails, - TransactionDslInterpreter + TransactionDSLInterpreter >.() -> LastLineShouldTestForVerifiesOrFails - ) = dsl(TransactionDsl(copy())) + ) = dsl(TransactionDSL(copy())) } class AttachmentResolutionException(attachmentId: SecureHash) : Exception("Attachment with id $attachmentId not found") -data class TestLedgerDslInterpreter private constructor ( +data class TestLedgerDSLInterpreter private constructor ( private val identityService: IdentityService, private val storageService: StorageService, internal val labelToOutputStateAndRefs: HashMap> = HashMap(), private val transactionWithLocations: HashMap = HashMap(), private val nonVerifiedTransactionWithLocations: HashMap = HashMap() -) : LedgerDslInterpreter { +) : LedgerDSLInterpreter { val wireTransactions: List get() = transactionWithLocations.values.map { it.transaction } @@ -178,8 +197,8 @@ data class TestLedgerDslInterpreter private constructor ( class TypeMismatch(requested: Class<*>, actual: Class<*>) : Exception("Actual type $actual is not a subtype of requested type $requested") - internal fun copy(): TestLedgerDslInterpreter = - TestLedgerDslInterpreter( + internal fun copy(): TestLedgerDSLInterpreter = + TestLedgerDSLInterpreter( identityService, storageService, labelToOutputStateAndRefs = HashMap(labelToOutputStateAndRefs), @@ -207,16 +226,16 @@ data class TestLedgerDslInterpreter private constructor ( } } - internal inline fun resolveStateRef(stateRef: StateRef): TransactionState { + internal inline fun resolveStateRef(stateRef: StateRef): TransactionState { val transactionWithLocation = transactionWithLocations[stateRef.txhash] ?: nonVerifiedTransactionWithLocations[stateRef.txhash] ?: throw TransactionResolutionException(stateRef.txhash) val output = transactionWithLocation.transaction.outputs[stateRef.index] - return if (State::class.java.isAssignableFrom(output.data.javaClass)) @Suppress("UNCHECKED_CAST") { - output as TransactionState + return if (S::class.java.isAssignableFrom(output.data.javaClass)) @Suppress("UNCHECKED_CAST") { + output as TransactionState } else { - throw TypeMismatch(requested = State::class.java, actual = output.data.javaClass) + throw TypeMismatch(requested = S::class.java, actual = output.data.javaClass) } } @@ -224,10 +243,10 @@ data class TestLedgerDslInterpreter private constructor ( storageService.attachments.openAttachment(attachmentId) ?: throw AttachmentResolutionException(attachmentId) private fun interpretTransactionDsl( - dsl: TransactionDsl.() -> Return - ): TestTransactionDslInterpreter { - val transactionInterpreter = TestTransactionDslInterpreter(this) - dsl(TransactionDsl(transactionInterpreter)) + dsl: TransactionDSL.() -> Return + ): TestTransactionDSLInterpreter { + val transactionInterpreter = TestTransactionDSLInterpreter(this) + dsl(TransactionDSL(transactionInterpreter)) return transactionInterpreter } @@ -253,9 +272,9 @@ data class TestLedgerDslInterpreter private constructor ( fun outputToLabel(state: ContractState): String? = labelToOutputStateAndRefs.filter { it.value.state.data == state }.keys.firstOrNull() - private fun recordTransactionWithTransactionMap( + private fun recordTransactionWithTransactionMap( transactionLabel: String?, - dsl: TransactionDsl.() -> Return, + dsl: TransactionDSL.() -> R, transactionMap: HashMap = HashMap() ): WireTransaction { val transactionLocation = getCallerLocation(3) @@ -277,19 +296,18 @@ data class TestLedgerDslInterpreter private constructor ( override fun transaction( transactionLabel: String?, - dsl: TransactionDsl.() -> LastLineShouldTestForVerifiesOrFails + dsl: TransactionDSL.() -> LastLineShouldTestForVerifiesOrFails ) = recordTransactionWithTransactionMap(transactionLabel, dsl, transactionWithLocations) - override fun nonVerifiedTransaction( + override fun unverifiedTransaction( transactionLabel: String?, - dsl: TransactionDsl.() -> Unit - ) = - recordTransactionWithTransactionMap(transactionLabel, dsl, nonVerifiedTransactionWithLocations) + dsl: TransactionDSL.() -> Unit + ) = recordTransactionWithTransactionMap(transactionLabel, dsl, nonVerifiedTransactionWithLocations) override fun tweak( - dsl: LedgerDsl>.() -> Unit) = - dsl(LedgerDsl(copy())) + dsl: LedgerDSL>.() -> Unit) = + dsl(LedgerDSL(copy())) override fun attachment(attachment: InputStream): SecureHash { return storageService.attachments.importAttachment(attachment) @@ -304,7 +322,7 @@ data class TestLedgerDslInterpreter private constructor ( } } - override fun retrieveOutputStateAndRef(clazz: Class, label: String): StateAndRef { + override fun retrieveOutputStateAndRef(clazz: Class, label: String): StateAndRef { val stateAndRef = labelToOutputStateAndRefs[label] if (stateAndRef == null) { throw IllegalArgumentException("State with label '$label' was not found") @@ -312,50 +330,25 @@ data class TestLedgerDslInterpreter private constructor ( throw TypeMismatch(requested = clazz, actual = stateAndRef.state.data.javaClass) } else { @Suppress("UNCHECKED_CAST") - return stateAndRef as StateAndRef + return stateAndRef as StateAndRef } } } -fun signAll(transactionsToSign: List, vararg extraKeys: KeyPair): List { - return transactionsToSign.map { wtx -> - val allPubKeys = wtx.signers.toMutableSet() - val bits = wtx.serialize() - require(bits == wtx.serialized) - val signatures = ArrayList() - for (key in ALL_TEST_KEYS + extraKeys) { - if (allPubKeys.contains(key.public)) { - signatures += key.signWithECDSA(bits) - allPubKeys -= key.public - } +fun signAll(transactionsToSign: List, extraKeys: Array) = transactionsToSign.map { wtx -> + val allPubKeys = wtx.signers.toMutableSet() + val bits = wtx.serialize() + require(bits == wtx.serialized) + val signatures = ArrayList() + for (key in ALL_TEST_KEYS + extraKeys) { + if (allPubKeys.contains(key.public)) { + signatures += key.signWithECDSA(bits) + allPubKeys -= key.public } - SignedTransaction(bits, signatures) } + SignedTransaction(bits, signatures) } -fun main(args: Array) { - ledger { - nonVerifiedTransaction { - output("hello") { DummyLinearState() } - } - - transaction { - input("hello") - tweak { - timestamp(TEST_TX_TIME, MEGA_CORP_PUBKEY) - fails() - } - } - - tweak { - - transaction { - input("hello") - timestamp(TEST_TX_TIME, MEGA_CORP_PUBKEY) - fails() - } - } - - this.verifies() - } -} +fun LedgerDSL.signAll( + transactionsToSign: List = this.interpreter.wireTransactions, vararg extraKeys: KeyPair) = + signAll(transactionsToSign, extraKeys) diff --git a/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt b/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt index bb57eec96f..db0361793f 100644 --- a/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt +++ b/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt @@ -93,13 +93,20 @@ object JavaTestHelpers { @JvmStatic @JvmOverloads fun ledger( identityService: IdentityService = MOCK_IDENTITY_SERVICE, storageService: StorageService = MockStorageService(), - dsl: LedgerDsl.() -> Unit - ): LedgerDsl { - val ledgerDsl = LedgerDsl(TestLedgerDslInterpreter(identityService, storageService)) + dsl: LedgerDSL.() -> Unit + ): LedgerDSL { + val ledgerDsl = LedgerDSL(TestLedgerDSLInterpreter(identityService, storageService)) dsl(ledgerDsl) return ledgerDsl } + @JvmStatic @JvmOverloads fun transaction( + transactionLabel: String? = null, + dsl: TransactionDSL< + LastLineShouldTestForVerifiesOrFails, + TransactionDSLInterpreter + >.() -> LastLineShouldTestForVerifiesOrFails + ) = ledger { transaction(transactionLabel, dsl) } } val TEST_TX_TIME = JavaTestHelpers.TEST_TX_TIME diff --git a/core/src/main/kotlin/com/r3corda/core/testing/TransactionDslInterpreter.kt b/core/src/main/kotlin/com/r3corda/core/testing/TransactionDSLInterpreter.kt similarity index 80% rename from core/src/main/kotlin/com/r3corda/core/testing/TransactionDslInterpreter.kt rename to core/src/main/kotlin/com/r3corda/core/testing/TransactionDSLInterpreter.kt index 85cb312839..d013c923fb 100644 --- a/core/src/main/kotlin/com/r3corda/core/testing/TransactionDslInterpreter.kt +++ b/core/src/main/kotlin/com/r3corda/core/testing/TransactionDSLInterpreter.kt @@ -30,39 +30,36 @@ import java.time.Instant // /** - * The [TransactionDslInterpreter] defines the interface DSL interpreters should satisfy. No + * The [TransactionDSLInterpreter] defines the interface DSL interpreters should satisfy. No * overloading/default valuing should be done here, only the basic functions that are required to implement everything. * Same goes for functions requiring reflection e.g. [OutputStateLookup.retrieveOutputStateAndRef] - * Put convenience functions in [TransactionDsl] instead. There are some cases where the overloads would clash with the + * Put convenience functions in [TransactionDSL] instead. There are some cases where the overloads would clash with the * Interpreter interface, in these cases define a "backing" function in the interface instead (e.g. [_command]). * * This way the responsibility of providing a nice frontend DSL and the implementation(s) are separated */ -interface TransactionDslInterpreter : OutputStateLookup { - val ledgerInterpreter: LedgerDslInterpreter> +interface TransactionDSLInterpreter : OutputStateLookup { + val ledgerInterpreter: LedgerDSLInterpreter> fun input(stateRef: StateRef) fun _output(label: String?, notary: Party, contractState: ContractState) fun attachment(attachmentId: SecureHash) fun _command(signers: List, commandData: CommandData) - fun verifies(): Return - fun failsWith(expectedMessage: String?): Return + fun verifies(): R + fun failsWith(expectedMessage: String?): R fun tweak( - dsl: TransactionDsl>.() -> Return - ): Return + dsl: TransactionDSL>.() -> R + ): R } -class TransactionDsl< - Return, - out TransactionInterpreter: TransactionDslInterpreter - > (val interpreter: TransactionInterpreter) - : TransactionDslInterpreter by interpreter { +class TransactionDSL> (val interpreter: T) : + TransactionDSLInterpreter by interpreter { fun input(stateLabel: String) = input(retrieveOutputStateAndRef(ContractState::class.java, stateLabel).ref) /** * Adds the passed in state as a non-verified transaction output to the ledger and adds that as an input */ fun input(state: ContractState) { - val transaction = ledgerInterpreter.nonVerifiedTransaction(null) { + val transaction = ledgerInterpreter.unverifiedTransaction(null) { output { state } } input(transaction.outRef(0).ref) diff --git a/core/src/test/kotlin/com/r3corda/core/contracts/TransactionGroupTests.kt b/core/src/test/kotlin/com/r3corda/core/contracts/TransactionGroupTests.kt index e8548db65d..6fb59ef18c 100644 --- a/core/src/test/kotlin/com/r3corda/core/contracts/TransactionGroupTests.kt +++ b/core/src/test/kotlin/com/r3corda/core/contracts/TransactionGroupTests.kt @@ -48,7 +48,7 @@ class TransactionGroupTests { @Test fun success() { ledger { - nonVerifiedTransaction { + unverifiedTransaction { output("£1000") { A_THOUSAND_POUNDS } } @@ -142,7 +142,7 @@ class TransactionGroupTests { fun duplicatedInputs() { // Check that a transaction cannot refer to the same input more than once. ledger { - nonVerifiedTransaction { + unverifiedTransaction { output("£1000") { A_THOUSAND_POUNDS } } @@ -162,7 +162,7 @@ class TransactionGroupTests { @Test fun signGroup() { - val signedTxns: List = ledger { + ledger { transaction { output("£1000") { A_THOUSAND_POUNDS } command(MINI_CORP_PUBKEY) { TestCash.Commands.Issue() } @@ -182,12 +182,14 @@ class TransactionGroupTests { command(MINI_CORP_PUBKEY) { TestCash.Commands.Exit(1000.POUNDS) } this.verifies() } - }.interpreter.wireTransactions.let { signAll(it) } - // Now go through the conversion -> verification path with them. - val ltxns = signedTxns.map { - it.verifyToLedgerTransaction(MOCK_IDENTITY_SERVICE, MockStorageService().attachments) - }.toSet() - TransactionGroup(ltxns, emptySet()).verify() + val signedTxns: List = signAll() + + // Now go through the conversion -> verification path with them. + val ltxns = signedTxns.map { + it.verifyToLedgerTransaction(MOCK_IDENTITY_SERVICE, MockStorageService().attachments) + }.toSet() + TransactionGroup(ltxns, emptySet()).verify() + } } } diff --git a/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt b/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt index e703d9306b..d18ab013aa 100644 --- a/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt +++ b/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt @@ -17,7 +17,6 @@ import com.r3corda.core.node.services.ServiceType import com.r3corda.core.node.services.TransactionStorage import com.r3corda.core.node.services.Wallet import com.r3corda.core.random63BitValue -import com.r3corda.core.contracts.Attachment import com.r3corda.core.seconds import com.r3corda.core.testing.* import com.r3corda.core.utilities.BriefLogFormatter @@ -367,7 +366,7 @@ class TwoPartyTradeProtocolTests { } } - private fun LedgerDsl.runWithError( + private fun LedgerDSL.runWithError( bobError: Boolean, aliceError: Boolean, expectedMessageSubstring: String @@ -423,7 +422,7 @@ class TwoPartyTradeProtocolTests { wtxToSign: List, services: ServiceHub, vararg extraKeys: KeyPair): Map { - val signed: List = signAll(wtxToSign, *extraKeys) + val signed: List = signAll(wtxToSign, extraKeys) services.recordTransactions(signed) val validatedTransactions = services.storageService.validatedTransactions if (validatedTransactions is RecordingTransactionStorage) { @@ -432,7 +431,7 @@ class TwoPartyTradeProtocolTests { return signed.associateBy { it.id } } - private fun LedgerDsl.fillUpForBuyer( + private fun LedgerDSL.fillUpForBuyer( withError: Boolean, owner: PublicKey = BOB_PUBKEY, issuer: PartyAndReference = MEGA_CORP.ref(1)): Pair> { @@ -473,7 +472,7 @@ class TwoPartyTradeProtocolTests { return Pair(wallet, listOf(eb1, bc1, bc2)) } - private fun LedgerDsl.fillUpForSeller( + private fun LedgerDSL.fillUpForSeller( withError: Boolean, owner: PublicKey, amount: Amount>, diff --git a/node/src/test/kotlin/com/r3corda/node/visualiser/GroupToGraphConversion.kt b/node/src/test/kotlin/com/r3corda/node/visualiser/GroupToGraphConversion.kt index 1285522a62..7b2292b35b 100644 --- a/node/src/test/kotlin/com/r3corda/node/visualiser/GroupToGraphConversion.kt +++ b/node/src/test/kotlin/com/r3corda/node/visualiser/GroupToGraphConversion.kt @@ -9,7 +9,7 @@ import org.graphstream.graph.Node import org.graphstream.graph.implementations.SingleGraph import kotlin.reflect.memberProperties -class GraphVisualiser(val dsl: LedgerDsl) { +class GraphVisualiser(val dsl: LedgerDSL) { companion object { val css = GraphVisualiser::class.java.getResourceAsStream("graph.css").bufferedReader().readText() } From f177b1ffaac7e0052b4db99a29a7e292bae89371 Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Tue, 5 Jul 2016 18:47:05 +0100 Subject: [PATCH 085/114] test dsl: LastLineShouldTestForVerifiesOrFails->EnforceVerifyOrFail --- .../r3corda/contracts/CommercialPaperTests.kt | 2 +- .../kotlin/com/r3corda/contracts/IRSTests.kt | 157 +++--- .../com/r3corda/contracts/asset/CashTests.kt | 528 +++++++++--------- .../contracts/asset/ObligationTests.kt | 2 +- .../com/r3corda/core/testing/TestDSL.kt | 60 +- .../com/r3corda/core/testing/TestUtils.kt | 10 +- .../messaging/TwoPartyTradeProtocolTests.kt | 6 +- .../node/visualiser/GroupToGraphConversion.kt | 2 +- 8 files changed, 374 insertions(+), 393 deletions(-) diff --git a/contracts/src/test/kotlin/com/r3corda/contracts/CommercialPaperTests.kt b/contracts/src/test/kotlin/com/r3corda/contracts/CommercialPaperTests.kt index 44a6d12700..c4b01fd7b1 100644 --- a/contracts/src/test/kotlin/com/r3corda/contracts/CommercialPaperTests.kt +++ b/contracts/src/test/kotlin/com/r3corda/contracts/CommercialPaperTests.kt @@ -97,7 +97,7 @@ class CommercialPaperTestsGeneric { input("alice's paper") input("some profits") - fun TransactionDSL>.outputs(aliceGetsBack: Amount>) { + fun TransactionDSL>.outputs(aliceGetsBack: Amount>) { output("Alice's profit") { aliceGetsBack.STATE `owned by` ALICE_PUBKEY } output("Change") { (someProfits - aliceGetsBack).STATE `owned by` MEGA_CORP_PUBKEY } } diff --git a/contracts/src/test/kotlin/com/r3corda/contracts/IRSTests.kt b/contracts/src/test/kotlin/com/r3corda/contracts/IRSTests.kt index 6d10560a42..e771e25140 100644 --- a/contracts/src/test/kotlin/com/r3corda/contracts/IRSTests.kt +++ b/contracts/src/test/kotlin/com/r3corda/contracts/IRSTests.kt @@ -360,7 +360,7 @@ class IRSTests { /** * Generates a typical transactional history for an IRS. */ - fun trade(): LedgerDSL { + fun trade(): LedgerDSL { val ld = LocalDate.of(2016, 3, 8) val bd = BigDecimal("0.0063518") @@ -555,96 +555,93 @@ class IRSTests { @Test fun `various fixing tests`() { - ledger { + val ld = LocalDate.of(2016, 3, 8) + val bd = BigDecimal("0.0063518") - val ld = LocalDate.of(2016, 3, 8) - val bd = BigDecimal("0.0063518") + transaction { + output("irs post agreement") { singleIRS() } + command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } + timestamp(TEST_TX_TIME) + this.verifies() + } - transaction { - output("irs post agreement") { singleIRS() } - command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } + val oldIRS = singleIRS(1) + val newIRS = oldIRS.copy(oldIRS.fixedLeg, + oldIRS.floatingLeg, + oldIRS.calculation.applyFixing(ld, FixedRate(RatioUnit(bd))), + oldIRS.common) + + transaction { + input() { + oldIRS + + } + + // Templated tweak for reference. A corrent fixing applied should be ok + tweak { + command(ORACLE_PUBKEY) { + InterestRateSwap.Commands.Fix() + } timestamp(TEST_TX_TIME) + command(ORACLE_PUBKEY) { + Fix(FixOf("ICE LIBOR", ld, Tenor("3M")), bd) + } + output() { newIRS } this.verifies() } - val oldIRS = singleIRS(1) - val newIRS = oldIRS.copy(oldIRS.fixedLeg, - oldIRS.floatingLeg, - oldIRS.calculation.applyFixing(ld, FixedRate(RatioUnit(bd))), - oldIRS.common) - - transaction { - input() { - oldIRS + // This test makes sure that verify confirms the fixing was applied and there is a difference in the old and new + tweak { + command(ORACLE_PUBKEY) { InterestRateSwap.Commands.Fix() } + timestamp(TEST_TX_TIME) + command(ORACLE_PUBKEY) { Fix(FixOf("ICE LIBOR", ld, Tenor("3M")), bd) } + output() { oldIRS } + this `fails with` "There is at least one difference in the IRS floating leg payment schedules" + } + // This tests tries to sneak in a change to another fixing (which may or may not be the latest one) + tweak { + command(ORACLE_PUBKEY) { InterestRateSwap.Commands.Fix() } + timestamp(TEST_TX_TIME) + command(ORACLE_PUBKEY) { + Fix(FixOf("ICE LIBOR", ld, Tenor("3M")), bd) } - // Templated tweak for reference. A corrent fixing applied should be ok - tweak { - command(ORACLE_PUBKEY) { - InterestRateSwap.Commands.Fix() - } - timestamp(TEST_TX_TIME) - command(ORACLE_PUBKEY) { - Fix(FixOf("ICE LIBOR", ld, Tenor("3M")), bd) - } - output() { newIRS } - this.verifies() + val firstResetKey = newIRS.calculation.floatingLegPaymentSchedule.keys.first() + val firstResetValue = newIRS.calculation.floatingLegPaymentSchedule[firstResetKey] + val modifiedFirstResetValue = firstResetValue!!.copy(notional = Amount(firstResetValue.notional.quantity, Currency.getInstance("JPY"))) + + output() { + newIRS.copy( + newIRS.fixedLeg, + newIRS.floatingLeg, + newIRS.calculation.copy(floatingLegPaymentSchedule = newIRS.calculation.floatingLegPaymentSchedule.plus( + Pair(firstResetKey, modifiedFirstResetValue))), + newIRS.common + ) } + this `fails with` "There is only one change in the IRS floating leg payment schedule" + } - // This test makes sure that verify confirms the fixing was applied and there is a difference in the old and new - tweak { - command(ORACLE_PUBKEY) { InterestRateSwap.Commands.Fix() } - timestamp(TEST_TX_TIME) - command(ORACLE_PUBKEY) { Fix(FixOf("ICE LIBOR", ld, Tenor("3M")), bd) } - output() { oldIRS } - this `fails with` "There is at least one difference in the IRS floating leg payment schedules" - } - - // This tests tries to sneak in a change to another fixing (which may or may not be the latest one) - tweak { - command(ORACLE_PUBKEY) { InterestRateSwap.Commands.Fix() } - timestamp(TEST_TX_TIME) - command(ORACLE_PUBKEY) { - Fix(FixOf("ICE LIBOR", ld, Tenor("3M")), bd) - } - - val firstResetKey = newIRS.calculation.floatingLegPaymentSchedule.keys.first() - val firstResetValue = newIRS.calculation.floatingLegPaymentSchedule[firstResetKey] - val modifiedFirstResetValue = firstResetValue!!.copy(notional = Amount(firstResetValue.notional.quantity, Currency.getInstance("JPY"))) - - output() { - newIRS.copy( - newIRS.fixedLeg, - newIRS.floatingLeg, - newIRS.calculation.copy(floatingLegPaymentSchedule = newIRS.calculation.floatingLegPaymentSchedule.plus( - Pair(firstResetKey, modifiedFirstResetValue))), - newIRS.common - ) - } - this `fails with` "There is only one change in the IRS floating leg payment schedule" - } - - // This tests modifies the payment currency for the fixing - tweak { - command(ORACLE_PUBKEY) { InterestRateSwap.Commands.Fix() } - timestamp(TEST_TX_TIME) - command(ORACLE_PUBKEY) { Fix(FixOf("ICE LIBOR", ld, Tenor("3M")), bd) } - - val latestReset = newIRS.calculation.floatingLegPaymentSchedule.filter { it.value.rate is FixedRate }.maxBy { it.key } - val modifiedLatestResetValue = latestReset!!.value.copy(notional = Amount(latestReset.value.notional.quantity, Currency.getInstance("JPY"))) - - output() { - newIRS.copy( - newIRS.fixedLeg, - newIRS.floatingLeg, - newIRS.calculation.copy(floatingLegPaymentSchedule = newIRS.calculation.floatingLegPaymentSchedule.plus( - Pair(latestReset.key, modifiedLatestResetValue))), - newIRS.common - ) - } - this `fails with` "The fix payment has the same currency as the notional" + // This tests modifies the payment currency for the fixing + tweak { + command(ORACLE_PUBKEY) { InterestRateSwap.Commands.Fix() } + timestamp(TEST_TX_TIME) + command(ORACLE_PUBKEY) { Fix(FixOf("ICE LIBOR", ld, Tenor("3M")), bd) } + + val latestReset = newIRS.calculation.floatingLegPaymentSchedule.filter { it.value.rate is FixedRate }.maxBy { it.key } + val modifiedLatestResetValue = latestReset!!.value.copy(notional = Amount(latestReset.value.notional.quantity, Currency.getInstance("JPY"))) + + output() { + newIRS.copy( + newIRS.fixedLeg, + newIRS.floatingLeg, + newIRS.calculation.copy(floatingLegPaymentSchedule = newIRS.calculation.floatingLegPaymentSchedule.plus( + Pair(latestReset.key, modifiedLatestResetValue))), + newIRS.common + ) } + this `fails with` "The fix payment has the same currency as the notional" } } } @@ -656,7 +653,7 @@ class IRSTests { * result and the grouping won't work either. * In reality, the only fields that should be in common will be the next fixing date and the reference rate. */ - fun tradegroups(): LedgerDSL { + fun tradegroups(): LedgerDSL { val ld1 = LocalDate.of(2016, 3, 8) val bd1 = BigDecimal("0.0063518") diff --git a/contracts/src/test/kotlin/com/r3corda/contracts/asset/CashTests.kt b/contracts/src/test/kotlin/com/r3corda/contracts/asset/CashTests.kt index a384315b2c..bc7e11a9f7 100644 --- a/contracts/src/test/kotlin/com/r3corda/contracts/asset/CashTests.kt +++ b/contracts/src/test/kotlin/com/r3corda/contracts/asset/CashTests.kt @@ -29,146 +29,142 @@ class CashTests { @Test fun trivial() { - ledger { - transaction { - input { inState } - this `fails with` "the amounts balance" + transaction { + input { inState } + this `fails with` "the amounts balance" - tweak { - output { outState.copy(amount = 2000.DOLLARS `issued by` defaultIssuer) } - this `fails with` "the amounts balance" - } - tweak { - output { outState } - // No command commanduments - this `fails with` "required com.r3corda.contracts.asset.FungibleAsset.Commands.Move command" - } - tweak { - output { outState } - command(DUMMY_PUBKEY_2) { Cash.Commands.Move() } - this `fails with` "the owning keys are the same as the signing keys" - } - tweak { - output { outState } - output { outState `issued by` MINI_CORP } - command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } - this `fails with` "at least one asset input" - } - // Simple reallocation works. - tweak { - output { outState } - command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } - this.verifies() - } + tweak { + output { outState.copy(amount = 2000.DOLLARS `issued by` defaultIssuer) } + this `fails with` "the amounts balance" + } + tweak { + output { outState } + // No command commanduments + this `fails with` "required com.r3corda.contracts.asset.FungibleAsset.Commands.Move command" + } + tweak { + output { outState } + command(DUMMY_PUBKEY_2) { Cash.Commands.Move() } + this `fails with` "the owning keys are the same as the signing keys" + } + tweak { + output { outState } + output { outState `issued by` MINI_CORP } + command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } + this `fails with` "at least one asset input" + } + // Simple reallocation works. + tweak { + output { outState } + command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } + this.verifies() } } } @Test fun issueMoney() { - ledger { - // Check we can't "move" money into existence. - transaction { - input { DummyState() } - output { outState } - command(MINI_CORP_PUBKEY) { Cash.Commands.Move() } + // Check we can't "move" money into existence. + transaction { + input { DummyState() } + output { outState } + command(MINI_CORP_PUBKEY) { Cash.Commands.Move() } - this `fails with` "there is at least one asset input" + this `fails with` "there is at least one asset input" + } + + // Check we can issue money only as long as the issuer institution is a command signer, i.e. any recognised + // institution is allowed to issue as much cash as they want. + transaction { + output { outState } + command(DUMMY_PUBKEY_1) { Cash.Commands.Issue() } + this `fails with` "output deposits are owned by a command signer" + } + transaction { + output { + Cash.State( + amount = 1000.DOLLARS `issued by` MINI_CORP.ref(12, 34), + owner = DUMMY_PUBKEY_1 + ) + } + tweak { + command(MINI_CORP_PUBKEY) { Cash.Commands.Issue(0) } + this `fails with` "has a nonce" + } + command(MINI_CORP_PUBKEY) { Cash.Commands.Issue() } + this.verifies() + } + + // Test generation works. + val ptx = TransactionType.General.Builder() + Cash().generateIssue(ptx, 100.DOLLARS `issued by` MINI_CORP.ref(12, 34), owner = DUMMY_PUBKEY_1, notary = DUMMY_NOTARY) + assertTrue(ptx.inputStates().isEmpty()) + val s = ptx.outputStates()[0].data as Cash.State + assertEquals(100.DOLLARS `issued by` MINI_CORP.ref(12, 34), s.amount) + assertEquals(MINI_CORP, s.deposit.party) + assertEquals(DUMMY_PUBKEY_1, s.owner) + assertTrue(ptx.commands()[0].value is Cash.Commands.Issue) + assertEquals(MINI_CORP_PUBKEY, ptx.commands()[0].signers[0]) + + // Test issuance from the issuance definition + val amount = 100.DOLLARS `issued by` MINI_CORP.ref(12, 34) + val templatePtx = TransactionType.General.Builder() + Cash().generateIssue(templatePtx, amount, owner = DUMMY_PUBKEY_1, notary = DUMMY_NOTARY) + assertTrue(templatePtx.inputStates().isEmpty()) + assertEquals(ptx.outputStates()[0], templatePtx.outputStates()[0]) + + // We can consume $1000 in a transaction and output $2000 as long as it's signed by an issuer. + transaction { + input { inState } + output { inState.copy(amount = inState.amount * 2) } + + // Move fails: not allowed to summon money. + tweak { + command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } + this `fails with` "at issuer MegaCorp the amounts balance" } - // Check we can issue money only as long as the issuer institution is a command signer, i.e. any recognised - // institution is allowed to issue as much cash as they want. - transaction { - output { outState } - command(DUMMY_PUBKEY_1) { Cash.Commands.Issue() } - this `fails with` "output deposits are owned by a command signer" - } - transaction { - output { - Cash.State( - amount = 1000.DOLLARS `issued by` MINI_CORP.ref(12, 34), - owner = DUMMY_PUBKEY_1 - ) - } - tweak { - command(MINI_CORP_PUBKEY) { Cash.Commands.Issue(0) } - this `fails with` "has a nonce" - } - command(MINI_CORP_PUBKEY) { Cash.Commands.Issue() } + // Issue works. + tweak { + command(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() } this.verifies() } + } - // Test generation works. - val ptx = TransactionType.General.Builder() - Cash().generateIssue(ptx, 100.DOLLARS `issued by` MINI_CORP.ref(12, 34), owner = DUMMY_PUBKEY_1, notary = DUMMY_NOTARY) - assertTrue(ptx.inputStates().isEmpty()) - val s = ptx.outputStates()[0].data as Cash.State - assertEquals(100.DOLLARS `issued by` MINI_CORP.ref(12, 34), s.amount) - assertEquals(MINI_CORP, s.deposit.party) - assertEquals(DUMMY_PUBKEY_1, s.owner) - assertTrue(ptx.commands()[0].value is Cash.Commands.Issue) - assertEquals(MINI_CORP_PUBKEY, ptx.commands()[0].signers[0]) + // Can't use an issue command to lower the amount. + transaction { + input { inState } + output { inState.copy(amount = inState.amount / 2) } + command(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() } + this `fails with` "output values sum to more than the inputs" + } - // Test issuance from the issuance definition - val amount = 100.DOLLARS `issued by` MINI_CORP.ref(12, 34) - val templatePtx = TransactionType.General.Builder() - Cash().generateIssue(templatePtx, amount, owner = DUMMY_PUBKEY_1, notary = DUMMY_NOTARY) - assertTrue(templatePtx.inputStates().isEmpty()) - assertEquals(ptx.outputStates()[0], templatePtx.outputStates()[0]) + // Can't have an issue command that doesn't actually issue money. + transaction { + input { inState } + output { inState } + command(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() } + this `fails with` "output values sum to more than the inputs" + } - // We can consume $1000 in a transaction and output $2000 as long as it's signed by an issuer. - transaction { - input { inState } - output { inState.copy(amount = inState.amount * 2) } - - // Move fails: not allowed to summon money. - tweak { - command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } - this `fails with` "at issuer MegaCorp the amounts balance" - } - - // Issue works. - tweak { - command(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() } - this.verifies() - } - } - - // Can't use an issue command to lower the amount. - transaction { - input { inState } - output { inState.copy(amount = inState.amount / 2) } + // Can't have any other commands if we have an issue command (because the issue command overrules them) + transaction { + input { inState } + output { inState.copy(amount = inState.amount * 2) } + command(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() } + tweak { command(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() } - this `fails with` "output values sum to more than the inputs" + this `fails with` "there is only a single issue command" } - - // Can't have an issue command that doesn't actually issue money. - transaction { - input { inState } - output { inState } - command(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() } - this `fails with` "output values sum to more than the inputs" + tweak { + command(MEGA_CORP_PUBKEY) { Cash.Commands.Move() } + this `fails with` "there is only a single issue command" } - - // Can't have any other commands if we have an issue command (because the issue command overrules them) - transaction { - input { inState } - output { inState.copy(amount = inState.amount * 2) } - command(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() } - tweak { - command(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() } - this `fails with` "there is only a single issue command" - } - tweak { - command(MEGA_CORP_PUBKEY) { Cash.Commands.Move() } - this `fails with` "there is only a single issue command" - } - tweak { - command(MEGA_CORP_PUBKEY) { Cash.Commands.Exit(inState.amount / 2) } - this `fails with` "there is only a single issue command" - } - this.verifies() + tweak { + command(MEGA_CORP_PUBKEY) { Cash.Commands.Exit(inState.amount / 2) } + this `fails with` "there is only a single issue command" } + this.verifies() } } @@ -193,190 +189,178 @@ class CashTests { @Test fun testMergeSplit() { - ledger { - // Splitting value works. - transaction { - command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } - tweak { - input { inState } - for (i in 1..4) output { inState.copy(amount = inState.amount / 4) } - this.verifies() - } - // Merging 4 inputs into 2 outputs works. - tweak { - for (i in 1..4) input { inState.copy(amount = inState.amount / 4) } - output { inState.copy(amount = inState.amount / 2) } - output { inState.copy(amount = inState.amount / 2) } - this.verifies() - } - // Merging 2 inputs into 1 works. - tweak { - input { inState.copy(amount = inState.amount / 2) } - input { inState.copy(amount = inState.amount / 2) } - output { inState } - this.verifies() - } + // Splitting value works. + transaction { + command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } + tweak { + input { inState } + for (i in 1..4) output { inState.copy(amount = inState.amount / 4) } + this.verifies() + } + // Merging 4 inputs into 2 outputs works. + tweak { + for (i in 1..4) input { inState.copy(amount = inState.amount / 4) } + output { inState.copy(amount = inState.amount / 2) } + output { inState.copy(amount = inState.amount / 2) } + this.verifies() + } + // Merging 2 inputs into 1 works. + tweak { + input { inState.copy(amount = inState.amount / 2) } + input { inState.copy(amount = inState.amount / 2) } + output { inState } + this.verifies() } } } @Test fun zeroSizedValues() { - ledger { - transaction { - input { inState } - input { inState.copy(amount = 0.DOLLARS `issued by` defaultIssuer) } - this `fails with` "zero sized inputs" - } - transaction { - input { inState } - output { inState } - output { inState.copy(amount = 0.DOLLARS `issued by` defaultIssuer) } - this `fails with` "zero sized outputs" - } + transaction { + input { inState } + input { inState.copy(amount = 0.DOLLARS `issued by` defaultIssuer) } + this `fails with` "zero sized inputs" + } + transaction { + input { inState } + output { inState } + output { inState.copy(amount = 0.DOLLARS `issued by` defaultIssuer) } + this `fails with` "zero sized outputs" } } @Test fun trivialMismatches() { - ledger { - // Can't change issuer. - transaction { - input { inState } - output { outState `issued by` MINI_CORP } - this `fails with` "at issuer MegaCorp the amounts balance" - } - // Can't change deposit reference when splitting. - transaction { - input { inState } - output { outState.copy(amount = inState.amount / 2).editDepositRef(0) } - output { outState.copy(amount = inState.amount / 2).editDepositRef(1) } - this `fails with` "for deposit [01] at issuer MegaCorp the amounts balance" - } - // Can't mix currencies. - transaction { - input { inState } - output { outState.copy(amount = 800.DOLLARS `issued by` defaultIssuer) } - output { outState.copy(amount = 200.POUNDS `issued by` defaultIssuer) } - this `fails with` "the amounts balance" - } - transaction { - input { inState } - input { - inState.copy( - amount = 150.POUNDS `issued by` defaultIssuer, - owner = DUMMY_PUBKEY_2 - ) - } - output { outState.copy(amount = 1150.DOLLARS `issued by` defaultIssuer) } - this `fails with` "the amounts balance" - } - // Can't have superfluous input states from different issuers. - transaction { - input { inState } - input { inState `issued by` MINI_CORP } - output { outState } - command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } - this `fails with` "at issuer MiniCorp the amounts balance" - } - // Can't combine two different deposits at the same issuer. - transaction { - input { inState } - input { inState.editDepositRef(3) } - output { outState.copy(amount = inState.amount * 2).editDepositRef(3) } - this `fails with` "for deposit [01]" + // Can't change issuer. + transaction { + input { inState } + output { outState `issued by` MINI_CORP } + this `fails with` "at issuer MegaCorp the amounts balance" + } + // Can't change deposit reference when splitting. + transaction { + input { inState } + output { outState.copy(amount = inState.amount / 2).editDepositRef(0) } + output { outState.copy(amount = inState.amount / 2).editDepositRef(1) } + this `fails with` "for deposit [01] at issuer MegaCorp the amounts balance" + } + // Can't mix currencies. + transaction { + input { inState } + output { outState.copy(amount = 800.DOLLARS `issued by` defaultIssuer) } + output { outState.copy(amount = 200.POUNDS `issued by` defaultIssuer) } + this `fails with` "the amounts balance" + } + transaction { + input { inState } + input { + inState.copy( + amount = 150.POUNDS `issued by` defaultIssuer, + owner = DUMMY_PUBKEY_2 + ) } + output { outState.copy(amount = 1150.DOLLARS `issued by` defaultIssuer) } + this `fails with` "the amounts balance" + } + // Can't have superfluous input states from different issuers. + transaction { + input { inState } + input { inState `issued by` MINI_CORP } + output { outState } + command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } + this `fails with` "at issuer MiniCorp the amounts balance" + } + // Can't combine two different deposits at the same issuer. + transaction { + input { inState } + input { inState.editDepositRef(3) } + output { outState.copy(amount = inState.amount * 2).editDepositRef(3) } + this `fails with` "for deposit [01]" } } @Test fun exitLedger() { - ledger { - // Single input/output straightforward case. - transaction { - input { inState } - output { outState.copy(amount = inState.amount - (200.DOLLARS `issued by` defaultIssuer)) } - - tweak { - command(MEGA_CORP_PUBKEY) { Cash.Commands.Exit(100.DOLLARS `issued by` defaultIssuer) } - command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } - this `fails with` "the amounts balance" - } - - tweak { - command(MEGA_CORP_PUBKEY) { Cash.Commands.Exit(200.DOLLARS `issued by` defaultIssuer) } - this `fails with` "required com.r3corda.contracts.asset.FungibleAsset.Commands.Move command" - - tweak { - command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } - this.verifies() - } - } - } - // Multi-issuer case. - transaction { - input { inState } - input { inState `issued by` MINI_CORP } - - output { inState.copy(amount = inState.amount - (200.DOLLARS `issued by` defaultIssuer)) `issued by` MINI_CORP } - output { inState.copy(amount = inState.amount - (200.DOLLARS `issued by` defaultIssuer)) } + // Single input/output straightforward case. + transaction { + input { inState } + output { outState.copy(amount = inState.amount - (200.DOLLARS `issued by` defaultIssuer)) } + tweak { + command(MEGA_CORP_PUBKEY) { Cash.Commands.Exit(100.DOLLARS `issued by` defaultIssuer) } command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } - - this `fails with` "at issuer MegaCorp the amounts balance" - - command(MEGA_CORP_PUBKEY) { Cash.Commands.Exit(200.DOLLARS `issued by` defaultIssuer) } - this `fails with` "at issuer MiniCorp the amounts balance" - - command(MINI_CORP_PUBKEY) { Cash.Commands.Exit(200.DOLLARS `issued by` MINI_CORP.ref(defaultRef)) } - this.verifies() + this `fails with` "the amounts balance" } + + tweak { + command(MEGA_CORP_PUBKEY) { Cash.Commands.Exit(200.DOLLARS `issued by` defaultIssuer) } + this `fails with` "required com.r3corda.contracts.asset.FungibleAsset.Commands.Move command" + + tweak { + command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } + this.verifies() + } + } + } + // Multi-issuer case. + transaction { + input { inState } + input { inState `issued by` MINI_CORP } + + output { inState.copy(amount = inState.amount - (200.DOLLARS `issued by` defaultIssuer)) `issued by` MINI_CORP } + output { inState.copy(amount = inState.amount - (200.DOLLARS `issued by` defaultIssuer)) } + + command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } + + this `fails with` "at issuer MegaCorp the amounts balance" + + command(MEGA_CORP_PUBKEY) { Cash.Commands.Exit(200.DOLLARS `issued by` defaultIssuer) } + this `fails with` "at issuer MiniCorp the amounts balance" + + command(MINI_CORP_PUBKEY) { Cash.Commands.Exit(200.DOLLARS `issued by` MINI_CORP.ref(defaultRef)) } + this.verifies() } } @Test fun multiIssuer() { - ledger { - transaction { - // Gather 2000 dollars from two different issuers. - input { inState } - input { inState `issued by` MINI_CORP } + transaction { + // Gather 2000 dollars from two different issuers. + input { inState } + input { inState `issued by` MINI_CORP } - // Can't merge them together. - tweak { - output { inState.copy(owner = DUMMY_PUBKEY_2, amount = 2000.DOLLARS `issued by` defaultIssuer) } - this `fails with` "at issuer MegaCorp the amounts balance" - } - // Missing MiniCorp deposit - tweak { - output { inState.copy(owner = DUMMY_PUBKEY_2) } - output { inState.copy(owner = DUMMY_PUBKEY_2) } - this `fails with` "at issuer MegaCorp the amounts balance" - } - - // This works. - output { inState.copy(owner = DUMMY_PUBKEY_2) } - output { inState.copy(owner = DUMMY_PUBKEY_2) `issued by` MINI_CORP } - command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } - this.verifies() + // Can't merge them together. + tweak { + output { inState.copy(owner = DUMMY_PUBKEY_2, amount = 2000.DOLLARS `issued by` defaultIssuer) } + this `fails with` "at issuer MegaCorp the amounts balance" } + // Missing MiniCorp deposit + tweak { + output { inState.copy(owner = DUMMY_PUBKEY_2) } + output { inState.copy(owner = DUMMY_PUBKEY_2) } + this `fails with` "at issuer MegaCorp the amounts balance" + } + + // This works. + output { inState.copy(owner = DUMMY_PUBKEY_2) } + output { inState.copy(owner = DUMMY_PUBKEY_2) `issued by` MINI_CORP } + command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } + this.verifies() } } @Test fun multiCurrency() { - ledger { - // Check we can do an atomic currency trade tx. - transaction { - val pounds = Cash.State(658.POUNDS `issued by` MINI_CORP.ref(3, 4, 5), DUMMY_PUBKEY_2) - input { inState `owned by` DUMMY_PUBKEY_1 } - input { pounds } - output { inState `owned by` DUMMY_PUBKEY_2 } - output { pounds `owned by` DUMMY_PUBKEY_1 } - command(DUMMY_PUBKEY_1, DUMMY_PUBKEY_2) { Cash.Commands.Move() } + // Check we can do an atomic currency trade tx. + transaction { + val pounds = Cash.State(658.POUNDS `issued by` MINI_CORP.ref(3, 4, 5), DUMMY_PUBKEY_2) + input { inState `owned by` DUMMY_PUBKEY_1 } + input { pounds } + output { inState `owned by` DUMMY_PUBKEY_2 } + output { pounds `owned by` DUMMY_PUBKEY_1 } + command(DUMMY_PUBKEY_1, DUMMY_PUBKEY_2) { Cash.Commands.Move() } - this.verifies() - } + this.verifies() } } diff --git a/contracts/src/test/kotlin/com/r3corda/contracts/asset/ObligationTests.kt b/contracts/src/test/kotlin/com/r3corda/contracts/asset/ObligationTests.kt index d6f8a6c1d6..5eec7d84c9 100644 --- a/contracts/src/test/kotlin/com/r3corda/contracts/asset/ObligationTests.kt +++ b/contracts/src/test/kotlin/com/r3corda/contracts/asset/ObligationTests.kt @@ -35,7 +35,7 @@ class ObligationTests { val outState = inState.copy(beneficiary = DUMMY_PUBKEY_2) private fun obligationTestRoots( - group: LedgerDSL + group: LedgerDSL ) = group.apply { unverifiedTransaction { output("Alice's $1,000,000 obligation to Bob", oneMillionDollars.OBLIGATION `between` Pair(ALICE, BOB_PUBKEY)) diff --git a/core/src/main/kotlin/com/r3corda/core/testing/TestDSL.kt b/core/src/main/kotlin/com/r3corda/core/testing/TestDSL.kt index 9415e30811..564524dc85 100644 --- a/core/src/main/kotlin/com/r3corda/core/testing/TestDSL.kt +++ b/core/src/main/kotlin/com/r3corda/core/testing/TestDSL.kt @@ -17,15 +17,15 @@ import java.util.* fun transaction( transactionLabel: String? = null, dsl: TransactionDSL< - LastLineShouldTestForVerifiesOrFails, - TransactionDSLInterpreter - >.() -> LastLineShouldTestForVerifiesOrFails + EnforceVerifyOrFail, + TransactionDSLInterpreter + >.() -> EnforceVerifyOrFail ) = JavaTestHelpers.transaction(transactionLabel, dsl) fun ledger( identityService: IdentityService = MOCK_IDENTITY_SERVICE, storageService: StorageService = MockStorageService(), - dsl: LedgerDSL.() -> Unit + dsl: LedgerDSL.() -> Unit ) = JavaTestHelpers.ledger(identityService, storageService, dsl) @Deprecated( @@ -33,8 +33,8 @@ fun ledger( replaceWith = ReplaceWith("tweak"), level = DeprecationLevel.ERROR) @Suppress("UNUSED_PARAMETER") -fun TransactionDSLInterpreter.ledger( - dsl: LedgerDSL.() -> Unit) { +fun TransactionDSLInterpreter.ledger( + dsl: LedgerDSL.() -> Unit) { } @Deprecated( @@ -42,11 +42,11 @@ fun TransactionDSLInterpreter.ledger( replaceWith = ReplaceWith("tweak"), level = DeprecationLevel.ERROR) @Suppress("UNUSED_PARAMETER") -fun TransactionDSLInterpreter.transaction( +fun TransactionDSLInterpreter.transaction( dsl: TransactionDSL< - LastLineShouldTestForVerifiesOrFails, - TransactionDSLInterpreter - >.() -> LastLineShouldTestForVerifiesOrFails) { + EnforceVerifyOrFail, + TransactionDSLInterpreter + >.() -> EnforceVerifyOrFail) { } @Deprecated( @@ -54,8 +54,8 @@ fun TransactionDSLInterpreter.transaction( replaceWith = ReplaceWith("tweak"), level = DeprecationLevel.ERROR) @Suppress("UNUSED_PARAMETER") -fun LedgerDSLInterpreter>.ledger( - dsl: LedgerDSL.() -> Unit) { +fun LedgerDSLInterpreter>.ledger( + dsl: LedgerDSL.() -> Unit) { } /** @@ -64,8 +64,8 @@ fun LedgerDSLInterpreter = arrayListOf(), private val signers: LinkedHashSet = LinkedHashSet(), private val transactionType: TransactionType = TransactionType.General() -) : TransactionDSLInterpreter, OutputStateLookup by ledgerInterpreter { +) : TransactionDSLInterpreter, OutputStateLookup by ledgerInterpreter { private fun copy(): TestTransactionDSLInterpreter = TestTransactionDSLInterpreter( ledgerInterpreter = ledgerInterpreter, @@ -121,13 +121,13 @@ data class TestTransactionDSLInterpreter( commands.add(Command(commandData, signers)) } - override fun verifies(): LastLineShouldTestForVerifiesOrFails { + override fun verifies(): EnforceVerifyOrFail { val resolvedTransaction = ledgerInterpreter.resolveWireTransaction(toWireTransaction()) resolvedTransaction.verify() - return LastLineShouldTestForVerifiesOrFails.Token + return EnforceVerifyOrFail.Token } - override fun failsWith(expectedMessage: String?): LastLineShouldTestForVerifiesOrFails { + override fun failsWith(expectedMessage: String?): EnforceVerifyOrFail { val exceptionThrown = try { this.verifies() false @@ -151,14 +151,14 @@ data class TestTransactionDSLInterpreter( throw AssertionError("Expected exception but didn't get one") } - return LastLineShouldTestForVerifiesOrFails.Token + return EnforceVerifyOrFail.Token } override fun tweak( dsl: TransactionDSL< - LastLineShouldTestForVerifiesOrFails, - TransactionDSLInterpreter - >.() -> LastLineShouldTestForVerifiesOrFails + EnforceVerifyOrFail, + TransactionDSLInterpreter + >.() -> EnforceVerifyOrFail ) = dsl(TransactionDSL(copy())) } @@ -171,7 +171,7 @@ data class TestLedgerDSLInterpreter private constructor ( internal val labelToOutputStateAndRefs: HashMap> = HashMap(), private val transactionWithLocations: HashMap = HashMap(), private val nonVerifiedTransactionWithLocations: HashMap = HashMap() -) : LedgerDSLInterpreter { +) : LedgerDSLInterpreter { val wireTransactions: List get() = transactionWithLocations.values.map { it.transaction } @@ -243,7 +243,7 @@ data class TestLedgerDSLInterpreter private constructor ( storageService.attachments.openAttachment(attachmentId) ?: throw AttachmentResolutionException(attachmentId) private fun interpretTransactionDsl( - dsl: TransactionDSL.() -> Return + dsl: TransactionDSL.() -> Return ): TestTransactionDSLInterpreter { val transactionInterpreter = TestTransactionDSLInterpreter(this) dsl(TransactionDSL(transactionInterpreter)) @@ -274,7 +274,7 @@ data class TestLedgerDSLInterpreter private constructor ( private fun recordTransactionWithTransactionMap( transactionLabel: String?, - dsl: TransactionDSL.() -> R, + dsl: TransactionDSL.() -> R, transactionMap: HashMap = HashMap() ): WireTransaction { val transactionLocation = getCallerLocation(3) @@ -296,17 +296,17 @@ data class TestLedgerDSLInterpreter private constructor ( override fun transaction( transactionLabel: String?, - dsl: TransactionDSL.() -> LastLineShouldTestForVerifiesOrFails + dsl: TransactionDSL.() -> EnforceVerifyOrFail ) = recordTransactionWithTransactionMap(transactionLabel, dsl, transactionWithLocations) override fun unverifiedTransaction( transactionLabel: String?, - dsl: TransactionDSL.() -> Unit + dsl: TransactionDSL.() -> Unit ) = recordTransactionWithTransactionMap(transactionLabel, dsl, nonVerifiedTransactionWithLocations) override fun tweak( - dsl: LedgerDSL>.() -> Unit) = + dsl: LedgerDSL>.() -> Unit) = dsl(LedgerDSL(copy())) override fun attachment(attachment: InputStream): SecureHash { @@ -349,6 +349,6 @@ fun signAll(transactionsToSign: List, extraKeys: Array.signAll( +fun LedgerDSL.signAll( transactionsToSign: List = this.interpreter.wireTransactions, vararg extraKeys: KeyPair) = signAll(transactionsToSign, extraKeys) diff --git a/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt b/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt index db0361793f..ad3557ae39 100644 --- a/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt +++ b/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt @@ -93,8 +93,8 @@ object JavaTestHelpers { @JvmStatic @JvmOverloads fun ledger( identityService: IdentityService = MOCK_IDENTITY_SERVICE, storageService: StorageService = MockStorageService(), - dsl: LedgerDSL.() -> Unit - ): LedgerDSL { + dsl: LedgerDSL.() -> Unit + ): LedgerDSL { val ledgerDsl = LedgerDSL(TestLedgerDSLInterpreter(identityService, storageService)) dsl(ledgerDsl) return ledgerDsl @@ -103,9 +103,9 @@ object JavaTestHelpers { @JvmStatic @JvmOverloads fun transaction( transactionLabel: String? = null, dsl: TransactionDSL< - LastLineShouldTestForVerifiesOrFails, - TransactionDSLInterpreter - >.() -> LastLineShouldTestForVerifiesOrFails + EnforceVerifyOrFail, + TransactionDSLInterpreter + >.() -> EnforceVerifyOrFail ) = ledger { transaction(transactionLabel, dsl) } } diff --git a/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt b/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt index d18ab013aa..0176a6eda9 100644 --- a/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt +++ b/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt @@ -366,7 +366,7 @@ class TwoPartyTradeProtocolTests { } } - private fun LedgerDSL.runWithError( + private fun LedgerDSL.runWithError( bobError: Boolean, aliceError: Boolean, expectedMessageSubstring: String @@ -431,7 +431,7 @@ class TwoPartyTradeProtocolTests { return signed.associateBy { it.id } } - private fun LedgerDSL.fillUpForBuyer( + private fun LedgerDSL.fillUpForBuyer( withError: Boolean, owner: PublicKey = BOB_PUBKEY, issuer: PartyAndReference = MEGA_CORP.ref(1)): Pair> { @@ -472,7 +472,7 @@ class TwoPartyTradeProtocolTests { return Pair(wallet, listOf(eb1, bc1, bc2)) } - private fun LedgerDSL.fillUpForSeller( + private fun LedgerDSL.fillUpForSeller( withError: Boolean, owner: PublicKey, amount: Amount>, diff --git a/node/src/test/kotlin/com/r3corda/node/visualiser/GroupToGraphConversion.kt b/node/src/test/kotlin/com/r3corda/node/visualiser/GroupToGraphConversion.kt index 7b2292b35b..6b61416d5a 100644 --- a/node/src/test/kotlin/com/r3corda/node/visualiser/GroupToGraphConversion.kt +++ b/node/src/test/kotlin/com/r3corda/node/visualiser/GroupToGraphConversion.kt @@ -9,7 +9,7 @@ import org.graphstream.graph.Node import org.graphstream.graph.implementations.SingleGraph import kotlin.reflect.memberProperties -class GraphVisualiser(val dsl: LedgerDSL) { +class GraphVisualiser(val dsl: LedgerDSL) { companion object { val css = GraphVisualiser::class.java.getResourceAsStream("graph.css").bufferedReader().readText() } From 26d897374699c66dc1ec2080bfd3c0bc0761270a Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Tue, 5 Jul 2016 19:01:26 +0100 Subject: [PATCH 086/114] test dsl: Add TODO on type synonyms --- .../kotlin/com/r3corda/core/testing/LedgerDSLInterpreter.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/src/main/kotlin/com/r3corda/core/testing/LedgerDSLInterpreter.kt b/core/src/main/kotlin/com/r3corda/core/testing/LedgerDSLInterpreter.kt index eb1aea76e1..27c24606b4 100644 --- a/core/src/main/kotlin/com/r3corda/core/testing/LedgerDSLInterpreter.kt +++ b/core/src/main/kotlin/com/r3corda/core/testing/LedgerDSLInterpreter.kt @@ -20,6 +20,8 @@ interface LedgerDSLInterpreter> : Output * This is the class the top-level primitives deal with. It delegates all other primitives to the contained interpreter. * This way we have a decoupling of the DSL "AST" and the interpretation(s) of it. Note how the delegation forces * covariance of the TransactionInterpreter parameter + * + * TODO (Kotlin 1.1): Use type synonyms to make the type params less unwieldy */ class LedgerDSL, out L : LedgerDSLInterpreter> (val interpreter: L) : LedgerDSLInterpreter> by interpreter { From 0cf54d1c1f431ff94b5151f862f1d6c2dd2722f2 Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Tue, 5 Jul 2016 19:03:48 +0100 Subject: [PATCH 087/114] test dsl: Comment full stops --- .../src/test/kotlin/com/r3corda/contracts/asset/CashTests.kt | 2 +- .../kotlin/com/r3corda/core/testing/LedgerDSLInterpreter.kt | 2 +- .../com/r3corda/core/testing/TransactionDSLInterpreter.kt | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/contracts/src/test/kotlin/com/r3corda/contracts/asset/CashTests.kt b/contracts/src/test/kotlin/com/r3corda/contracts/asset/CashTests.kt index bc7e11a9f7..a4adf2afbb 100644 --- a/contracts/src/test/kotlin/com/r3corda/contracts/asset/CashTests.kt +++ b/contracts/src/test/kotlin/com/r3corda/contracts/asset/CashTests.kt @@ -39,7 +39,7 @@ class CashTests { } tweak { output { outState } - // No command commanduments + // No command arguments this `fails with` "required com.r3corda.contracts.asset.FungibleAsset.Commands.Move command" } tweak { diff --git a/core/src/main/kotlin/com/r3corda/core/testing/LedgerDSLInterpreter.kt b/core/src/main/kotlin/com/r3corda/core/testing/LedgerDSLInterpreter.kt index 27c24606b4..d41ad3cd60 100644 --- a/core/src/main/kotlin/com/r3corda/core/testing/LedgerDSLInterpreter.kt +++ b/core/src/main/kotlin/com/r3corda/core/testing/LedgerDSLInterpreter.kt @@ -19,7 +19,7 @@ interface LedgerDSLInterpreter> : Output /** * This is the class the top-level primitives deal with. It delegates all other primitives to the contained interpreter. * This way we have a decoupling of the DSL "AST" and the interpretation(s) of it. Note how the delegation forces - * covariance of the TransactionInterpreter parameter + * covariance of the TransactionInterpreter parameter. * * TODO (Kotlin 1.1): Use type synonyms to make the type params less unwieldy */ diff --git a/core/src/main/kotlin/com/r3corda/core/testing/TransactionDSLInterpreter.kt b/core/src/main/kotlin/com/r3corda/core/testing/TransactionDSLInterpreter.kt index d013c923fb..f8421a8326 100644 --- a/core/src/main/kotlin/com/r3corda/core/testing/TransactionDSLInterpreter.kt +++ b/core/src/main/kotlin/com/r3corda/core/testing/TransactionDSLInterpreter.kt @@ -36,7 +36,7 @@ import java.time.Instant * Put convenience functions in [TransactionDSL] instead. There are some cases where the overloads would clash with the * Interpreter interface, in these cases define a "backing" function in the interface instead (e.g. [_command]). * - * This way the responsibility of providing a nice frontend DSL and the implementation(s) are separated + * This way the responsibility of providing a nice frontend DSL and the implementation(s) are separated. */ interface TransactionDSLInterpreter : OutputStateLookup { val ledgerInterpreter: LedgerDSLInterpreter> @@ -56,7 +56,7 @@ class TransactionDSL> (val interpreter: fun input(stateLabel: String) = input(retrieveOutputStateAndRef(ContractState::class.java, stateLabel).ref) /** - * Adds the passed in state as a non-verified transaction output to the ledger and adds that as an input + * Adds the passed in state as a non-verified transaction output to the ledger and adds that as an input. */ fun input(state: ContractState) { val transaction = ledgerInterpreter.unverifiedTransaction(null) { From 6fb7e59b916099419853fef5190df75fb52c374f Mon Sep 17 00:00:00 2001 From: Mike Hearn Date: Mon, 4 Jul 2016 15:34:45 +0100 Subject: [PATCH 088/114] Upgrade dependencies, July edition. --- build.gradle | 17 ++++++++++++----- .../r3corda/contracts/CommercialPaperTests.kt | 10 +++++----- core/build.gradle | 15 +++++++-------- .../com/r3corda/core/serialization/Kryo.kt | 4 ---- node/build.gradle | 16 ++++++++-------- .../com/r3corda/node/utilities/JsonSupport.kt | 10 +++++----- 6 files changed, 37 insertions(+), 35 deletions(-) diff --git a/build.gradle b/build.gradle index 69f11733df..f839d043eb 100644 --- a/build.gradle +++ b/build.gradle @@ -6,6 +6,7 @@ apply plugin: 'kotlin' apply plugin: 'application' apply plugin: 'project-report' apply plugin: QuasarPlugin +apply plugin: 'com.github.ben-manes.versions' allprojects { sourceCompatibility = 1.8 @@ -17,13 +18,16 @@ allprojects { } buildscript { - ext.kotlin_version = '1.0.2' + ext.kotlin_version = '1.0.3' ext.quasar_version = '0.7.5' ext.asm_version = '0.5.3' ext.artemis_version = '1.3.0' - ext.jetty_version = '9.1.1.v20140108' - ext.jersey_version = '2.22.2' + ext.jackson_version = '2.8.0.rc2' + ext.jetty_version = '9.3.9.v20160517' + ext.jersey_version = '2.23.1' ext.jolokia_version = '2.0.0-M1' + ext.slf4j_version = '1.7.21' + ext.assertj_version = '3.5.1' repositories { mavenCentral() @@ -31,6 +35,9 @@ buildscript { } dependencies { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + + // Can run 'gradle dependencyUpdates' to find new versions of things. + classpath 'com.github.ben-manes:gradle-versions-plugin:0.12.0' } } @@ -77,7 +84,7 @@ dependencies { compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" compile "org.jetbrains.kotlin:kotlin-test:$kotlin_version" - compile "org.jetbrains.kotlinx:kotlinx-support-jdk8:0.1" + compile "org.jetbrains.kotlinx:kotlinx-support-jdk8:0.2" // Unit testing helpers. testCompile 'junit:junit:4.12' @@ -86,7 +93,7 @@ dependencies { // Integration test helpers integrationTestCompile 'junit:junit:4.12' - integrationTestCompile 'org.assertj:assertj-core:3.4.1' + integrationTestCompile 'org.assertj:assertj-core:${assertj_version}' } // Package up the demo programs. diff --git a/contracts/src/test/kotlin/com/r3corda/contracts/CommercialPaperTests.kt b/contracts/src/test/kotlin/com/r3corda/contracts/CommercialPaperTests.kt index e7f0fb3083..32ba64de9c 100644 --- a/contracts/src/test/kotlin/com/r3corda/contracts/CommercialPaperTests.kt +++ b/contracts/src/test/kotlin/com/r3corda/contracts/CommercialPaperTests.kt @@ -12,15 +12,15 @@ import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized import java.time.Instant -import java.util.Currency +import java.util.* import kotlin.test.assertFailsWith import kotlin.test.assertTrue interface ICommercialPaperTestTemplate { - open fun getPaper(): ICommercialPaperState - open fun getIssueCommand(): CommandData - open fun getRedeemCommand(): CommandData - open fun getMoveCommand(): CommandData + fun getPaper(): ICommercialPaperState + fun getIssueCommand(): CommandData + fun getRedeemCommand(): CommandData + fun getMoveCommand(): CommandData } class JavaCommercialPaperTest() : ICommercialPaperTestTemplate { diff --git a/core/build.gradle b/core/build.gradle index 84881b6925..1de8918861 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -24,8 +24,7 @@ repositories { dependencies { testCompile 'junit:junit:4.12' - testCompile 'org.assertj:assertj-core:3.4.1' - testCompile "commons-fileupload:commons-fileupload:1.3.1" + testCompile "commons-fileupload:commons-fileupload:1.3.2" // Guava: Google test library (collections test suite) testCompile "com.google.guava:guava-testlib:19.0" @@ -38,27 +37,27 @@ dependencies { compile "com.google.code.findbugs:jsr305:3.0.1" // AssertJ: for fluent assertions for testing - testCompile "org.assertj:assertj-core:3.4.1" + testCompile "org.assertj:assertj-core:${assertj_version}" // SLF4J: Logging framework. - compile "org.slf4j:slf4j-jdk14:1.7.13" + compile "org.slf4j:slf4j-jdk14:${slf4j_version}" // Guava: Google utilities library. compile "com.google.guava:guava:19.0" // RxJava: observable streams of events. - compile "io.reactivex:rxjava:1.0.17" + compile "io.reactivex:rxjava:1.1.6" // Kryo: object graph serialization. - compile "com.esotericsoftware:kryo:3.0.3" - compile "de.javakaffee:kryo-serializers:0.37" + compile "com.esotericsoftware:kryo:4.0.0" + compile "de.javakaffee:kryo-serializers:0.38" // Apache JEXL: An embeddable expression evaluation library. // This may be temporary until we experiment with other ways to do on-the-fly contract specialisation via an API. compile "org.apache.commons:commons-jexl3:3.0" // For JSON - compile "com.fasterxml.jackson.core:jackson-databind:2.5.5" + compile "com.fasterxml.jackson.core:jackson-databind:${jackson_version}" // Java ed25519 implementation. See https://github.com/str4d/ed25519-java/ compile 'net.i2p.crypto:eddsa:0.1.0' diff --git a/core/src/main/kotlin/com/r3corda/core/serialization/Kryo.kt b/core/src/main/kotlin/com/r3corda/core/serialization/Kryo.kt index 2e555156e7..904741d06a 100644 --- a/core/src/main/kotlin/com/r3corda/core/serialization/Kryo.kt +++ b/core/src/main/kotlin/com/r3corda/core/serialization/Kryo.kt @@ -360,10 +360,6 @@ fun createKryo(k: Kryo = Kryo()): Kryo { // This is required to make all the unit tests pass register(Party::class.java) - // Work around a bug in Kryo handling nested generics - register(Issued::class.java, ImmutableClassSerializer(Issued::class)) - register(TransactionState::class.java, ImmutableClassSerializer(TransactionState::class)) - // This ensures a NonEmptySetSerializer is constructed with an initial value. register(NonEmptySet::class.java, NonEmptySetSerializer) diff --git a/node/build.gradle b/node/build.gradle index f9005d9349..f2bf98796b 100644 --- a/node/build.gradle +++ b/node/build.gradle @@ -29,24 +29,24 @@ dependencies { compile project(':contracts') compile "com.google.code.findbugs:jsr305:3.0.1" - compile "org.slf4j:slf4j-jdk14:1.7.13" + compile "org.slf4j:slf4j-jdk14:${slf4j_version}" compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" compile "org.jetbrains.kotlin:kotlin-test:$kotlin_version" - compile "org.jetbrains.kotlinx:kotlinx-support-jdk8:0.1" + compile "org.jetbrains.kotlinx:kotlinx-support-jdk8:0.2" compile "com.google.guava:guava:19.0" // JOpt: for command line flags. - compile "net.sf.jopt-simple:jopt-simple:4.9" + compile "net.sf.jopt-simple:jopt-simple:5.0.2" // Artemis: for reliable p2p message queues. compile "org.apache.activemq:artemis-server:${artemis_version}" compile "org.apache.activemq:artemis-core-client:${artemis_version}" // JAnsi: for drawing things to the terminal in nicely coloured ways. - compile "org.fusesource.jansi:jansi:1.11" + compile "org.fusesource.jansi:jansi:1.13" // GraphStream: For visualisation compile "org.graphstream:gs-core:1.3" @@ -63,7 +63,7 @@ dependencies { compile "org.eclipse.jetty:jetty-webapp:${jetty_version}" compile "javax.servlet:javax.servlet-api:3.1.0" compile "org.jolokia:jolokia-agent-war:2.0.0-M1" - compile "commons-fileupload:commons-fileupload:1.3.1" + compile "commons-fileupload:commons-fileupload:1.3.2" // Jersey for JAX-RS implementation for use in Jetty compile "org.glassfish.jersey.core:jersey-server:${jersey_version}" @@ -76,10 +76,10 @@ dependencies { exclude group: 'com.fasterxml.jackson.core', module: 'jackson-databind' exclude group: 'com.fasterxml.jackson.core', module: 'jackson-core' } - compile ("com.fasterxml.jackson.module:jackson-module-kotlin:2.5.5-2") { + compile ("com.fasterxml.jackson.module:jackson-module-kotlin:${jackson_version}") { exclude group: 'com.fasterxml.jackson.core', module: 'jackson-annotations' } - compile "com.fasterxml.jackson.core:jackson-annotations:2.5.5" + compile "com.fasterxml.jackson.core:jackson-annotations:${jackson_version}" // Coda Hale's Metrics: for monitoring of key statistics compile "io.dropwizard.metrics:metrics-core:3.1.2" @@ -92,7 +92,7 @@ dependencies { // Unit testing helpers. testCompile 'junit:junit:4.12' - testCompile 'org.assertj:assertj-core:3.4.1' + testCompile "org.assertj:assertj-core:${assertj_version}" } quasarScan.dependsOn('classes', ':core:classes', ':contracts:classes') diff --git a/node/src/main/kotlin/com/r3corda/node/utilities/JsonSupport.kt b/node/src/main/kotlin/com/r3corda/node/utilities/JsonSupport.kt index f598f1c17f..3c38165696 100644 --- a/node/src/main/kotlin/com/r3corda/node/utilities/JsonSupport.kt +++ b/node/src/main/kotlin/com/r3corda/node/utilities/JsonSupport.kt @@ -73,7 +73,7 @@ object JsonSupport { return try { LocalDate.parse(parser.text) } catch (e: Exception) { - throw JsonParseException("Invalid LocalDate ${parser.text}: ${e.message}", parser.currentLocation) + throw JsonParseException(parser, "Invalid LocalDate ${parser.text}: ${e.message}") } } } @@ -98,7 +98,7 @@ object JsonSupport { } val mapper = parser.codec as ServiceHubObjectMapper // TODO this needs to use some industry identifier(s) not just these human readable names - return mapper.identities.partyFromName(parser.text) ?: throw JsonParseException("Could not find a Party with name: ${parser.text}", parser.currentLocation) + return mapper.identities.partyFromName(parser.text) ?: throw JsonParseException(parser, "Could not find a Party with name: ${parser.text}") } } @@ -120,7 +120,7 @@ object JsonSupport { @Suppress("UNCHECKED_CAST") return SecureHash.parse(parser.text) as T } catch (e: Exception) { - throw JsonParseException("Invalid hash ${parser.text}: ${e.message}", parser.currentLocation) + throw JsonParseException(parser, "Invalid hash ${parser.text}: ${e.message}") } } } @@ -131,7 +131,7 @@ object JsonSupport { val array = StringArrayDeserializer.instance.deserialize(parser, context) BusinessCalendar.getInstance(*array) } catch (e: Exception) { - throw JsonParseException("Invalid calendar(s) ${parser.text}: ${e.message}", parser.currentLocation) + throw JsonParseException(parser, "Invalid calendar(s) ${parser.text}: ${e.message}") } } } @@ -151,7 +151,7 @@ object JsonSupport { val A = Base58.decode(parser.text) EdDSAPublicKey(EdDSAPublicKeySpec(A, ed25519Curve)) } catch (e: Exception) { - throw JsonParseException("Invalid public key ${parser.text}: ${e.message}", parser.currentLocation) + throw JsonParseException(parser, "Invalid public key ${parser.text}: ${e.message}") } } } From f6e7ffdd31b4d1d90dfe2e976f6fcc0a31bee510 Mon Sep 17 00:00:00 2001 From: Mike Hearn Date: Wed, 6 Jul 2016 14:00:29 +0100 Subject: [PATCH 089/114] Fix a race condition in the MockNode class that only shows up when used in thread-per-node mode. Witnessed in the unit tests. --- .../kotlin/com/r3corda/node/internal/testing/MockNode.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/node/src/main/kotlin/com/r3corda/node/internal/testing/MockNode.kt b/node/src/main/kotlin/com/r3corda/node/internal/testing/MockNode.kt index ea7e7fb279..6245192984 100644 --- a/node/src/main/kotlin/com/r3corda/node/internal/testing/MockNode.kt +++ b/node/src/main/kotlin/com/r3corda/node/internal/testing/MockNode.kt @@ -121,7 +121,11 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false, override val nearestCity: String = "Atlantis" } val node = nodeFactory.create(path, config, this, networkMapAddress, advertisedServices.toSet(), id, keyPair) - if (start) node.setup().start() + if (start) { + node.setup().start() + if (threadPerNode && networkMapAddress != null) + node.networkMapRegistrationFuture.get() // Block and wait for the node to register in the net map. + } _nodes.add(node) return node } From 9e849378cfb8d2e6809b60396a63efe093c0b847 Mon Sep 17 00:00:00 2001 From: Mike Hearn Date: Wed, 6 Jul 2016 14:00:48 +0100 Subject: [PATCH 090/114] Minor: add some assertions in the WalletFiller code after a test was observed to fail due to a negative amount. --- .../main/kotlin/com/r3corda/contracts/testing/WalletFiller.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contracts/src/main/kotlin/com/r3corda/contracts/testing/WalletFiller.kt b/contracts/src/main/kotlin/com/r3corda/contracts/testing/WalletFiller.kt index 2a9bd90fac..456b8dd391 100644 --- a/contracts/src/main/kotlin/com/r3corda/contracts/testing/WalletFiller.kt +++ b/contracts/src/main/kotlin/com/r3corda/contracts/testing/WalletFiller.kt @@ -66,6 +66,7 @@ private fun calculateRandomlySizedAmounts(howMuch: Amount, min: Int, m val numStates = min + Math.floor(rng.nextDouble() * (max - min)).toInt() val amounts = LongArray(numStates) val baseSize = howMuch.quantity / numStates + check(baseSize > 0) { baseSize } var filledSoFar = 0L for (i in 0..numStates - 1) { if (i < numStates - 1) { @@ -76,6 +77,7 @@ private fun calculateRandomlySizedAmounts(howMuch: Amount, min: Int, m // Handle inexact rounding. amounts[i] = howMuch.quantity - filledSoFar } + check(amounts[i] >= 0) { amounts[i] } } check(amounts.sum() == howMuch.quantity) return amounts From 2e3f689fd37f87faf6d5786fe04c58f549f29ae5 Mon Sep 17 00:00:00 2001 From: Mike Hearn Date: Wed, 6 Jul 2016 16:04:10 +0100 Subject: [PATCH 091/114] Minor: fix PublicKey.toShortString after the switch to ed25519 --- .../main/kotlin/com/r3corda/core/crypto/CryptoUtilities.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/main/kotlin/com/r3corda/core/crypto/CryptoUtilities.kt b/core/src/main/kotlin/com/r3corda/core/crypto/CryptoUtilities.kt index 0f81331f5f..11022a2086 100644 --- a/core/src/main/kotlin/com/r3corda/core/crypto/CryptoUtilities.kt +++ b/core/src/main/kotlin/com/r3corda/core/crypto/CryptoUtilities.kt @@ -5,9 +5,9 @@ import com.r3corda.core.serialization.OpaqueBytes import com.r3corda.core.serialization.SerializedBytes import com.r3corda.core.serialization.deserialize import net.i2p.crypto.eddsa.EdDSAEngine +import net.i2p.crypto.eddsa.EdDSAPublicKey import java.math.BigInteger import java.security.* -import java.security.interfaces.ECPublicKey import net.i2p.crypto.eddsa.KeyPairGenerator as EddsaKeyPairGenerator fun newSecureRandom(): SecureRandom { @@ -158,8 +158,8 @@ fun PublicKey.verifyWithECDSA(content: ByteArray, signature: DigitalSignature) { /** Render a public key to a string, using a short form if it's an elliptic curve public key */ fun PublicKey.toStringShort(): String { - return (this as? ECPublicKey)?.let { key -> - "DL" + Base58.encode(key.w.affineX.toByteArray()) // DL -> Distributed Ledger + return (this as? EdDSAPublicKey)?.let { key -> + "DL" + Base58.encode(key.abyte) // DL -> Distributed Ledger } ?: toString() } From bdb34ab26a149bc89f1a3f5ff916977457fe3e7a Mon Sep 17 00:00:00 2001 From: Matthew Nesbit Date: Wed, 6 Jul 2016 13:23:41 +0100 Subject: [PATCH 092/114] Make the IRS Demo web api an api plugin (scanned from the Node classpath) and use the same permission checking entry point for web api's as the scheduler. Fix whitespace Change ProtocolLogicRefFactory to use Map> as whitelist definition --- .../r3corda/core/node/CordaPluginRegistry.kt | 23 +++++++++++ .../com/r3corda/core/node/ServiceHub.kt | 9 ++++ .../core/protocols/ProtocolLogicRef.kt | 20 +++++---- .../ProtocolLogicRefFromJavaTest.java | 38 ++++++++++++++--- .../core/protocols/ProtocolLogicRefTest.kt | 41 ++++++++++++++----- .../com/r3corda/node/internal/AbstractNode.kt | 19 ++++++++- .../kotlin/com/r3corda/node/internal/Node.kt | 19 +++++---- .../node/services/api/ServiceHubInternal.kt | 7 ++++ .../services/clientapi/NodeInterestRates.kt | 11 +++++ .../node/services/NodeSchedulerServiceTest.kt | 2 +- src/main/kotlin/com/r3corda/demos/IRSDemo.kt | 13 +++++- .../kotlin/com/r3corda/demos/RateFixDemo.kt | 3 +- .../r3corda/demos/api/InterestRateSwapAPI.kt | 27 ++++++------ .../demos/protocols/ExitServerProtocol.kt | 7 ++-- .../com.r3corda.core.node.CordaPluginRegistry | 2 + 15 files changed, 186 insertions(+), 55 deletions(-) create mode 100644 core/src/main/kotlin/com/r3corda/core/node/CordaPluginRegistry.kt create mode 100644 src/main/resources/META-INF/services/com.r3corda.core.node.CordaPluginRegistry diff --git a/core/src/main/kotlin/com/r3corda/core/node/CordaPluginRegistry.kt b/core/src/main/kotlin/com/r3corda/core/node/CordaPluginRegistry.kt new file mode 100644 index 0000000000..89492ee373 --- /dev/null +++ b/core/src/main/kotlin/com/r3corda/core/node/CordaPluginRegistry.kt @@ -0,0 +1,23 @@ +package com.r3corda.core.node + +/** + * Implement this interface on a class advertised in a META-INF/services/com.r3corda.core.node.CordaPluginRegistry file + * to extend a Corda node with additional application services. + */ +interface CordaPluginRegistry { + /** + * List of JAX-RS classes inside the contract jar. They are expected to have a single parameter constructor that takes a ServiceHub as input. + * These are listed as Class<*>, because they will be instantiated inside an AttachmentClassLoader so that subsequent protocols, contracts, etc + * will be running in the appropriate isolated context. + */ + val webApis: List> + + /** + * A Map with an entry for each consumed protocol used by the webAPIs. + * The key of each map entry should contain the ProtocolLogic class name. + * The associated map values are the union of all concrete class names passed to the protocol constructor. + * Standard java.lang.* and kotlin.* types do not need to be included explicitly + * This is used to extend the white listed protocols that can be initiated from the ServiceHub invokeProtocolAsync method + */ + val requiredProtocols: Map> +} \ No newline at end of file diff --git a/core/src/main/kotlin/com/r3corda/core/node/ServiceHub.kt b/core/src/main/kotlin/com/r3corda/core/node/ServiceHub.kt index 893f83a868..d1cf7fa0fd 100644 --- a/core/src/main/kotlin/com/r3corda/core/node/ServiceHub.kt +++ b/core/src/main/kotlin/com/r3corda/core/node/ServiceHub.kt @@ -1,8 +1,10 @@ package com.r3corda.core.node +import com.google.common.util.concurrent.ListenableFuture import com.r3corda.core.contracts.* import com.r3corda.core.messaging.MessagingService import com.r3corda.core.node.services.* +import com.r3corda.core.protocols.ProtocolLogic import java.time.Clock /** @@ -61,4 +63,11 @@ interface ServiceHub { val definingTx = storageService.validatedTransactions.getTransaction(stateRef.txhash) ?: throw TransactionResolutionException(stateRef.txhash) return definingTx.tx.outputs[stateRef.index] } + + /** + * Will check [logicType] and [args] against a whitelist and if acceptable then construct and initiate the protocol. + * + * @throws IllegalProtocolLogicException or IllegalArgumentException if there are problems with the [logicType] or [args] + */ + fun invokeProtocolAsync(logicType: Class>, vararg args: Any?): ListenableFuture } \ No newline at end of file diff --git a/core/src/main/kotlin/com/r3corda/core/protocols/ProtocolLogicRef.kt b/core/src/main/kotlin/com/r3corda/core/protocols/ProtocolLogicRef.kt index 2e8bffb531..c63bfeb6cc 100644 --- a/core/src/main/kotlin/com/r3corda/core/protocols/ProtocolLogicRef.kt +++ b/core/src/main/kotlin/com/r3corda/core/protocols/ProtocolLogicRef.kt @@ -25,22 +25,26 @@ import kotlin.reflect.primaryConstructor * TODO: Align with API related logic for passing in ProtocolLogic references (ProtocolRef) * TODO: Actual support for AppContext / AttachmentsClassLoader */ -class ProtocolLogicRefFactory(private val protocolLogicClassNameWhitelist: Set, private val argsClassNameWhitelist: Set) : SingletonSerializeAsToken() { +class ProtocolLogicRefFactory(private val protocolWhitelist: Map>) : SingletonSerializeAsToken() { - constructor() : this(setOf(TwoPartyDealProtocol.FixingRoleDecider::class.java.name), setOf(StateRef::class.java.name, Duration::class.java.name)) + constructor() : this(mapOf(Pair(TwoPartyDealProtocol.FixingRoleDecider::class.java.name, setOf(StateRef::class.java.name, Duration::class.java.name)))) // Pending real dependence on AppContext for class loading etc @Suppress("UNUSED_PARAMETER") private fun validateProtocolClassName(className: String, appContext: AppContext) { // TODO: make this specific to the attachments in the [AppContext] by including [SecureHash] in whitelist check - require(className in protocolLogicClassNameWhitelist) { "${ProtocolLogic::class.java.simpleName} of ${ProtocolLogicRef::class.java.simpleName} must have type on the whitelist: $className" } + require(protocolWhitelist.containsKey(className)) { "${ProtocolLogic::class.java.simpleName} of ${ProtocolLogicRef::class.java.simpleName} must have type on the whitelist: $className" } } // Pending real dependence on AppContext for class loading etc @Suppress("UNUSED_PARAMETER") - private fun validateArgClassName(className: String, appContext: AppContext) { + private fun validateArgClassName(className: String, argClassName: String, appContext: AppContext) { + // Accept standard java.lang.* and kotlin.* types + if (argClassName.startsWith("java.lang.") || argClassName.startsWith("kotlin.")) { + return + } // TODO: make this specific to the attachments in the [AppContext] by including [SecureHash] in whitelist check - require(className in argsClassNameWhitelist) { "Args to ${ProtocolLogicRef::class.java.simpleName} must have types on the args whitelist: $className" } + require(protocolWhitelist[className]!!.contains(argClassName)) { "Args to ${className} must have types on the args whitelist: $argClassName" } } /** @@ -90,14 +94,14 @@ class ProtocolLogicRefFactory(private val protocolLogicClassNameWhitelist: Set>, args: Map): () -> ProtocolLogic<*> { for (constructor in clazz.kotlin.constructors) { - val params = buildParams(appContext, constructor, args) ?: continue + val params = buildParams(appContext, clazz, constructor, args) ?: continue // If we get here then we matched every parameter return { constructor.callBy(params) } } throw IllegalProtocolLogicException(clazz, "as could not find matching constructor for: $args") } - private fun buildParams(appContext: AppContext, constructor: KFunction>, args: Map): HashMap? { + private fun buildParams(appContext: AppContext, clazz: Class>, constructor: KFunction>, args: Map): HashMap? { val params = hashMapOf() val usedKeys = hashSetOf() for (parameter in constructor.parameters) { @@ -111,7 +115,7 @@ class ProtocolLogicRefFactory(private val protocolLogicClassNameWhitelist: Set { - public JavaProtocolLogic(int A, String b) { + public JavaProtocolLogic(ParamType1 A, ParamType2 b) { } @Override @@ -43,13 +63,21 @@ public class ProtocolLogicRefFromJavaTest { @Test public void test() { - ProtocolLogicRefFactory factory = new ProtocolLogicRefFactory(Sets.newHashSet(JavaProtocolLogic.class.getName()), Sets.newHashSet(Integer.class.getName(), String.class.getName())); - factory.create(JavaProtocolLogic.class, 1, "Hello Jack"); + Map> whiteList = new HashMap<>(); + Set argsList = new HashSet<>(); + argsList.add(ParamType1.class.getName()); + argsList.add(ParamType2.class.getName()); + whiteList.put(JavaProtocolLogic.class.getName(), argsList); + ProtocolLogicRefFactory factory = new ProtocolLogicRefFactory(whiteList); + factory.create(JavaProtocolLogic.class, new ParamType1(1), new ParamType2("Hello Jack")); } @Test public void testNoArg() { - ProtocolLogicRefFactory factory = new ProtocolLogicRefFactory(Sets.newHashSet(JavaNoArgProtocolLogic.class.getName()), Sets.newHashSet(Integer.class.getName(), String.class.getName())); + Map> whiteList = new HashMap<>(); + Set argsList = new HashSet<>(); + whiteList.put(JavaNoArgProtocolLogic.class.getName(), argsList); + ProtocolLogicRefFactory factory = new ProtocolLogicRefFactory(whiteList); factory.create(JavaNoArgProtocolLogic.class); } } diff --git a/core/src/test/kotlin/com/r3corda/core/protocols/ProtocolLogicRefTest.kt b/core/src/test/kotlin/com/r3corda/core/protocols/ProtocolLogicRefTest.kt index bcede610b1..aa5651f12d 100644 --- a/core/src/test/kotlin/com/r3corda/core/protocols/ProtocolLogicRefTest.kt +++ b/core/src/test/kotlin/com/r3corda/core/protocols/ProtocolLogicRefTest.kt @@ -1,6 +1,5 @@ package com.r3corda.core.protocols -import com.google.common.collect.Sets import com.r3corda.core.days import org.junit.Before import org.junit.Test @@ -8,13 +7,20 @@ import java.time.Duration class ProtocolLogicRefTest { + data class ParamType1(val value: Int) + data class ParamType2(val value: String) + @Suppress("UNUSED_PARAMETER") // We will never use A or b - class KotlinProtocolLogic(A: Int, b: String) : ProtocolLogic() { - constructor() : this(1, "2") + class KotlinProtocolLogic(A: ParamType1, b: ParamType2) : ProtocolLogic() { + constructor() : this(ParamType1(1), ParamType2("2")) - constructor(C: String) : this(1, C) + constructor(C: ParamType2) : this(ParamType1(1), C) - constructor(illegal: Duration) : this(1, illegal.toString()) + constructor(illegal: Duration) : this(ParamType1(1), ParamType2(illegal.toString())) + + constructor(primitive: String) : this(ParamType1(1), ParamType2(primitive)) + + constructor(kotlinType: Int) : this(ParamType1(kotlinType), ParamType2("b")) override fun call(): Unit { } @@ -40,8 +46,8 @@ class ProtocolLogicRefTest { @Before fun setup() { // We have to allow Java boxed primitives but Kotlin warns we shouldn't be using them - factory = ProtocolLogicRefFactory(Sets.newHashSet(KotlinProtocolLogic::class.java.name, KotlinNoArgProtocolLogic::class.java.name), - Sets.newHashSet(@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") Integer::class.java.name, String::class.java.name)) + factory = ProtocolLogicRefFactory(mapOf(Pair(KotlinProtocolLogic::class.java.name, setOf(ParamType1::class.java.name, ParamType2::class.java.name)), + Pair(KotlinNoArgProtocolLogic::class.java.name, setOf()))) } @Test @@ -51,18 +57,18 @@ class ProtocolLogicRefTest { @Test fun testCreateKotlin() { - val args = mapOf(Pair("A", 1), Pair("b", "Hello Jack")) + val args = mapOf(Pair("A", ParamType1(1)), Pair("b", ParamType2("Hello Jack"))) factory.createKotlin(KotlinProtocolLogic::class.java, args) } @Test fun testCreatePrimary() { - factory.create(KotlinProtocolLogic::class.java, 1, "Hello Jack") + factory.create(KotlinProtocolLogic::class.java, ParamType1(1), ParamType2("Hello Jack")) } @Test(expected = IllegalArgumentException::class) fun testCreateNotWhiteListed() { - factory.create(NotWhiteListedKotlinProtocolLogic::class.java, 1, "Hello Jack") + factory.create(NotWhiteListedKotlinProtocolLogic::class.java, ParamType1(1), ParamType2("Hello Jack")) } @Test @@ -72,7 +78,7 @@ class ProtocolLogicRefTest { @Test fun testCreateKotlinNonPrimary() { - val args = mapOf(Pair("C", "Hello Jack")) + val args = mapOf(Pair("C", ParamType2("Hello Jack"))) factory.createKotlin(KotlinProtocolLogic::class.java, args) } @@ -81,4 +87,17 @@ class ProtocolLogicRefTest { val args = mapOf(Pair("illegal", 1.days)) factory.createKotlin(KotlinProtocolLogic::class.java, args) } + + @Test + fun testCreateJavaPrimitiveNoRegistrationRequired() { + val args = mapOf(Pair("primitive", "A string")) + factory.createKotlin(KotlinProtocolLogic::class.java, args) + } + + @Test + fun testCreateKotlinPrimitiveNoRegistrationRequired() { + val args = mapOf(Pair("kotlinType", 3)) + factory.createKotlin(KotlinProtocolLogic::class.java, args) + } + } diff --git a/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt index 7838807b5a..797344945c 100644 --- a/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt @@ -9,6 +9,7 @@ import com.r3corda.core.crypto.Party import com.r3corda.core.messaging.MessagingService import com.r3corda.core.messaging.runOnNextMessage import com.r3corda.core.node.CityDatabase +import com.r3corda.core.node.CordaPluginRegistry import com.r3corda.core.node.NodeInfo import com.r3corda.core.node.PhysicalLocation import com.r3corda.core.node.services.* @@ -97,7 +98,7 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration, // Internal only override val monitoringService: MonitoringService = MonitoringService(MetricRegistry()) - override val protocolLogicRefFactory = ProtocolLogicRefFactory() + override val protocolLogicRefFactory: ProtocolLogicRefFactory get() = protocolLogicFactory override fun startProtocol(loggerName: String, logic: ProtocolLogic): ListenableFuture { return smm.add(loggerName, logic) @@ -124,6 +125,7 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration, lateinit var net: MessagingService lateinit var api: APIServer lateinit var scheduler: SchedulerService + lateinit var protocolLogicFactory: ProtocolLogicRefFactory var isPreviousCheckpointsPresent = false private set @@ -158,6 +160,8 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration, checkpointStorage, serverThread) + protocolLogicFactory = initialiseProtocolLogicFactory() + // This object doesn't need to be referenced from this class because it registers handlers on the network // service and so that keeps it from being collected. DataVendingService(net, storage, services.networkMapCache) @@ -180,6 +184,19 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration, return this } + private fun initialiseProtocolLogicFactory(): ProtocolLogicRefFactory { + val serviceLoader = ServiceLoader.load(CordaPluginRegistry::class.java) + val pluginRegistries = serviceLoader.toList() + val protocolWhitelist = HashMap>() + for (plugin in pluginRegistries) { + for (protocol in plugin.requiredProtocols) { + protocolWhitelist.merge(protocol.key, protocol.value, { x, y -> x + y }) + } + } + + return ProtocolLogicRefFactory(protocolWhitelist) + } + /** * Run any tasks that are needed to ensure the node is in a correct state before running start() */ diff --git a/node/src/main/kotlin/com/r3corda/node/internal/Node.kt b/node/src/main/kotlin/com/r3corda/node/internal/Node.kt index 85cfac29a3..98e7a72745 100644 --- a/node/src/main/kotlin/com/r3corda/node/internal/Node.kt +++ b/node/src/main/kotlin/com/r3corda/node/internal/Node.kt @@ -3,10 +3,11 @@ package com.r3corda.node.internal import com.codahale.metrics.JmxReporter import com.google.common.net.HostAndPort import com.r3corda.core.messaging.MessagingService +import com.r3corda.core.node.CordaPluginRegistry import com.r3corda.core.node.NodeInfo +import com.r3corda.core.node.ServiceHub import com.r3corda.core.node.services.ServiceType import com.r3corda.core.utilities.loggerFor -import com.r3corda.node.api.APIServer import com.r3corda.node.serialization.NodeClock import com.r3corda.node.services.config.NodeConfiguration import com.r3corda.node.services.messaging.ArtemisMessagingService @@ -27,9 +28,9 @@ import java.io.RandomAccessFile import java.lang.management.ManagementFactory import java.net.InetSocketAddress import java.nio.channels.FileLock -import java.nio.file.Files import java.nio.file.Path import java.time.Clock +import java.util.* import javax.management.ObjectName class ConfigurationException(message: String) : Exception(message) @@ -55,8 +56,7 @@ class ConfigurationException(message: String) : Exception(message) */ class Node(dir: Path, val p2pAddr: HostAndPort, val webServerAddr: HostAndPort, configuration: NodeConfiguration, networkMapAddress: NodeInfo?, advertisedServices: Set, - clock: Clock = NodeClock(), - val clientAPIs: List> = listOf()) : AbstractNode(dir, configuration, networkMapAddress, advertisedServices, clock) { + clock: Clock = NodeClock()) : AbstractNode(dir, configuration, networkMapAddress, advertisedServices, clock) { companion object { /** The port that is used by default if none is specified. As you know, 31337 is the most elite number. */ val DEFAULT_PORT = 31337 @@ -109,12 +109,15 @@ class Node(dir: Path, val p2pAddr: HostAndPort, val webServerAddr: HostAndPort, resourceConfig.register(ResponseFilter()) resourceConfig.register(api) - for(customAPIClass in clientAPIs) { - val customAPI = customAPIClass.getConstructor(APIServer::class.java).newInstance(api) + val serviceLoader = ServiceLoader.load(CordaPluginRegistry::class.java) + val pluginRegistries = serviceLoader.toList() + val webAPIsOnClasspath = pluginRegistries.flatMap { x -> x.webApis } + for (webapi in webAPIsOnClasspath) { + log.info("Add Plugin web API from attachment ${webapi.name}") + val customAPI = webapi.getConstructor(ServiceHub::class.java).newInstance(services) resourceConfig.register(customAPI) } - // 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")) @@ -187,5 +190,5 @@ class Node(dir: Path, val p2pAddr: HostAndPort, val webServerAddr: HostAndPort, val ourProcessID: String = ManagementFactory.getRuntimeMXBean().name.split("@")[0] f.setLength(0) f.write(ourProcessID.toByteArray()) - } + } } diff --git a/node/src/main/kotlin/com/r3corda/node/services/api/ServiceHubInternal.kt b/node/src/main/kotlin/com/r3corda/node/services/api/ServiceHubInternal.kt index e206a28644..d60c20ab67 100644 --- a/node/src/main/kotlin/com/r3corda/node/services/api/ServiceHubInternal.kt +++ b/node/src/main/kotlin/com/r3corda/node/services/api/ServiceHubInternal.kt @@ -29,4 +29,11 @@ abstract class ServiceHubInternal : ServiceHub { * itself, at which point this method would not be needed (by the scheduler) */ abstract fun startProtocol(loggerName: String, logic: ProtocolLogic): ListenableFuture + + override fun invokeProtocolAsync(logicType: Class>, vararg args: Any?): ListenableFuture { + val logicRef = protocolLogicRefFactory.create(logicType, *args) + @Suppress("UNCHECKED_CAST") + val logic = protocolLogicRefFactory.toProtocolLogic(logicRef) as ProtocolLogic + return startProtocol(logicType.simpleName, logic) + } } \ No newline at end of file diff --git a/node/src/main/kotlin/com/r3corda/node/services/clientapi/NodeInterestRates.kt b/node/src/main/kotlin/com/r3corda/node/services/clientapi/NodeInterestRates.kt index 94d4c9dbeb..dbd3182ab7 100644 --- a/node/src/main/kotlin/com/r3corda/node/services/clientapi/NodeInterestRates.kt +++ b/node/src/main/kotlin/com/r3corda/node/services/clientapi/NodeInterestRates.kt @@ -9,6 +9,7 @@ import com.r3corda.core.crypto.signWithECDSA import com.r3corda.core.math.CubicSplineInterpolator import com.r3corda.core.math.Interpolator import com.r3corda.core.math.InterpolatorFactory +import com.r3corda.core.node.CordaPluginRegistry import com.r3corda.core.node.services.ServiceType import com.r3corda.core.protocols.ProtocolLogic import com.r3corda.core.utilities.ProgressTracker @@ -23,6 +24,7 @@ import java.io.InputStream import java.math.BigDecimal import java.security.KeyPair import java.time.Clock +import java.time.Duration import java.time.Instant import java.time.LocalDate import java.util.* @@ -93,6 +95,15 @@ object NodeInterestRates { } } + /** + * Register the protocol that is used with the Fixing integration tests + */ + class FixingServicePlugin : CordaPluginRegistry { + override val webApis: List> = emptyList() + override val requiredProtocols: Map> = mapOf(Pair(TwoPartyDealProtocol.FixingRoleDecider::class.java.name, setOf(Duration::class.java.name, StateRef::class.java.name))) + + } + // File upload support override val dataTypePrefix = "interest-rates" override val acceptableFileExtensions = listOf(".rates", ".txt") diff --git a/node/src/test/kotlin/com/r3corda/node/services/NodeSchedulerServiceTest.kt b/node/src/test/kotlin/com/r3corda/node/services/NodeSchedulerServiceTest.kt index 566d2aff3f..c2f20ec8b3 100644 --- a/node/src/test/kotlin/com/r3corda/node/services/NodeSchedulerServiceTest.kt +++ b/node/src/test/kotlin/com/r3corda/node/services/NodeSchedulerServiceTest.kt @@ -43,7 +43,7 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() { // We have to allow Java boxed primitives but Kotlin warns we shouldn't be using them @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") - val factory = ProtocolLogicRefFactory(setOf(TestProtocolLogic::class.java.name), setOf(NodeSchedulerServiceTest::class.java.name, Integer::class.java.name)) + val factory = ProtocolLogicRefFactory(mapOf(Pair(TestProtocolLogic::class.java.name, setOf(NodeSchedulerServiceTest::class.java.name, Integer::class.java.name)))) val scheduler: NodeSchedulerService val services: ServiceHub diff --git a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt index c2a60d4609..d3824c39e0 100644 --- a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt @@ -1,9 +1,11 @@ package com.r3corda.demos import com.google.common.net.HostAndPort +import com.r3corda.contracts.InterestRateSwap import com.r3corda.core.crypto.Party import com.r3corda.core.logElapsedTime import com.r3corda.core.messaging.SingleMessageRecipient +import com.r3corda.core.node.CordaPluginRegistry import com.r3corda.core.node.NodeInfo import com.r3corda.core.node.services.ServiceType import com.r3corda.core.serialization.deserialize @@ -241,6 +243,14 @@ object CliParamsSpec { val nonOptions = parser.nonOptions() } +class IRSDemoPluginRegistry : CordaPluginRegistry { + override val webApis: List> = listOf(InterestRateSwapAPI::class.java) + override val requiredProtocols: Map> = mapOf( + Pair(AutoOfferProtocol.Requester::class.java.name, setOf(InterestRateSwap.State::class.java.name)), + Pair(UpdateBusinessDayProtocol.Broadcast::class.java.name, setOf(java.time.LocalDate::class.java.name)), + Pair(ExitServerProtocol.Broadcast::class.java.name, setOf(kotlin.Int::class.java.name))) +} + private class NotSetupException: Throwable { constructor(message: String): super(message) {} } @@ -374,8 +384,7 @@ private fun startNode(params: CliParams.RunNode, networkMap: SingleMessageRecipi } val node = logElapsedTime("Node startup") { - Node(params.dir, params.networkAddress, params.apiAddress, config, networkMapId, advertisedServices, DemoClock(), - listOf(InterestRateSwapAPI::class.java)).start() + Node(params.dir, params.networkAddress, params.apiAddress, config, networkMapId, advertisedServices, DemoClock()).start() } // TODO: This should all be replaced by the identity service being updated diff --git a/src/main/kotlin/com/r3corda/demos/RateFixDemo.kt b/src/main/kotlin/com/r3corda/demos/RateFixDemo.kt index 96473b033c..1374c58dd4 100644 --- a/src/main/kotlin/com/r3corda/demos/RateFixDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/RateFixDemo.kt @@ -76,8 +76,7 @@ fun main(args: Array) { val apiAddr = HostAndPort.fromParts(myNetAddr.hostText, myNetAddr.port + 1) val node = logElapsedTime("Node startup") { Node(dir, myNetAddr, apiAddr, config, networkMapAddress, - advertisedServices, DemoClock(), - listOf(InterestRateSwapAPI::class.java)).setup().start() } + advertisedServices, DemoClock()).setup().start() } val notary = node.services.networkMapCache.notaryNodes[0] diff --git a/src/main/kotlin/com/r3corda/demos/api/InterestRateSwapAPI.kt b/src/main/kotlin/com/r3corda/demos/api/InterestRateSwapAPI.kt index 9197216da7..c5e3574360 100644 --- a/src/main/kotlin/com/r3corda/demos/api/InterestRateSwapAPI.kt +++ b/src/main/kotlin/com/r3corda/demos/api/InterestRateSwapAPI.kt @@ -1,15 +1,16 @@ package com.r3corda.demos.api import com.r3corda.contracts.InterestRateSwap +import com.r3corda.core.contracts.SignedTransaction +import com.r3corda.core.node.ServiceHub +import com.r3corda.core.node.services.linearHeadsOfType import com.r3corda.core.utilities.loggerFor import com.r3corda.demos.protocols.AutoOfferProtocol import com.r3corda.demos.protocols.ExitServerProtocol import com.r3corda.demos.protocols.UpdateBusinessDayProtocol -import com.r3corda.node.api.APIServer -import com.r3corda.node.api.ProtocolClassRef -import com.r3corda.node.api.StatesQuery import java.net.URI import java.time.LocalDate +import java.time.LocalDateTime import javax.ws.rs.* import javax.ws.rs.core.MediaType import javax.ws.rs.core.Response @@ -35,23 +36,23 @@ import javax.ws.rs.core.Response * or if the demodate or population of deals should be reset (will only work while persistence is disabled). */ @Path("irs") -class InterestRateSwapAPI(val api: APIServer) { +class InterestRateSwapAPI(val services: ServiceHub) { private val logger = loggerFor() private fun generateDealLink(deal: InterestRateSwap.State) = "/api/irs/deals/" + deal.common.tradeID private fun getDealByRef(ref: String): InterestRateSwap.State? { - val states = api.queryStates(StatesQuery.selectDeal(ref)) + val states = services.walletService.linearHeadsOfType().filterValues { it.state.data.ref == ref } return if (states.isEmpty()) null else { - val deals = api.fetchStates(states).values.map { it?.data as InterestRateSwap.State }.filterNotNull() + val deals = states.values.map { it.state.data } return if (deals.isEmpty()) null else deals[0] } } private fun getAllDeals(): Array { - val states = api.queryStates(StatesQuery.selectAllDeals()) - val swaps = api.fetchStates(states).values.map { it?.data as InterestRateSwap.State }.filterNotNull().toTypedArray() + val states = services.walletService.linearHeadsOfType() + val swaps = states.values.map { it.state.data }.toTypedArray() return swaps } @@ -64,7 +65,7 @@ class InterestRateSwapAPI(val api: APIServer) { @Path("deals") @Consumes(MediaType.APPLICATION_JSON) fun storeDeal(newDeal: InterestRateSwap.State): Response { - api.invokeProtocolSync(ProtocolClassRef(AutoOfferProtocol.Requester::class.java.name!!), mapOf("dealToBeOffered" to newDeal)) + services.invokeProtocolAsync(AutoOfferProtocol.Requester::class.java, newDeal).get() return Response.created(URI.create(generateDealLink(newDeal))).build() } @@ -84,10 +85,10 @@ class InterestRateSwapAPI(val api: APIServer) { @Path("demodate") @Consumes(MediaType.APPLICATION_JSON) fun storeDemoDate(newDemoDate: LocalDate): Response { - val priorDemoDate = api.serverTime().toLocalDate() + val priorDemoDate = fetchDemoDate() // Can only move date forwards if (newDemoDate.isAfter(priorDemoDate)) { - api.invokeProtocolSync(ProtocolClassRef(UpdateBusinessDayProtocol.Broadcast::class.java.name!!), mapOf("date" to newDemoDate)) + services.invokeProtocolAsync(UpdateBusinessDayProtocol.Broadcast::class.java, newDemoDate).get() return Response.ok().build() } val msg = "demodate is already $priorDemoDate and can only be updated with a later date" @@ -99,14 +100,14 @@ class InterestRateSwapAPI(val api: APIServer) { @Path("demodate") @Produces(MediaType.APPLICATION_JSON) fun fetchDemoDate(): LocalDate { - return api.serverTime().toLocalDate() + return LocalDateTime.now(services.clock).toLocalDate() } @PUT @Path("restart") @Consumes(MediaType.APPLICATION_JSON) fun exitServer(): Response { - api.invokeProtocolSync(ProtocolClassRef(ExitServerProtocol.Broadcast::class.java.name!!), mapOf("exitCode" to 83)) + services.invokeProtocolAsync(ExitServerProtocol.Broadcast::class.java, 83).get() return Response.ok().build() } } diff --git a/src/main/kotlin/com/r3corda/demos/protocols/ExitServerProtocol.kt b/src/main/kotlin/com/r3corda/demos/protocols/ExitServerProtocol.kt index 007aebd7e2..9b5ff0799c 100644 --- a/src/main/kotlin/com/r3corda/demos/protocols/ExitServerProtocol.kt +++ b/src/main/kotlin/com/r3corda/demos/protocols/ExitServerProtocol.kt @@ -37,22 +37,21 @@ object ExitServerProtocol { * This takes a Java Integer rather than Kotlin Int as that is what we end up with in the calling map and currently * we do not support coercing numeric types in the reflective search for matching constructors */ - class Broadcast(@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") val exitCode: Integer) : ProtocolLogic() { + class Broadcast(@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") val exitCode: Int) : ProtocolLogic() { override val topic: String get() = TOPIC @Suspendable override fun call(): Boolean { if (enabled) { - val rc = exitCode.toInt() - val message = ExitMessage(rc) + val message = ExitMessage(exitCode) for (recipient in serviceHub.networkMapCache.partyNodes) { doNextRecipient(recipient, message) } // Sleep a little in case any async message delivery to other nodes needs to happen Strand.sleep(1, TimeUnit.SECONDS) - System.exit(rc) + System.exit(exitCode) } return enabled } diff --git a/src/main/resources/META-INF/services/com.r3corda.core.node.CordaPluginRegistry b/src/main/resources/META-INF/services/com.r3corda.core.node.CordaPluginRegistry new file mode 100644 index 0000000000..279300f9f9 --- /dev/null +++ b/src/main/resources/META-INF/services/com.r3corda.core.node.CordaPluginRegistry @@ -0,0 +1,2 @@ +# Register a ServiceLoader service extending from com.r3corda.node.CordaPluginRegistry +com.r3corda.demos.IRSDemoPluginRegistry \ No newline at end of file From 8dc6f760bbbac76f2a9b83b17b243066ac3d6116 Mon Sep 17 00:00:00 2001 From: Matthew Nesbit Date: Thu, 7 Jul 2016 12:08:53 +0100 Subject: [PATCH 093/114] Add missing import --- .../com/r3corda/node/services/clientapi/NodeInterestRates.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/node/src/main/kotlin/com/r3corda/node/services/clientapi/NodeInterestRates.kt b/node/src/main/kotlin/com/r3corda/node/services/clientapi/NodeInterestRates.kt index dbd3182ab7..d69dd39e2a 100644 --- a/node/src/main/kotlin/com/r3corda/node/services/clientapi/NodeInterestRates.kt +++ b/node/src/main/kotlin/com/r3corda/node/services/clientapi/NodeInterestRates.kt @@ -19,6 +19,7 @@ import com.r3corda.node.services.api.AcceptsFileUpload import com.r3corda.node.utilities.FiberBox import com.r3corda.protocols.RatesFixProtocol import com.r3corda.protocols.ServiceRequestMessage +import com.r3corda.protocols.TwoPartyDealProtocol import org.slf4j.LoggerFactory import java.io.InputStream import java.math.BigDecimal From 92aeb74c19d0edafdb699c5d74d893397fc2b283 Mon Sep 17 00:00:00 2001 From: Matthew Nesbit Date: Thu, 7 Jul 2016 12:17:06 +0100 Subject: [PATCH 094/114] Make the IRS Demo web api an api plugin (scanned from the Node classpath) and use the same permission checking entry point for web api's as the scheduler. --- .../META-INF/services/com.r3corda.core.node.CordaPluginRegistry | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 node/src/main/resources/META-INF/services/com.r3corda.core.node.CordaPluginRegistry diff --git a/node/src/main/resources/META-INF/services/com.r3corda.core.node.CordaPluginRegistry b/node/src/main/resources/META-INF/services/com.r3corda.core.node.CordaPluginRegistry new file mode 100644 index 0000000000..6c27482af8 --- /dev/null +++ b/node/src/main/resources/META-INF/services/com.r3corda.core.node.CordaPluginRegistry @@ -0,0 +1,2 @@ +# Register a ServiceLoader service extending from com.r3corda.node.CordaPluginRegistry +com.r3corda.node.services.clientapi.NodeInterestRates$Service$FixingServicePlugin \ No newline at end of file From 0157018901ade55db0275feaab33db1f311cd483 Mon Sep 17 00:00:00 2001 From: Matthew Nesbit Date: Thu, 7 Jul 2016 13:55:15 +0100 Subject: [PATCH 095/114] Make ServiceLoader results for CordaPlugins a protected property on the AbstractNode --- .../main/kotlin/com/r3corda/node/internal/AbstractNode.kt | 7 +++++-- node/src/main/kotlin/com/r3corda/node/internal/Node.kt | 2 -- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt index 797344945c..aafd6fc5da 100644 --- a/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt @@ -134,6 +134,10 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration, val networkMapRegistrationFuture: ListenableFuture get() = _networkMapRegistrationFuture + /** fetch CordaPluginRegistry classes registered in META-INF/services/com.r3corda.core.node.CordaPluginRegistry files that exist in the classpath */ + protected val pluginRegistries: List + get() = ServiceLoader.load(CordaPluginRegistry::class.java).toList() + /** Set to true once [start] has been successfully called. */ @Volatile var started = false private set @@ -185,8 +189,6 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration, } private fun initialiseProtocolLogicFactory(): ProtocolLogicRefFactory { - val serviceLoader = ServiceLoader.load(CordaPluginRegistry::class.java) - val pluginRegistries = serviceLoader.toList() val protocolWhitelist = HashMap>() for (plugin in pluginRegistries) { for (protocol in plugin.requiredProtocols) { @@ -197,6 +199,7 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration, return ProtocolLogicRefFactory(protocolWhitelist) } + /** * Run any tasks that are needed to ensure the node is in a correct state before running start() */ diff --git a/node/src/main/kotlin/com/r3corda/node/internal/Node.kt b/node/src/main/kotlin/com/r3corda/node/internal/Node.kt index 98e7a72745..1c5c167b76 100644 --- a/node/src/main/kotlin/com/r3corda/node/internal/Node.kt +++ b/node/src/main/kotlin/com/r3corda/node/internal/Node.kt @@ -109,8 +109,6 @@ class Node(dir: Path, val p2pAddr: HostAndPort, val webServerAddr: HostAndPort, resourceConfig.register(ResponseFilter()) resourceConfig.register(api) - val serviceLoader = ServiceLoader.load(CordaPluginRegistry::class.java) - val pluginRegistries = serviceLoader.toList() val webAPIsOnClasspath = pluginRegistries.flatMap { x -> x.webApis } for (webapi in webAPIsOnClasspath) { log.info("Add Plugin web API from attachment ${webapi.name}") From ad3e9be1c80d9d6f2b675cac6e7d98ea64fea8c9 Mon Sep 17 00:00:00 2001 From: Mike Hearn Date: Wed, 6 Jul 2016 17:54:46 +0100 Subject: [PATCH 096/114] Add a version number to gradle and allow "gradle install" to install the core module to the local Maven repository. --- build.gradle | 8 ++++++-- core/build.gradle | 5 ++--- docs/source/release-process.rst | 8 +++++--- node/build.gradle | 3 --- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/build.gradle b/build.gradle index 39d87a3993..2d258f4d8a 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,4 @@ -group 'com.r3cev.prototyping' -version '1.0-SNAPSHOT' +group 'com.r3corda' apply plugin: 'java' apply plugin: 'kotlin' @@ -41,6 +40,11 @@ buildscript { } } +allprojects { + // Our version: bump this on release. + group 'com.r3corda' + version '0.2-SNAPSHOT' +} repositories { mavenLocal() diff --git a/core/build.gradle b/core/build.gradle index 1de8918861..33e81bafc6 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -1,9 +1,8 @@ -group 'com.r3cev.prototyping' -version '1.0-SNAPSHOT' - apply plugin: 'java' apply plugin: 'kotlin' apply plugin: QuasarPlugin +// Applying the maven plugin means this will get installed locally when running "gradle install" +apply plugin: 'maven' buildscript { repositories { diff --git a/docs/source/release-process.rst b/docs/source/release-process.rst index 7116ba0b09..5cdf4201c9 100644 --- a/docs/source/release-process.rst +++ b/docs/source/release-process.rst @@ -33,10 +33,12 @@ Steps to cut a release create one, bug them to do so a day or two before the release. 4. Regenerate the docsite if necessary and commit. 5. Create a branch with a name like `release-M0` where 0 is replaced by the number of the milestone. -6. Tag that branch with a tag like `release-M0.0` -7. Push the branch and the tag to git. -8. Write up a short announcement containing the summary of new features, changes, and API breaks. Send it to the +6. Adjust the version in the root build.gradle file to take out the -SNAPSHOT and commit it on the branch. +7. Tag the branch with a tag like `release-M0.0` +8. Push the branch and the tag to git. +9. Write up a short announcement containing the summary of new features, changes, and API breaks. Send it to the r3dlg-awg mailing list. +10. On master, adjust the version number in the root build.gradle file upwards. If there are serious bugs found in the release, backport the fix to the branch and then tag it with e.g. `release-M0.1` Minor changes to the branch don't have to be announced unless it'd be critical to get all developers updated. \ No newline at end of file diff --git a/node/build.gradle b/node/build.gradle index f2bf98796b..8a289161b5 100644 --- a/node/build.gradle +++ b/node/build.gradle @@ -1,6 +1,3 @@ -group 'com.r3cev.prototyping' -version '1.0-SNAPSHOT' - apply plugin: 'java' apply plugin: 'kotlin' apply plugin: QuasarPlugin From db131eb2c0301912241f0d3f79f77a9619c9947c Mon Sep 17 00:00:00 2001 From: Matthew Nesbit Date: Thu, 7 Jul 2016 14:03:08 +0100 Subject: [PATCH 097/114] Remove @Suppress now we use standard Kotlin Int --- .../kotlin/com/r3corda/demos/protocols/ExitServerProtocol.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/com/r3corda/demos/protocols/ExitServerProtocol.kt b/src/main/kotlin/com/r3corda/demos/protocols/ExitServerProtocol.kt index 9b5ff0799c..5258e3dead 100644 --- a/src/main/kotlin/com/r3corda/demos/protocols/ExitServerProtocol.kt +++ b/src/main/kotlin/com/r3corda/demos/protocols/ExitServerProtocol.kt @@ -37,7 +37,7 @@ object ExitServerProtocol { * This takes a Java Integer rather than Kotlin Int as that is what we end up with in the calling map and currently * we do not support coercing numeric types in the reflective search for matching constructors */ - class Broadcast(@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") val exitCode: Int) : ProtocolLogic() { + class Broadcast(val exitCode: Int) : ProtocolLogic() { override val topic: String get() = TOPIC From fb93b86d6be99246fe8b705a0bdf518dac8f1150 Mon Sep 17 00:00:00 2001 From: Andrius Dagys Date: Thu, 7 Jul 2016 15:51:47 +0100 Subject: [PATCH 098/114] Move test class into correct package --- .../kotlin/{ => com/r3corda}/node/services/NotaryChangeTests.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename node/src/test/kotlin/{ => com/r3corda}/node/services/NotaryChangeTests.kt (99%) diff --git a/node/src/test/kotlin/node/services/NotaryChangeTests.kt b/node/src/test/kotlin/com/r3corda/node/services/NotaryChangeTests.kt similarity index 99% rename from node/src/test/kotlin/node/services/NotaryChangeTests.kt rename to node/src/test/kotlin/com/r3corda/node/services/NotaryChangeTests.kt index d81c674800..a24501caa4 100644 --- a/node/src/test/kotlin/node/services/NotaryChangeTests.kt +++ b/node/src/test/kotlin/com/r3corda/node/services/NotaryChangeTests.kt @@ -1,4 +1,4 @@ -package node.services +package com.r3corda.node.services import com.r3corda.core.crypto.Party import com.r3corda.core.crypto.generateKeyPair From 6381b5e6a1a3cc77fab8486c336497f265ed7560 Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Mon, 13 Jun 2016 18:33:53 +0100 Subject: [PATCH 099/114] Added OkHttp and used it to clean up the HTTP calls in the demo and then moved those new functions to a util lib. --- build.gradle | 1 + src/main/kotlin/com/r3corda/demos/IRSDemo.kt | 73 +------------------ .../com/r3corda/demos/utilities/HttpUtils.kt | 39 ++++++++++ 3 files changed, 42 insertions(+), 71 deletions(-) create mode 100644 src/main/kotlin/com/r3corda/demos/utilities/HttpUtils.kt diff --git a/build.gradle b/build.gradle index 39d87a3993..e2a00d8296 100644 --- a/build.gradle +++ b/build.gradle @@ -85,6 +85,7 @@ dependencies { compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" compile "org.jetbrains.kotlin:kotlin-test:$kotlin_version" compile "org.jetbrains.kotlinx:kotlinx-support-jdk8:0.2" + compile 'com.squareup.okhttp3:okhttp:3.3.1' // Unit testing helpers. testCompile 'junit:junit:4.12' diff --git a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt index c2a60d4609..1a91e48dd9 100644 --- a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt @@ -37,6 +37,8 @@ import java.nio.file.Paths import java.util.* import kotlin.concurrent.fixedRateTimer import kotlin.system.exitProcess +import org.apache.commons.io.IOUtils +import com.r3corda.demos.utilities.* // IRS DEMO // @@ -421,77 +423,6 @@ private fun runUploadRates(host: HostAndPort) { }) } -// Todo: Use a simpler library function for this and handle timeout exceptions -private fun sendJson(url: URL, data: String, method: String) : Boolean { - val connection = url.openConnection() as HttpURLConnection - connection.doOutput = true - connection.useCaches = false - connection.requestMethod = method - connection.connectTimeout = 5000 - connection.readTimeout = 60000 - connection.setRequestProperty("Connection", "Keep-Alive") - connection.setRequestProperty("Cache-Control", "no-cache") - connection.setRequestProperty("Content-Type", "application/json") - connection.setRequestProperty("Content-Length", data.length.toString()) - - try { - val outStream = DataOutputStream(connection.outputStream) - outStream.writeBytes(data) - outStream.close() - - return when (connection.responseCode) { - 200 -> true - 201 -> true - else -> { - println("Failed to " + method + " data. Status Code: " + connection.responseCode + ". Message: " + connection.responseMessage) - false - } - } - } catch(e: SocketTimeoutException) { - println("Server took too long to respond") - return false - } -} - -private fun putJson(url: URL, data: String) : Boolean { - return sendJson(url, data, "PUT") -} - -private fun postJson(url: URL, data: String) : Boolean { - return sendJson(url, data, "POST") -} - -// Todo: Use a simpler library function for this and handle timeout exceptions -private fun uploadFile(url: URL, file: String) : Boolean { - val boundary = "===" + System.currentTimeMillis() + "===" - val hyphens = "--" - val clrf = "\r\n" - - val connection = url.openConnection() as HttpURLConnection - connection.doOutput = true - connection.doInput = true - connection.useCaches = false - connection.requestMethod = "POST" - connection.connectTimeout = 5000 - connection.readTimeout = 60000 - connection.setRequestProperty("Connection", "Keep-Alive") - connection.setRequestProperty("Cache-Control", "no-cache") - connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary) - - val request = DataOutputStream(connection.outputStream) - request.writeBytes(hyphens + boundary + clrf) - request.writeBytes("Content-Disposition: form-data; name=\"rates\" filename=\"example.rates.txt\"$clrf") - request.writeBytes(clrf) - request.writeBytes(file) - request.writeBytes(clrf) - request.writeBytes(hyphens + boundary + hyphens + clrf) - - if (connection.responseCode == 200) { - return true - } else { - println("Could not upload file. Status Code: " + connection + ". Message: " + connection.responseMessage) - return false - } } private fun getNodeConfig(cliParams: CliParams.RunNode): NodeConfiguration { diff --git a/src/main/kotlin/com/r3corda/demos/utilities/HttpUtils.kt b/src/main/kotlin/com/r3corda/demos/utilities/HttpUtils.kt new file mode 100644 index 0000000000..f26340303d --- /dev/null +++ b/src/main/kotlin/com/r3corda/demos/utilities/HttpUtils.kt @@ -0,0 +1,39 @@ +package com.r3corda.demos.utilities + +import okhttp3.* +import java.net.URL +import java.util.concurrent.TimeUnit + +/** + * A small set of utilities for making HttpCalls, aimed at demos. + */ +private val client = OkHttpClient.Builder() + .connectTimeout(5, TimeUnit.SECONDS) + .readTimeout(15, TimeUnit.SECONDS).build(); + +fun putJson(url: URL, data: String) : Boolean { + val body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), data) + return makeRequest(Request.Builder().url(url).put(body).build()) +} + +fun postJson(url: URL, data: String) : Boolean { + val body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), data) + return makeRequest(Request.Builder().url(url).post(body).build()) +} + +fun uploadFile(url: URL, file: String) : Boolean { + val body = MultipartBody.Builder() + .setType(MultipartBody.FORM) + .addFormDataPart("rates", "example.rates.txt", RequestBody.create(MediaType.parse("text/plain"), file)) + .build(); + return makeRequest(Request.Builder().url(url).post(body).build()) +} + +private fun makeRequest(request: Request): Boolean { + val response = client.newCall(request).execute(); + + if (!response.isSuccessful) { + println("Could not fulfill HTTP request. Status Code: ${response.code()}. Message: ${response.body()}") + } + return response.isSuccessful +} \ No newline at end of file From 3651bd54aa1efa1e300806a00457e54d825c2185 Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Tue, 14 Jun 2016 11:28:28 +0100 Subject: [PATCH 100/114] Increased read timeout in order to avoid timeouts on long fixing periods (ie; 2020-01-01) on the IRS demo. --- src/main/kotlin/com/r3corda/demos/utilities/HttpUtils.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/com/r3corda/demos/utilities/HttpUtils.kt b/src/main/kotlin/com/r3corda/demos/utilities/HttpUtils.kt index f26340303d..f6d54e6a44 100644 --- a/src/main/kotlin/com/r3corda/demos/utilities/HttpUtils.kt +++ b/src/main/kotlin/com/r3corda/demos/utilities/HttpUtils.kt @@ -9,7 +9,7 @@ import java.util.concurrent.TimeUnit */ private val client = OkHttpClient.Builder() .connectTimeout(5, TimeUnit.SECONDS) - .readTimeout(15, TimeUnit.SECONDS).build(); + .readTimeout(60, TimeUnit.SECONDS).build(); fun putJson(url: URL, data: String) : Boolean { val body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), data) From 98b02e9d3321acac12bb31378faf52f5b2560f31 Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Tue, 14 Jun 2016 16:41:08 +0100 Subject: [PATCH 101/114] Added some simple documentation to the IRSDemo. --- src/main/kotlin/com/r3corda/demos/IRSDemo.kt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt index 1a91e48dd9..fd24b5929e 100644 --- a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt @@ -256,7 +256,7 @@ fun runIRSDemo(args: Array): Int { CliParams.parse(CliParamsSpec.parser.parse(*args)) } catch (e: Exception) { println(e) - printHelp() + printHelp(CliParamsSpec.parser) return 1 } @@ -462,8 +462,10 @@ private fun createDefaultConfigFile(configFile: File, legalName: String) { """.trimIndent().toByteArray()) } -private fun printHelp() { +private fun printHelp(parser: OptionParser) { println(""" - Please refer to the documentation in docs/build/index.html to learn how to run the demo. + Usage: irsdemo --role [NodeA|NodeB|Trade|Date] [|] [options] + Please refer to the documentation in docs/build/index.html for more info. + """.trimIndent()) } From 24deb5a79c2165484951761f9d05604ea22750f6 Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Tue, 14 Jun 2016 17:03:07 +0100 Subject: [PATCH 102/114] Added more useful help message that includes basic usage to the TraderDemo. --- src/main/kotlin/com/r3corda/demos/TraderDemo.kt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/com/r3corda/demos/TraderDemo.kt b/src/main/kotlin/com/r3corda/demos/TraderDemo.kt index c1e6fce49c..c5f62ea2b2 100644 --- a/src/main/kotlin/com/r3corda/demos/TraderDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/TraderDemo.kt @@ -84,7 +84,7 @@ fun runTraderDemo(args: Array): Int { parser.parse(*args) } catch (e: Exception) { println(e.message) - println("Please refer to the documentation in docs/build/index.html to learn how to run the demo.") + printHelp(parser) return 1 } @@ -377,3 +377,13 @@ private class TraderDemoProtocolSeller(val otherSide: Party, } } + +private fun printHelp(parser: OptionParser) { + println(""" + Usage: trader-demo --role [BUYER|SELLER] [options] + Please refer to the documentation in docs/build/index.html for more info. + + """.trimIndent()) + parser.printHelpOn(System.out) +} + From d4da633b1eff016bbfd01965f24ca95b6b44c015 Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Thu, 7 Jul 2016 16:31:52 +0100 Subject: [PATCH 103/114] Fixed merge issues --- src/main/kotlin/com/r3corda/demos/IRSDemo.kt | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt index fd24b5929e..6ced85929a 100644 --- a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt @@ -26,10 +26,7 @@ import com.typesafe.config.ConfigFactory import joptsimple.OptionParser import joptsimple.OptionSet import org.apache.commons.io.IOUtils -import java.io.DataOutputStream import java.io.File -import java.net.HttpURLConnection -import java.net.SocketTimeoutException import java.net.URL import java.nio.file.Files import java.nio.file.Path @@ -37,7 +34,6 @@ import java.nio.file.Paths import java.util.* import kotlin.concurrent.fixedRateTimer import kotlin.system.exitProcess -import org.apache.commons.io.IOUtils import com.r3corda.demos.utilities.* // IRS DEMO @@ -423,8 +419,6 @@ private fun runUploadRates(host: HostAndPort) { }) } -} - private fun getNodeConfig(cliParams: CliParams.RunNode): NodeConfiguration { if (!Files.exists(cliParams.dir)) { throw NotSetupException("Missing config directory. Please run node setup before running the node") From 01e64d303056ba01e233f6af8c7ab17ee7b2ac0b Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Thu, 7 Jul 2016 17:23:14 +0100 Subject: [PATCH 104/114] Fixed merge conflicts. --- src/main/kotlin/com/r3corda/demos/IRSDemo.kt | 1 + src/main/kotlin/com/r3corda/demos/TraderDemo.kt | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt index 6ced85929a..0a2f3cdd13 100644 --- a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt @@ -462,4 +462,5 @@ private fun printHelp(parser: OptionParser) { Please refer to the documentation in docs/build/index.html for more info. """.trimIndent()) + parser.printHelpOn(System.out) } diff --git a/src/main/kotlin/com/r3corda/demos/TraderDemo.kt b/src/main/kotlin/com/r3corda/demos/TraderDemo.kt index c5f62ea2b2..d994281a20 100644 --- a/src/main/kotlin/com/r3corda/demos/TraderDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/TraderDemo.kt @@ -71,7 +71,6 @@ fun main(args: Array) { } fun runTraderDemo(args: Array): Int { - val cashIssuerKey = generateKeyPair() val parser = OptionParser() val roleArg = parser.accepts("role").withRequiredArg().ofType(Role::class.java).required() From c260c227a9770e860b01f8e02cab8c36fcaab355 Mon Sep 17 00:00:00 2001 From: Matthew Nesbit Date: Fri, 8 Jul 2016 10:24:51 +0100 Subject: [PATCH 105/114] Add cacheing to ServiceLoader scanning of plugins and add a TODO on whitelisting --- .../kotlin/com/r3corda/core/protocols/ProtocolLogicRef.kt | 4 +++- .../main/kotlin/com/r3corda/node/internal/AbstractNode.kt | 7 ++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/core/src/main/kotlin/com/r3corda/core/protocols/ProtocolLogicRef.kt b/core/src/main/kotlin/com/r3corda/core/protocols/ProtocolLogicRef.kt index c63bfeb6cc..5b0154cb81 100644 --- a/core/src/main/kotlin/com/r3corda/core/protocols/ProtocolLogicRef.kt +++ b/core/src/main/kotlin/com/r3corda/core/protocols/ProtocolLogicRef.kt @@ -39,7 +39,9 @@ class ProtocolLogicRefFactory(private val protocolWhitelist: Map get() = _networkMapRegistrationFuture - /** fetch CordaPluginRegistry classes registered in META-INF/services/com.r3corda.core.node.CordaPluginRegistry files that exist in the classpath */ - protected val pluginRegistries: List - get() = ServiceLoader.load(CordaPluginRegistry::class.java).toList() + /** Fetch CordaPluginRegistry classes registered in META-INF/services/com.r3corda.core.node.CordaPluginRegistry files that exist in the classpath */ + protected val pluginRegistries: List by lazy { + ServiceLoader.load(CordaPluginRegistry::class.java).toList() + } /** Set to true once [start] has been successfully called. */ @Volatile var started = false From 1fb4371de9b12e9cb41b74718e19bf2133ddaee7 Mon Sep 17 00:00:00 2001 From: Matthew Nesbit Date: Wed, 6 Jul 2016 13:23:41 +0100 Subject: [PATCH 106/114] Make the IRS Demo web api an api plugin (scanned from the Node classpath) and use the same permission checking entry point for web api's as the scheduler. Fix whitespace Change ProtocolLogicRefFactory to use Map> as whitelist definition --- .../r3corda/core/node/CordaPluginRegistry.kt | 23 +++++++++++ .../com/r3corda/core/node/ServiceHub.kt | 9 ++++ .../core/protocols/ProtocolLogicRef.kt | 20 +++++---- .../ProtocolLogicRefFromJavaTest.java | 38 ++++++++++++++--- .../core/protocols/ProtocolLogicRefTest.kt | 41 ++++++++++++++----- .../com/r3corda/node/internal/AbstractNode.kt | 19 ++++++++- .../kotlin/com/r3corda/node/internal/Node.kt | 19 +++++---- .../node/services/api/ServiceHubInternal.kt | 7 ++++ .../services/clientapi/NodeInterestRates.kt | 11 +++++ .../node/services/NodeSchedulerServiceTest.kt | 2 +- src/main/kotlin/com/r3corda/demos/IRSDemo.kt | 13 +++++- .../kotlin/com/r3corda/demos/RateFixDemo.kt | 3 +- .../r3corda/demos/api/InterestRateSwapAPI.kt | 27 ++++++------ .../demos/protocols/ExitServerProtocol.kt | 7 ++-- .../com.r3corda.core.node.CordaPluginRegistry | 2 + 15 files changed, 186 insertions(+), 55 deletions(-) create mode 100644 core/src/main/kotlin/com/r3corda/core/node/CordaPluginRegistry.kt create mode 100644 src/main/resources/META-INF/services/com.r3corda.core.node.CordaPluginRegistry diff --git a/core/src/main/kotlin/com/r3corda/core/node/CordaPluginRegistry.kt b/core/src/main/kotlin/com/r3corda/core/node/CordaPluginRegistry.kt new file mode 100644 index 0000000000..89492ee373 --- /dev/null +++ b/core/src/main/kotlin/com/r3corda/core/node/CordaPluginRegistry.kt @@ -0,0 +1,23 @@ +package com.r3corda.core.node + +/** + * Implement this interface on a class advertised in a META-INF/services/com.r3corda.core.node.CordaPluginRegistry file + * to extend a Corda node with additional application services. + */ +interface CordaPluginRegistry { + /** + * List of JAX-RS classes inside the contract jar. They are expected to have a single parameter constructor that takes a ServiceHub as input. + * These are listed as Class<*>, because they will be instantiated inside an AttachmentClassLoader so that subsequent protocols, contracts, etc + * will be running in the appropriate isolated context. + */ + val webApis: List> + + /** + * A Map with an entry for each consumed protocol used by the webAPIs. + * The key of each map entry should contain the ProtocolLogic class name. + * The associated map values are the union of all concrete class names passed to the protocol constructor. + * Standard java.lang.* and kotlin.* types do not need to be included explicitly + * This is used to extend the white listed protocols that can be initiated from the ServiceHub invokeProtocolAsync method + */ + val requiredProtocols: Map> +} \ No newline at end of file diff --git a/core/src/main/kotlin/com/r3corda/core/node/ServiceHub.kt b/core/src/main/kotlin/com/r3corda/core/node/ServiceHub.kt index 893f83a868..d1cf7fa0fd 100644 --- a/core/src/main/kotlin/com/r3corda/core/node/ServiceHub.kt +++ b/core/src/main/kotlin/com/r3corda/core/node/ServiceHub.kt @@ -1,8 +1,10 @@ package com.r3corda.core.node +import com.google.common.util.concurrent.ListenableFuture import com.r3corda.core.contracts.* import com.r3corda.core.messaging.MessagingService import com.r3corda.core.node.services.* +import com.r3corda.core.protocols.ProtocolLogic import java.time.Clock /** @@ -61,4 +63,11 @@ interface ServiceHub { val definingTx = storageService.validatedTransactions.getTransaction(stateRef.txhash) ?: throw TransactionResolutionException(stateRef.txhash) return definingTx.tx.outputs[stateRef.index] } + + /** + * Will check [logicType] and [args] against a whitelist and if acceptable then construct and initiate the protocol. + * + * @throws IllegalProtocolLogicException or IllegalArgumentException if there are problems with the [logicType] or [args] + */ + fun invokeProtocolAsync(logicType: Class>, vararg args: Any?): ListenableFuture } \ No newline at end of file diff --git a/core/src/main/kotlin/com/r3corda/core/protocols/ProtocolLogicRef.kt b/core/src/main/kotlin/com/r3corda/core/protocols/ProtocolLogicRef.kt index 2e8bffb531..c63bfeb6cc 100644 --- a/core/src/main/kotlin/com/r3corda/core/protocols/ProtocolLogicRef.kt +++ b/core/src/main/kotlin/com/r3corda/core/protocols/ProtocolLogicRef.kt @@ -25,22 +25,26 @@ import kotlin.reflect.primaryConstructor * TODO: Align with API related logic for passing in ProtocolLogic references (ProtocolRef) * TODO: Actual support for AppContext / AttachmentsClassLoader */ -class ProtocolLogicRefFactory(private val protocolLogicClassNameWhitelist: Set, private val argsClassNameWhitelist: Set) : SingletonSerializeAsToken() { +class ProtocolLogicRefFactory(private val protocolWhitelist: Map>) : SingletonSerializeAsToken() { - constructor() : this(setOf(TwoPartyDealProtocol.FixingRoleDecider::class.java.name), setOf(StateRef::class.java.name, Duration::class.java.name)) + constructor() : this(mapOf(Pair(TwoPartyDealProtocol.FixingRoleDecider::class.java.name, setOf(StateRef::class.java.name, Duration::class.java.name)))) // Pending real dependence on AppContext for class loading etc @Suppress("UNUSED_PARAMETER") private fun validateProtocolClassName(className: String, appContext: AppContext) { // TODO: make this specific to the attachments in the [AppContext] by including [SecureHash] in whitelist check - require(className in protocolLogicClassNameWhitelist) { "${ProtocolLogic::class.java.simpleName} of ${ProtocolLogicRef::class.java.simpleName} must have type on the whitelist: $className" } + require(protocolWhitelist.containsKey(className)) { "${ProtocolLogic::class.java.simpleName} of ${ProtocolLogicRef::class.java.simpleName} must have type on the whitelist: $className" } } // Pending real dependence on AppContext for class loading etc @Suppress("UNUSED_PARAMETER") - private fun validateArgClassName(className: String, appContext: AppContext) { + private fun validateArgClassName(className: String, argClassName: String, appContext: AppContext) { + // Accept standard java.lang.* and kotlin.* types + if (argClassName.startsWith("java.lang.") || argClassName.startsWith("kotlin.")) { + return + } // TODO: make this specific to the attachments in the [AppContext] by including [SecureHash] in whitelist check - require(className in argsClassNameWhitelist) { "Args to ${ProtocolLogicRef::class.java.simpleName} must have types on the args whitelist: $className" } + require(protocolWhitelist[className]!!.contains(argClassName)) { "Args to ${className} must have types on the args whitelist: $argClassName" } } /** @@ -90,14 +94,14 @@ class ProtocolLogicRefFactory(private val protocolLogicClassNameWhitelist: Set>, args: Map): () -> ProtocolLogic<*> { for (constructor in clazz.kotlin.constructors) { - val params = buildParams(appContext, constructor, args) ?: continue + val params = buildParams(appContext, clazz, constructor, args) ?: continue // If we get here then we matched every parameter return { constructor.callBy(params) } } throw IllegalProtocolLogicException(clazz, "as could not find matching constructor for: $args") } - private fun buildParams(appContext: AppContext, constructor: KFunction>, args: Map): HashMap? { + private fun buildParams(appContext: AppContext, clazz: Class>, constructor: KFunction>, args: Map): HashMap? { val params = hashMapOf() val usedKeys = hashSetOf() for (parameter in constructor.parameters) { @@ -111,7 +115,7 @@ class ProtocolLogicRefFactory(private val protocolLogicClassNameWhitelist: Set { - public JavaProtocolLogic(int A, String b) { + public JavaProtocolLogic(ParamType1 A, ParamType2 b) { } @Override @@ -43,13 +63,21 @@ public class ProtocolLogicRefFromJavaTest { @Test public void test() { - ProtocolLogicRefFactory factory = new ProtocolLogicRefFactory(Sets.newHashSet(JavaProtocolLogic.class.getName()), Sets.newHashSet(Integer.class.getName(), String.class.getName())); - factory.create(JavaProtocolLogic.class, 1, "Hello Jack"); + Map> whiteList = new HashMap<>(); + Set argsList = new HashSet<>(); + argsList.add(ParamType1.class.getName()); + argsList.add(ParamType2.class.getName()); + whiteList.put(JavaProtocolLogic.class.getName(), argsList); + ProtocolLogicRefFactory factory = new ProtocolLogicRefFactory(whiteList); + factory.create(JavaProtocolLogic.class, new ParamType1(1), new ParamType2("Hello Jack")); } @Test public void testNoArg() { - ProtocolLogicRefFactory factory = new ProtocolLogicRefFactory(Sets.newHashSet(JavaNoArgProtocolLogic.class.getName()), Sets.newHashSet(Integer.class.getName(), String.class.getName())); + Map> whiteList = new HashMap<>(); + Set argsList = new HashSet<>(); + whiteList.put(JavaNoArgProtocolLogic.class.getName(), argsList); + ProtocolLogicRefFactory factory = new ProtocolLogicRefFactory(whiteList); factory.create(JavaNoArgProtocolLogic.class); } } diff --git a/core/src/test/kotlin/com/r3corda/core/protocols/ProtocolLogicRefTest.kt b/core/src/test/kotlin/com/r3corda/core/protocols/ProtocolLogicRefTest.kt index bcede610b1..aa5651f12d 100644 --- a/core/src/test/kotlin/com/r3corda/core/protocols/ProtocolLogicRefTest.kt +++ b/core/src/test/kotlin/com/r3corda/core/protocols/ProtocolLogicRefTest.kt @@ -1,6 +1,5 @@ package com.r3corda.core.protocols -import com.google.common.collect.Sets import com.r3corda.core.days import org.junit.Before import org.junit.Test @@ -8,13 +7,20 @@ import java.time.Duration class ProtocolLogicRefTest { + data class ParamType1(val value: Int) + data class ParamType2(val value: String) + @Suppress("UNUSED_PARAMETER") // We will never use A or b - class KotlinProtocolLogic(A: Int, b: String) : ProtocolLogic() { - constructor() : this(1, "2") + class KotlinProtocolLogic(A: ParamType1, b: ParamType2) : ProtocolLogic() { + constructor() : this(ParamType1(1), ParamType2("2")) - constructor(C: String) : this(1, C) + constructor(C: ParamType2) : this(ParamType1(1), C) - constructor(illegal: Duration) : this(1, illegal.toString()) + constructor(illegal: Duration) : this(ParamType1(1), ParamType2(illegal.toString())) + + constructor(primitive: String) : this(ParamType1(1), ParamType2(primitive)) + + constructor(kotlinType: Int) : this(ParamType1(kotlinType), ParamType2("b")) override fun call(): Unit { } @@ -40,8 +46,8 @@ class ProtocolLogicRefTest { @Before fun setup() { // We have to allow Java boxed primitives but Kotlin warns we shouldn't be using them - factory = ProtocolLogicRefFactory(Sets.newHashSet(KotlinProtocolLogic::class.java.name, KotlinNoArgProtocolLogic::class.java.name), - Sets.newHashSet(@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") Integer::class.java.name, String::class.java.name)) + factory = ProtocolLogicRefFactory(mapOf(Pair(KotlinProtocolLogic::class.java.name, setOf(ParamType1::class.java.name, ParamType2::class.java.name)), + Pair(KotlinNoArgProtocolLogic::class.java.name, setOf()))) } @Test @@ -51,18 +57,18 @@ class ProtocolLogicRefTest { @Test fun testCreateKotlin() { - val args = mapOf(Pair("A", 1), Pair("b", "Hello Jack")) + val args = mapOf(Pair("A", ParamType1(1)), Pair("b", ParamType2("Hello Jack"))) factory.createKotlin(KotlinProtocolLogic::class.java, args) } @Test fun testCreatePrimary() { - factory.create(KotlinProtocolLogic::class.java, 1, "Hello Jack") + factory.create(KotlinProtocolLogic::class.java, ParamType1(1), ParamType2("Hello Jack")) } @Test(expected = IllegalArgumentException::class) fun testCreateNotWhiteListed() { - factory.create(NotWhiteListedKotlinProtocolLogic::class.java, 1, "Hello Jack") + factory.create(NotWhiteListedKotlinProtocolLogic::class.java, ParamType1(1), ParamType2("Hello Jack")) } @Test @@ -72,7 +78,7 @@ class ProtocolLogicRefTest { @Test fun testCreateKotlinNonPrimary() { - val args = mapOf(Pair("C", "Hello Jack")) + val args = mapOf(Pair("C", ParamType2("Hello Jack"))) factory.createKotlin(KotlinProtocolLogic::class.java, args) } @@ -81,4 +87,17 @@ class ProtocolLogicRefTest { val args = mapOf(Pair("illegal", 1.days)) factory.createKotlin(KotlinProtocolLogic::class.java, args) } + + @Test + fun testCreateJavaPrimitiveNoRegistrationRequired() { + val args = mapOf(Pair("primitive", "A string")) + factory.createKotlin(KotlinProtocolLogic::class.java, args) + } + + @Test + fun testCreateKotlinPrimitiveNoRegistrationRequired() { + val args = mapOf(Pair("kotlinType", 3)) + factory.createKotlin(KotlinProtocolLogic::class.java, args) + } + } diff --git a/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt index 7838807b5a..797344945c 100644 --- a/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt @@ -9,6 +9,7 @@ import com.r3corda.core.crypto.Party import com.r3corda.core.messaging.MessagingService import com.r3corda.core.messaging.runOnNextMessage import com.r3corda.core.node.CityDatabase +import com.r3corda.core.node.CordaPluginRegistry import com.r3corda.core.node.NodeInfo import com.r3corda.core.node.PhysicalLocation import com.r3corda.core.node.services.* @@ -97,7 +98,7 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration, // Internal only override val monitoringService: MonitoringService = MonitoringService(MetricRegistry()) - override val protocolLogicRefFactory = ProtocolLogicRefFactory() + override val protocolLogicRefFactory: ProtocolLogicRefFactory get() = protocolLogicFactory override fun startProtocol(loggerName: String, logic: ProtocolLogic): ListenableFuture { return smm.add(loggerName, logic) @@ -124,6 +125,7 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration, lateinit var net: MessagingService lateinit var api: APIServer lateinit var scheduler: SchedulerService + lateinit var protocolLogicFactory: ProtocolLogicRefFactory var isPreviousCheckpointsPresent = false private set @@ -158,6 +160,8 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration, checkpointStorage, serverThread) + protocolLogicFactory = initialiseProtocolLogicFactory() + // This object doesn't need to be referenced from this class because it registers handlers on the network // service and so that keeps it from being collected. DataVendingService(net, storage, services.networkMapCache) @@ -180,6 +184,19 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration, return this } + private fun initialiseProtocolLogicFactory(): ProtocolLogicRefFactory { + val serviceLoader = ServiceLoader.load(CordaPluginRegistry::class.java) + val pluginRegistries = serviceLoader.toList() + val protocolWhitelist = HashMap>() + for (plugin in pluginRegistries) { + for (protocol in plugin.requiredProtocols) { + protocolWhitelist.merge(protocol.key, protocol.value, { x, y -> x + y }) + } + } + + return ProtocolLogicRefFactory(protocolWhitelist) + } + /** * Run any tasks that are needed to ensure the node is in a correct state before running start() */ diff --git a/node/src/main/kotlin/com/r3corda/node/internal/Node.kt b/node/src/main/kotlin/com/r3corda/node/internal/Node.kt index 85cfac29a3..98e7a72745 100644 --- a/node/src/main/kotlin/com/r3corda/node/internal/Node.kt +++ b/node/src/main/kotlin/com/r3corda/node/internal/Node.kt @@ -3,10 +3,11 @@ package com.r3corda.node.internal import com.codahale.metrics.JmxReporter import com.google.common.net.HostAndPort import com.r3corda.core.messaging.MessagingService +import com.r3corda.core.node.CordaPluginRegistry import com.r3corda.core.node.NodeInfo +import com.r3corda.core.node.ServiceHub import com.r3corda.core.node.services.ServiceType import com.r3corda.core.utilities.loggerFor -import com.r3corda.node.api.APIServer import com.r3corda.node.serialization.NodeClock import com.r3corda.node.services.config.NodeConfiguration import com.r3corda.node.services.messaging.ArtemisMessagingService @@ -27,9 +28,9 @@ import java.io.RandomAccessFile import java.lang.management.ManagementFactory import java.net.InetSocketAddress import java.nio.channels.FileLock -import java.nio.file.Files import java.nio.file.Path import java.time.Clock +import java.util.* import javax.management.ObjectName class ConfigurationException(message: String) : Exception(message) @@ -55,8 +56,7 @@ class ConfigurationException(message: String) : Exception(message) */ class Node(dir: Path, val p2pAddr: HostAndPort, val webServerAddr: HostAndPort, configuration: NodeConfiguration, networkMapAddress: NodeInfo?, advertisedServices: Set, - clock: Clock = NodeClock(), - val clientAPIs: List> = listOf()) : AbstractNode(dir, configuration, networkMapAddress, advertisedServices, clock) { + clock: Clock = NodeClock()) : AbstractNode(dir, configuration, networkMapAddress, advertisedServices, clock) { companion object { /** The port that is used by default if none is specified. As you know, 31337 is the most elite number. */ val DEFAULT_PORT = 31337 @@ -109,12 +109,15 @@ class Node(dir: Path, val p2pAddr: HostAndPort, val webServerAddr: HostAndPort, resourceConfig.register(ResponseFilter()) resourceConfig.register(api) - for(customAPIClass in clientAPIs) { - val customAPI = customAPIClass.getConstructor(APIServer::class.java).newInstance(api) + val serviceLoader = ServiceLoader.load(CordaPluginRegistry::class.java) + val pluginRegistries = serviceLoader.toList() + val webAPIsOnClasspath = pluginRegistries.flatMap { x -> x.webApis } + for (webapi in webAPIsOnClasspath) { + log.info("Add Plugin web API from attachment ${webapi.name}") + val customAPI = webapi.getConstructor(ServiceHub::class.java).newInstance(services) resourceConfig.register(customAPI) } - // 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")) @@ -187,5 +190,5 @@ class Node(dir: Path, val p2pAddr: HostAndPort, val webServerAddr: HostAndPort, val ourProcessID: String = ManagementFactory.getRuntimeMXBean().name.split("@")[0] f.setLength(0) f.write(ourProcessID.toByteArray()) - } + } } diff --git a/node/src/main/kotlin/com/r3corda/node/services/api/ServiceHubInternal.kt b/node/src/main/kotlin/com/r3corda/node/services/api/ServiceHubInternal.kt index e206a28644..d60c20ab67 100644 --- a/node/src/main/kotlin/com/r3corda/node/services/api/ServiceHubInternal.kt +++ b/node/src/main/kotlin/com/r3corda/node/services/api/ServiceHubInternal.kt @@ -29,4 +29,11 @@ abstract class ServiceHubInternal : ServiceHub { * itself, at which point this method would not be needed (by the scheduler) */ abstract fun startProtocol(loggerName: String, logic: ProtocolLogic): ListenableFuture + + override fun invokeProtocolAsync(logicType: Class>, vararg args: Any?): ListenableFuture { + val logicRef = protocolLogicRefFactory.create(logicType, *args) + @Suppress("UNCHECKED_CAST") + val logic = protocolLogicRefFactory.toProtocolLogic(logicRef) as ProtocolLogic + return startProtocol(logicType.simpleName, logic) + } } \ No newline at end of file diff --git a/node/src/main/kotlin/com/r3corda/node/services/clientapi/NodeInterestRates.kt b/node/src/main/kotlin/com/r3corda/node/services/clientapi/NodeInterestRates.kt index 94d4c9dbeb..dbd3182ab7 100644 --- a/node/src/main/kotlin/com/r3corda/node/services/clientapi/NodeInterestRates.kt +++ b/node/src/main/kotlin/com/r3corda/node/services/clientapi/NodeInterestRates.kt @@ -9,6 +9,7 @@ import com.r3corda.core.crypto.signWithECDSA import com.r3corda.core.math.CubicSplineInterpolator import com.r3corda.core.math.Interpolator import com.r3corda.core.math.InterpolatorFactory +import com.r3corda.core.node.CordaPluginRegistry import com.r3corda.core.node.services.ServiceType import com.r3corda.core.protocols.ProtocolLogic import com.r3corda.core.utilities.ProgressTracker @@ -23,6 +24,7 @@ import java.io.InputStream import java.math.BigDecimal import java.security.KeyPair import java.time.Clock +import java.time.Duration import java.time.Instant import java.time.LocalDate import java.util.* @@ -93,6 +95,15 @@ object NodeInterestRates { } } + /** + * Register the protocol that is used with the Fixing integration tests + */ + class FixingServicePlugin : CordaPluginRegistry { + override val webApis: List> = emptyList() + override val requiredProtocols: Map> = mapOf(Pair(TwoPartyDealProtocol.FixingRoleDecider::class.java.name, setOf(Duration::class.java.name, StateRef::class.java.name))) + + } + // File upload support override val dataTypePrefix = "interest-rates" override val acceptableFileExtensions = listOf(".rates", ".txt") diff --git a/node/src/test/kotlin/com/r3corda/node/services/NodeSchedulerServiceTest.kt b/node/src/test/kotlin/com/r3corda/node/services/NodeSchedulerServiceTest.kt index 566d2aff3f..c2f20ec8b3 100644 --- a/node/src/test/kotlin/com/r3corda/node/services/NodeSchedulerServiceTest.kt +++ b/node/src/test/kotlin/com/r3corda/node/services/NodeSchedulerServiceTest.kt @@ -43,7 +43,7 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() { // We have to allow Java boxed primitives but Kotlin warns we shouldn't be using them @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") - val factory = ProtocolLogicRefFactory(setOf(TestProtocolLogic::class.java.name), setOf(NodeSchedulerServiceTest::class.java.name, Integer::class.java.name)) + val factory = ProtocolLogicRefFactory(mapOf(Pair(TestProtocolLogic::class.java.name, setOf(NodeSchedulerServiceTest::class.java.name, Integer::class.java.name)))) val scheduler: NodeSchedulerService val services: ServiceHub diff --git a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt index c2a60d4609..d3824c39e0 100644 --- a/src/main/kotlin/com/r3corda/demos/IRSDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/IRSDemo.kt @@ -1,9 +1,11 @@ package com.r3corda.demos import com.google.common.net.HostAndPort +import com.r3corda.contracts.InterestRateSwap import com.r3corda.core.crypto.Party import com.r3corda.core.logElapsedTime import com.r3corda.core.messaging.SingleMessageRecipient +import com.r3corda.core.node.CordaPluginRegistry import com.r3corda.core.node.NodeInfo import com.r3corda.core.node.services.ServiceType import com.r3corda.core.serialization.deserialize @@ -241,6 +243,14 @@ object CliParamsSpec { val nonOptions = parser.nonOptions() } +class IRSDemoPluginRegistry : CordaPluginRegistry { + override val webApis: List> = listOf(InterestRateSwapAPI::class.java) + override val requiredProtocols: Map> = mapOf( + Pair(AutoOfferProtocol.Requester::class.java.name, setOf(InterestRateSwap.State::class.java.name)), + Pair(UpdateBusinessDayProtocol.Broadcast::class.java.name, setOf(java.time.LocalDate::class.java.name)), + Pair(ExitServerProtocol.Broadcast::class.java.name, setOf(kotlin.Int::class.java.name))) +} + private class NotSetupException: Throwable { constructor(message: String): super(message) {} } @@ -374,8 +384,7 @@ private fun startNode(params: CliParams.RunNode, networkMap: SingleMessageRecipi } val node = logElapsedTime("Node startup") { - Node(params.dir, params.networkAddress, params.apiAddress, config, networkMapId, advertisedServices, DemoClock(), - listOf(InterestRateSwapAPI::class.java)).start() + Node(params.dir, params.networkAddress, params.apiAddress, config, networkMapId, advertisedServices, DemoClock()).start() } // TODO: This should all be replaced by the identity service being updated diff --git a/src/main/kotlin/com/r3corda/demos/RateFixDemo.kt b/src/main/kotlin/com/r3corda/demos/RateFixDemo.kt index 96473b033c..1374c58dd4 100644 --- a/src/main/kotlin/com/r3corda/demos/RateFixDemo.kt +++ b/src/main/kotlin/com/r3corda/demos/RateFixDemo.kt @@ -76,8 +76,7 @@ fun main(args: Array) { val apiAddr = HostAndPort.fromParts(myNetAddr.hostText, myNetAddr.port + 1) val node = logElapsedTime("Node startup") { Node(dir, myNetAddr, apiAddr, config, networkMapAddress, - advertisedServices, DemoClock(), - listOf(InterestRateSwapAPI::class.java)).setup().start() } + advertisedServices, DemoClock()).setup().start() } val notary = node.services.networkMapCache.notaryNodes[0] diff --git a/src/main/kotlin/com/r3corda/demos/api/InterestRateSwapAPI.kt b/src/main/kotlin/com/r3corda/demos/api/InterestRateSwapAPI.kt index 9197216da7..c5e3574360 100644 --- a/src/main/kotlin/com/r3corda/demos/api/InterestRateSwapAPI.kt +++ b/src/main/kotlin/com/r3corda/demos/api/InterestRateSwapAPI.kt @@ -1,15 +1,16 @@ package com.r3corda.demos.api import com.r3corda.contracts.InterestRateSwap +import com.r3corda.core.contracts.SignedTransaction +import com.r3corda.core.node.ServiceHub +import com.r3corda.core.node.services.linearHeadsOfType import com.r3corda.core.utilities.loggerFor import com.r3corda.demos.protocols.AutoOfferProtocol import com.r3corda.demos.protocols.ExitServerProtocol import com.r3corda.demos.protocols.UpdateBusinessDayProtocol -import com.r3corda.node.api.APIServer -import com.r3corda.node.api.ProtocolClassRef -import com.r3corda.node.api.StatesQuery import java.net.URI import java.time.LocalDate +import java.time.LocalDateTime import javax.ws.rs.* import javax.ws.rs.core.MediaType import javax.ws.rs.core.Response @@ -35,23 +36,23 @@ import javax.ws.rs.core.Response * or if the demodate or population of deals should be reset (will only work while persistence is disabled). */ @Path("irs") -class InterestRateSwapAPI(val api: APIServer) { +class InterestRateSwapAPI(val services: ServiceHub) { private val logger = loggerFor() private fun generateDealLink(deal: InterestRateSwap.State) = "/api/irs/deals/" + deal.common.tradeID private fun getDealByRef(ref: String): InterestRateSwap.State? { - val states = api.queryStates(StatesQuery.selectDeal(ref)) + val states = services.walletService.linearHeadsOfType().filterValues { it.state.data.ref == ref } return if (states.isEmpty()) null else { - val deals = api.fetchStates(states).values.map { it?.data as InterestRateSwap.State }.filterNotNull() + val deals = states.values.map { it.state.data } return if (deals.isEmpty()) null else deals[0] } } private fun getAllDeals(): Array { - val states = api.queryStates(StatesQuery.selectAllDeals()) - val swaps = api.fetchStates(states).values.map { it?.data as InterestRateSwap.State }.filterNotNull().toTypedArray() + val states = services.walletService.linearHeadsOfType() + val swaps = states.values.map { it.state.data }.toTypedArray() return swaps } @@ -64,7 +65,7 @@ class InterestRateSwapAPI(val api: APIServer) { @Path("deals") @Consumes(MediaType.APPLICATION_JSON) fun storeDeal(newDeal: InterestRateSwap.State): Response { - api.invokeProtocolSync(ProtocolClassRef(AutoOfferProtocol.Requester::class.java.name!!), mapOf("dealToBeOffered" to newDeal)) + services.invokeProtocolAsync(AutoOfferProtocol.Requester::class.java, newDeal).get() return Response.created(URI.create(generateDealLink(newDeal))).build() } @@ -84,10 +85,10 @@ class InterestRateSwapAPI(val api: APIServer) { @Path("demodate") @Consumes(MediaType.APPLICATION_JSON) fun storeDemoDate(newDemoDate: LocalDate): Response { - val priorDemoDate = api.serverTime().toLocalDate() + val priorDemoDate = fetchDemoDate() // Can only move date forwards if (newDemoDate.isAfter(priorDemoDate)) { - api.invokeProtocolSync(ProtocolClassRef(UpdateBusinessDayProtocol.Broadcast::class.java.name!!), mapOf("date" to newDemoDate)) + services.invokeProtocolAsync(UpdateBusinessDayProtocol.Broadcast::class.java, newDemoDate).get() return Response.ok().build() } val msg = "demodate is already $priorDemoDate and can only be updated with a later date" @@ -99,14 +100,14 @@ class InterestRateSwapAPI(val api: APIServer) { @Path("demodate") @Produces(MediaType.APPLICATION_JSON) fun fetchDemoDate(): LocalDate { - return api.serverTime().toLocalDate() + return LocalDateTime.now(services.clock).toLocalDate() } @PUT @Path("restart") @Consumes(MediaType.APPLICATION_JSON) fun exitServer(): Response { - api.invokeProtocolSync(ProtocolClassRef(ExitServerProtocol.Broadcast::class.java.name!!), mapOf("exitCode" to 83)) + services.invokeProtocolAsync(ExitServerProtocol.Broadcast::class.java, 83).get() return Response.ok().build() } } diff --git a/src/main/kotlin/com/r3corda/demos/protocols/ExitServerProtocol.kt b/src/main/kotlin/com/r3corda/demos/protocols/ExitServerProtocol.kt index 007aebd7e2..9b5ff0799c 100644 --- a/src/main/kotlin/com/r3corda/demos/protocols/ExitServerProtocol.kt +++ b/src/main/kotlin/com/r3corda/demos/protocols/ExitServerProtocol.kt @@ -37,22 +37,21 @@ object ExitServerProtocol { * This takes a Java Integer rather than Kotlin Int as that is what we end up with in the calling map and currently * we do not support coercing numeric types in the reflective search for matching constructors */ - class Broadcast(@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") val exitCode: Integer) : ProtocolLogic() { + class Broadcast(@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") val exitCode: Int) : ProtocolLogic() { override val topic: String get() = TOPIC @Suspendable override fun call(): Boolean { if (enabled) { - val rc = exitCode.toInt() - val message = ExitMessage(rc) + val message = ExitMessage(exitCode) for (recipient in serviceHub.networkMapCache.partyNodes) { doNextRecipient(recipient, message) } // Sleep a little in case any async message delivery to other nodes needs to happen Strand.sleep(1, TimeUnit.SECONDS) - System.exit(rc) + System.exit(exitCode) } return enabled } diff --git a/src/main/resources/META-INF/services/com.r3corda.core.node.CordaPluginRegistry b/src/main/resources/META-INF/services/com.r3corda.core.node.CordaPluginRegistry new file mode 100644 index 0000000000..279300f9f9 --- /dev/null +++ b/src/main/resources/META-INF/services/com.r3corda.core.node.CordaPluginRegistry @@ -0,0 +1,2 @@ +# Register a ServiceLoader service extending from com.r3corda.node.CordaPluginRegistry +com.r3corda.demos.IRSDemoPluginRegistry \ No newline at end of file From f0f2dc4eb5a58ab8e02afc3e8e6d1ca92d6a5a6c Mon Sep 17 00:00:00 2001 From: Matthew Nesbit Date: Thu, 7 Jul 2016 12:08:53 +0100 Subject: [PATCH 107/114] Add missing import --- .../com/r3corda/node/services/clientapi/NodeInterestRates.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/node/src/main/kotlin/com/r3corda/node/services/clientapi/NodeInterestRates.kt b/node/src/main/kotlin/com/r3corda/node/services/clientapi/NodeInterestRates.kt index dbd3182ab7..d69dd39e2a 100644 --- a/node/src/main/kotlin/com/r3corda/node/services/clientapi/NodeInterestRates.kt +++ b/node/src/main/kotlin/com/r3corda/node/services/clientapi/NodeInterestRates.kt @@ -19,6 +19,7 @@ import com.r3corda.node.services.api.AcceptsFileUpload import com.r3corda.node.utilities.FiberBox import com.r3corda.protocols.RatesFixProtocol import com.r3corda.protocols.ServiceRequestMessage +import com.r3corda.protocols.TwoPartyDealProtocol import org.slf4j.LoggerFactory import java.io.InputStream import java.math.BigDecimal From d9d4fb360ff0d3e5f7d269d60c26ae7754f7af77 Mon Sep 17 00:00:00 2001 From: Matthew Nesbit Date: Thu, 7 Jul 2016 12:17:06 +0100 Subject: [PATCH 108/114] Make the IRS Demo web api an api plugin (scanned from the Node classpath) and use the same permission checking entry point for web api's as the scheduler. --- .../META-INF/services/com.r3corda.core.node.CordaPluginRegistry | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 node/src/main/resources/META-INF/services/com.r3corda.core.node.CordaPluginRegistry diff --git a/node/src/main/resources/META-INF/services/com.r3corda.core.node.CordaPluginRegistry b/node/src/main/resources/META-INF/services/com.r3corda.core.node.CordaPluginRegistry new file mode 100644 index 0000000000..6c27482af8 --- /dev/null +++ b/node/src/main/resources/META-INF/services/com.r3corda.core.node.CordaPluginRegistry @@ -0,0 +1,2 @@ +# Register a ServiceLoader service extending from com.r3corda.node.CordaPluginRegistry +com.r3corda.node.services.clientapi.NodeInterestRates$Service$FixingServicePlugin \ No newline at end of file From 51ba0cc8dd4a8cd069038674803a7e4272aad62e Mon Sep 17 00:00:00 2001 From: Matthew Nesbit Date: Wed, 6 Jul 2016 13:23:41 +0100 Subject: [PATCH 109/114] Make the IRS Demo web api an api plugin (scanned from the Node classpath) and use the same permission checking entry point for web api's as the scheduler. --- node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt index 797344945c..3b4dae1b20 100644 --- a/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt @@ -5,6 +5,7 @@ import com.google.common.util.concurrent.ListenableFuture import com.google.common.util.concurrent.SettableFuture import com.r3corda.core.RunOnCallerThread import com.r3corda.core.contracts.SignedTransaction +import com.r3corda.core.contracts.StateRef import com.r3corda.core.crypto.Party import com.r3corda.core.messaging.MessagingService import com.r3corda.core.messaging.runOnNextMessage @@ -47,12 +48,14 @@ import com.r3corda.node.services.wallet.NodeWalletService import com.r3corda.node.utilities.ANSIProgressObserver import com.r3corda.node.utilities.AddOrRemove import com.r3corda.node.utilities.AffinityExecutor +import com.r3corda.protocols.TwoPartyDealProtocol import org.slf4j.Logger import java.nio.file.FileAlreadyExistsException import java.nio.file.Files import java.nio.file.Path import java.security.KeyPair import java.time.Clock +import java.time.Duration import java.util.* /** From 1557a82992e7c4c2506e0a8847a00aeb89478296 Mon Sep 17 00:00:00 2001 From: Matthew Nesbit Date: Thu, 7 Jul 2016 13:55:15 +0100 Subject: [PATCH 110/114] Make ServiceLoader results for CordaPlugins a protected property on the AbstractNode --- .../main/kotlin/com/r3corda/node/internal/AbstractNode.kt | 7 +++++-- node/src/main/kotlin/com/r3corda/node/internal/Node.kt | 2 -- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt index 3b4dae1b20..c6924b73dd 100644 --- a/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/com/r3corda/node/internal/AbstractNode.kt @@ -137,6 +137,10 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration, val networkMapRegistrationFuture: ListenableFuture get() = _networkMapRegistrationFuture + /** fetch CordaPluginRegistry classes registered in META-INF/services/com.r3corda.core.node.CordaPluginRegistry files that exist in the classpath */ + protected val pluginRegistries: List + get() = ServiceLoader.load(CordaPluginRegistry::class.java).toList() + /** Set to true once [start] has been successfully called. */ @Volatile var started = false private set @@ -188,8 +192,6 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration, } private fun initialiseProtocolLogicFactory(): ProtocolLogicRefFactory { - val serviceLoader = ServiceLoader.load(CordaPluginRegistry::class.java) - val pluginRegistries = serviceLoader.toList() val protocolWhitelist = HashMap>() for (plugin in pluginRegistries) { for (protocol in plugin.requiredProtocols) { @@ -200,6 +202,7 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration, return ProtocolLogicRefFactory(protocolWhitelist) } + /** * Run any tasks that are needed to ensure the node is in a correct state before running start() */ diff --git a/node/src/main/kotlin/com/r3corda/node/internal/Node.kt b/node/src/main/kotlin/com/r3corda/node/internal/Node.kt index 98e7a72745..1c5c167b76 100644 --- a/node/src/main/kotlin/com/r3corda/node/internal/Node.kt +++ b/node/src/main/kotlin/com/r3corda/node/internal/Node.kt @@ -109,8 +109,6 @@ class Node(dir: Path, val p2pAddr: HostAndPort, val webServerAddr: HostAndPort, resourceConfig.register(ResponseFilter()) resourceConfig.register(api) - val serviceLoader = ServiceLoader.load(CordaPluginRegistry::class.java) - val pluginRegistries = serviceLoader.toList() val webAPIsOnClasspath = pluginRegistries.flatMap { x -> x.webApis } for (webapi in webAPIsOnClasspath) { log.info("Add Plugin web API from attachment ${webapi.name}") From 8d31df5fe16817220b592c0251f0ad8e547169a1 Mon Sep 17 00:00:00 2001 From: Matthew Nesbit Date: Thu, 7 Jul 2016 14:03:08 +0100 Subject: [PATCH 111/114] Remove @Suppress now we use standard Kotlin Int --- .../kotlin/com/r3corda/demos/protocols/ExitServerProtocol.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/com/r3corda/demos/protocols/ExitServerProtocol.kt b/src/main/kotlin/com/r3corda/demos/protocols/ExitServerProtocol.kt index 9b5ff0799c..5258e3dead 100644 --- a/src/main/kotlin/com/r3corda/demos/protocols/ExitServerProtocol.kt +++ b/src/main/kotlin/com/r3corda/demos/protocols/ExitServerProtocol.kt @@ -37,7 +37,7 @@ object ExitServerProtocol { * This takes a Java Integer rather than Kotlin Int as that is what we end up with in the calling map and currently * we do not support coercing numeric types in the reflective search for matching constructors */ - class Broadcast(@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") val exitCode: Int) : ProtocolLogic() { + class Broadcast(val exitCode: Int) : ProtocolLogic() { override val topic: String get() = TOPIC From eee049d66b89238967ae8746aa925378ad9221e3 Mon Sep 17 00:00:00 2001 From: Matthew Nesbit Date: Fri, 8 Jul 2016 10:24:51 +0100 Subject: [PATCH 112/114] Add cacheing to ServiceLoader scanning of plugins and add a TODO on whitelisting --- .../kotlin/com/r3corda/core/protocols/ProtocolLogicRef.kt | 4 +++- .../main/kotlin/com/r3corda/node/internal/AbstractNode.kt | 7 ++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/core/src/main/kotlin/com/r3corda/core/protocols/ProtocolLogicRef.kt b/core/src/main/kotlin/com/r3corda/core/protocols/ProtocolLogicRef.kt index c63bfeb6cc..5b0154cb81 100644 --- a/core/src/main/kotlin/com/r3corda/core/protocols/ProtocolLogicRef.kt +++ b/core/src/main/kotlin/com/r3corda/core/protocols/ProtocolLogicRef.kt @@ -39,7 +39,9 @@ class ProtocolLogicRefFactory(private val protocolWhitelist: Map get() = _networkMapRegistrationFuture - /** fetch CordaPluginRegistry classes registered in META-INF/services/com.r3corda.core.node.CordaPluginRegistry files that exist in the classpath */ - protected val pluginRegistries: List - get() = ServiceLoader.load(CordaPluginRegistry::class.java).toList() + /** Fetch CordaPluginRegistry classes registered in META-INF/services/com.r3corda.core.node.CordaPluginRegistry files that exist in the classpath */ + protected val pluginRegistries: List by lazy { + ServiceLoader.load(CordaPluginRegistry::class.java).toList() + } /** Set to true once [start] has been successfully called. */ @Volatile var started = false From 639df4dcb90edebc7271efe81ad6ef57713f0cfa Mon Sep 17 00:00:00 2001 From: Clinton Alexander Date: Fri, 8 Jul 2016 10:48:55 +0100 Subject: [PATCH 113/114] Http Client is now lazy init. --- src/main/kotlin/com/r3corda/demos/utilities/HttpUtils.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/com/r3corda/demos/utilities/HttpUtils.kt b/src/main/kotlin/com/r3corda/demos/utilities/HttpUtils.kt index f6d54e6a44..24d09b7b09 100644 --- a/src/main/kotlin/com/r3corda/demos/utilities/HttpUtils.kt +++ b/src/main/kotlin/com/r3corda/demos/utilities/HttpUtils.kt @@ -7,9 +7,11 @@ import java.util.concurrent.TimeUnit /** * A small set of utilities for making HttpCalls, aimed at demos. */ -private val client = OkHttpClient.Builder() +private val client by lazy { + OkHttpClient.Builder() .connectTimeout(5, TimeUnit.SECONDS) .readTimeout(60, TimeUnit.SECONDS).build(); +} fun putJson(url: URL, data: String) : Boolean { val body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), data) From 1ae8ada999ef041b8ce06872999ed733acc2dd0c Mon Sep 17 00:00:00 2001 From: Ross Nicoll Date: Thu, 7 Jul 2016 18:10:05 +0100 Subject: [PATCH 114/114] Add support for clause based contract verification --- .../r3corda/core/contracts/ContractsDSL.kt | 31 +++-- .../core/contracts/clauses/ClauseVerifier.kt | 92 ++++++++++++++ .../contracts/clauses/GroupClauseVerifier.kt | 82 +++++++++++++ .../contracts/clauses/InterceptorClause.kt | 28 +++++ .../contracts/clauses/VerifyClausesTests.kt | 114 ++++++++++++++++++ 5 files changed, 338 insertions(+), 9 deletions(-) create mode 100644 core/src/main/kotlin/com/r3corda/core/contracts/clauses/ClauseVerifier.kt create mode 100644 core/src/main/kotlin/com/r3corda/core/contracts/clauses/GroupClauseVerifier.kt create mode 100644 core/src/main/kotlin/com/r3corda/core/contracts/clauses/InterceptorClause.kt create mode 100644 core/src/test/kotlin/com/r3corda/core/contracts/clauses/VerifyClausesTests.kt diff --git a/core/src/main/kotlin/com/r3corda/core/contracts/ContractsDSL.kt b/core/src/main/kotlin/com/r3corda/core/contracts/ContractsDSL.kt index 370db1a055..529ad5f8df 100644 --- a/core/src/main/kotlin/com/r3corda/core/contracts/ContractsDSL.kt +++ b/core/src/main/kotlin/com/r3corda/core/contracts/ContractsDSL.kt @@ -60,14 +60,22 @@ inline fun requireThat(body: Requirements.() -> R) = R.body() //// Authenticated commands /////////////////////////////////////////////////////////////////////////////////////////// /** Filters the command list by type, party and public key all at once. */ -inline fun List>.select(signer: PublicKey? = null, +inline fun Collection>.select(signer: PublicKey? = null, party: Party? = null) = filter { it.value is T }. - filter { if (signer == null) true else it.signers.contains(signer) }. - filter { if (party == null) true else it.signingParties.contains(party) }. + filter { if (signer == null) true else signer in it.signers }. + filter { if (party == null) true else party in it.signingParties }. map { AuthenticatedObject(it.signers, it.signingParties, it.value as T) } -inline fun List>.requireSingleCommand() = try { +/** Filters the command list by type, parties and public keys all at once. */ +inline fun Collection>.select(signers: Collection?, + parties: Collection?) = + filter { it.value is T }. + filter { if (signers == null) true else it.signers.containsAll(signers)}. + filter { if (parties == null) true else it.signingParties.containsAll(parties) }. + map { AuthenticatedObject(it.signers, it.signingParties, it.value as T) } + +inline fun Collection>.requireSingleCommand() = try { select().single() } catch (e: NoSuchElementException) { throw IllegalStateException("Required ${T::class.qualifiedName} command") // Better error message. @@ -106,9 +114,10 @@ fun List>.getTimestampByName(vararg names: Stri */ @Throws(IllegalArgumentException::class) // TODO: Can we have a common Move command for all contracts and avoid the reified type parameter here? -inline fun verifyMoveCommand(inputs: List, tx: TransactionForContract) { - return verifyMoveCommand(inputs, tx.commands) -} +inline fun verifyMoveCommand(inputs: List, + tx: TransactionForContract) + : MoveCommand + = verifyMoveCommand(inputs, tx.commands) /** * Simple functionality for verifying a move command. Verifies that each input has a signature from its owning key. @@ -116,13 +125,17 @@ inline fun verifyMoveCommand(inputs: List verifyMoveCommand(inputs: List, commands: List>) { +inline fun verifyMoveCommand(inputs: List, + commands: List>) + : MoveCommand { // Now check the digital signatures on the move command. Every input has an owning public key, and we must // see a signature from each of those keys. The actual signatures have been verified against the transaction // data by the platform before execution. val owningPubKeys = inputs.map { it.owner }.toSet() - val keysThatSigned = commands.requireSingleCommand().signers.toSet() + val command = commands.requireSingleCommand() + val keysThatSigned = command.signers.toSet() requireThat { "the owning keys are the same as the signing keys" by keysThatSigned.containsAll(owningPubKeys) } + return command.value } diff --git a/core/src/main/kotlin/com/r3corda/core/contracts/clauses/ClauseVerifier.kt b/core/src/main/kotlin/com/r3corda/core/contracts/clauses/ClauseVerifier.kt new file mode 100644 index 0000000000..009115ed25 --- /dev/null +++ b/core/src/main/kotlin/com/r3corda/core/contracts/clauses/ClauseVerifier.kt @@ -0,0 +1,92 @@ +package com.r3corda.core.contracts.clauses + +import com.r3corda.core.contracts.* +import java.util.* + +interface Clause { + /** Classes for commands which must ALL be present in transaction for this clause to be triggered */ + val requiredCommands: Set> + /** Behaviour if this clause is matched */ + val ifNotMatched: MatchBehaviour + /** Behaviour if this clause is not matches */ + val ifMatched: MatchBehaviour +} + +enum class MatchBehaviour { + CONTINUE, + END, + ERROR +} + +interface SingleVerify { + /** + * Verify the transaction matches the conditions from this clause. For example, a "no zero amount output" clause + * would check each of the output states that it applies to, looking for a zero amount, and throw IllegalStateException + * if any matched. + * + * @return the set of commands that are consumed IF this clause is matched, and cannot be used to match a + * later clause. This would normally be all commands matching "requiredCommands" for this clause, but some + * verify() functions may do further filtering on possible matches, and return a subset. This may also include + * commands that were not required (for example the Exit command for fungible assets is optional). + */ + @Throws(IllegalStateException::class) + fun verify(tx: TransactionForContract, + commands: Collection>): Set + +} + + +interface SingleClause : Clause, SingleVerify + +/** + * Abstract superclass for clause-based contracts to extend, which provides a verify() function + * that delegates to the supplied list of clauses. + */ +abstract class ClauseVerifier : Contract { + abstract val clauses: List + abstract fun extractCommands(tx: TransactionForContract): Collection> + override fun verify(tx: TransactionForContract) = verifyClauses(tx, clauses, extractCommands(tx)) +} + +/** + * Verify a transaction against the given list of clauses. + * + * @param tx transaction to be verified. + * @param clauses the clauses to verify. + * @param T common supertype of commands to extract from the transaction, which are of relevance to these clauses. + */ +inline fun verifyClauses(tx: TransactionForContract, + clauses: List) + = verifyClauses(tx, clauses, tx.commands.select()) + +/** + * Verify a transaction against the given list of clauses. + * + * @param tx transaction to be verified. + * @param clauses the clauses to verify. + * @param commands commands extracted from the transaction, which are relevant to the + * clauses. + */ +fun verifyClauses(tx: TransactionForContract, + clauses: List, + commands: Collection>) { + val unmatchedCommands = ArrayList(commands.map { it.value }) + + verify@ for (clause in clauses) { + val matchBehaviour = if (unmatchedCommands.map { command -> command.javaClass }.containsAll(clause.requiredCommands)) { + unmatchedCommands.removeAll(clause.verify(tx, commands)) + clause.ifMatched + } else { + clause.ifNotMatched + } + + when (matchBehaviour) { + MatchBehaviour.ERROR -> throw IllegalStateException() + MatchBehaviour.CONTINUE -> { + } + MatchBehaviour.END -> break@verify + } + } + + require(unmatchedCommands.isEmpty()) { "All commands must be matched at end of execution." } +} \ No newline at end of file diff --git a/core/src/main/kotlin/com/r3corda/core/contracts/clauses/GroupClauseVerifier.kt b/core/src/main/kotlin/com/r3corda/core/contracts/clauses/GroupClauseVerifier.kt new file mode 100644 index 0000000000..38bcf37262 --- /dev/null +++ b/core/src/main/kotlin/com/r3corda/core/contracts/clauses/GroupClauseVerifier.kt @@ -0,0 +1,82 @@ +package com.r3corda.core.contracts.clauses + +import com.r3corda.core.contracts.AuthenticatedObject +import com.r3corda.core.contracts.CommandData +import com.r3corda.core.contracts.ContractState +import com.r3corda.core.contracts.TransactionForContract +import java.util.* + +interface GroupVerify { + /** + * + * @return the set of commands that are consumed IF this clause is matched, and cannot be used to match a + * later clause. + */ + fun verify(tx: TransactionForContract, + inputs: List, + outputs: List, + commands: Collection>, + token: T): Set +} + +interface GroupClause : Clause, GroupVerify + +abstract class GroupClauseVerifier : SingleClause { + abstract val clauses: List> + override val requiredCommands: Set> + get() = emptySet() + + abstract fun extractGroups(tx: TransactionForContract): List> + + override fun verify(tx: TransactionForContract, commands: Collection>): Set { + val groups = extractGroups(tx) + val matchedCommands = HashSet() + val unmatchedCommands = ArrayList(commands.map { it.value }) + + for ((inputs, outputs, token) in groups) { + val temp = verifyGroup(commands, inputs, outputs, token, tx, unmatchedCommands) + matchedCommands.addAll(temp) + unmatchedCommands.removeAll(temp) + } + + return matchedCommands + } + + /** + * Verify a subset of a transaction's inputs and outputs matches the conditions from this clause. For example, a + * "no zero amount output" clause would check each of the output states within the group, looking for a zero amount, + * and throw IllegalStateException if any matched. + * + * @param commands the full set of commands which apply to this contract. + * @param inputs input states within this group. + * @param outputs output states within this group. + * @param token the object used as a key when grouping states. + * @param unmatchedCommands commands which have not yet been matched within this group. + * @return matchedCommands commands which are matched during the verification process. + */ + @Throws(IllegalStateException::class) + private fun verifyGroup(commands: Collection>, + inputs: List, + outputs: List, + token: T, + tx: TransactionForContract, + unmatchedCommands: List): Set { + val matchedCommands = HashSet() + verify@ for (clause in clauses) { + val matchBehaviour = if (unmatchedCommands.map { command -> command.javaClass }.containsAll(clause.requiredCommands)) { + matchedCommands.addAll(clause.verify(tx, inputs, outputs, commands, token)) + clause.ifMatched + } else { + clause.ifNotMatched + } + + when (matchBehaviour) { + MatchBehaviour.ERROR -> throw IllegalStateException() + MatchBehaviour.CONTINUE -> { + } + MatchBehaviour.END -> break@verify + } + } + return matchedCommands + } +} \ No newline at end of file diff --git a/core/src/main/kotlin/com/r3corda/core/contracts/clauses/InterceptorClause.kt b/core/src/main/kotlin/com/r3corda/core/contracts/clauses/InterceptorClause.kt new file mode 100644 index 0000000000..9f9f4d3625 --- /dev/null +++ b/core/src/main/kotlin/com/r3corda/core/contracts/clauses/InterceptorClause.kt @@ -0,0 +1,28 @@ +package com.r3corda.core.contracts.clauses + +import com.r3corda.core.contracts.AuthenticatedObject +import com.r3corda.core.contracts.CommandData +import com.r3corda.core.contracts.TransactionForContract +import java.util.* + +/** + * A clause which intercepts calls to a wrapped clause, and passes them through verification + * only from a pre-clause. This is similar to an inceptor in aspect orientated programming. + */ +data class InterceptorClause( + val preclause: SingleVerify, + val clause: SingleClause +) : SingleClause { + override val ifNotMatched: MatchBehaviour + get() = clause.ifNotMatched + override val ifMatched: MatchBehaviour + get() = clause.ifMatched + override val requiredCommands: Set> + get() = clause.requiredCommands + + override fun verify(tx: TransactionForContract, commands: Collection>): Set { + val consumed = HashSet(preclause.verify(tx, commands)) + consumed.addAll(clause.verify(tx, commands)) + return consumed + } +} \ No newline at end of file diff --git a/core/src/test/kotlin/com/r3corda/core/contracts/clauses/VerifyClausesTests.kt b/core/src/test/kotlin/com/r3corda/core/contracts/clauses/VerifyClausesTests.kt new file mode 100644 index 0000000000..b97d943745 --- /dev/null +++ b/core/src/test/kotlin/com/r3corda/core/contracts/clauses/VerifyClausesTests.kt @@ -0,0 +1,114 @@ +package com.r3corda.core.contracts.clauses + +import com.r3corda.core.contracts.* +import com.r3corda.core.crypto.SecureHash +import org.junit.Test +import kotlin.test.assertFailsWith + +/** + * Tests for the clause verifier. + */ +class VerifyClausesTests { + /** Check that if there's no clauses, verification passes. */ + @Test + fun `passes empty clauses`() { + val tx = TransactionForContract(emptyList(), emptyList(), emptyList(), emptyList(), SecureHash.randomSHA256()) + verifyClauses(tx, emptyList(), emptyList>()) + } + + /** Very simple check that the function doesn't error when given any clause */ + @Test + fun minimal() { + val clause = object : SingleClause { + override val requiredCommands: Set> + get() = emptySet() + override val ifMatched: MatchBehaviour + get() = MatchBehaviour.CONTINUE + override val ifNotMatched: MatchBehaviour + get() = MatchBehaviour.CONTINUE + + override fun verify(tx: TransactionForContract, commands: Collection>): Set = emptySet() + } + val tx = TransactionForContract(emptyList(), emptyList(), emptyList(), emptyList(), SecureHash.randomSHA256()) + verifyClauses(tx, listOf(clause), emptyList>()) + } + + /** Check that when there are no required commands, a clause always matches */ + @Test + fun emptyAlwaysMatches() { + val clause = object : SingleClause { + override val requiredCommands: Set> + get() = emptySet() + override val ifMatched: MatchBehaviour + get() = MatchBehaviour.CONTINUE + override val ifNotMatched: MatchBehaviour + get() = MatchBehaviour.ERROR + + override fun verify(tx: TransactionForContract, commands: Collection>): Set = emptySet() + } + val tx = TransactionForContract(emptyList(), emptyList(), emptyList(), emptyList(), SecureHash.randomSHA256()) + // This would error if it wasn't matched + verifyClauses(tx, listOf(clause), emptyList>()) + } + + @Test + fun errorSuperfluousCommands() { + val clause = object : SingleClause { + override val requiredCommands: Set> + get() = emptySet() + override val ifMatched: MatchBehaviour + get() = MatchBehaviour.ERROR + override val ifNotMatched: MatchBehaviour + get() = MatchBehaviour.CONTINUE + + override fun verify(tx: TransactionForContract, commands: Collection>): Set + = emptySet() + } + val command = AuthenticatedObject(emptyList(), emptyList(), DummyContract.Commands.Create()) + val tx = TransactionForContract(emptyList(), emptyList(), emptyList(), listOf(command), SecureHash.randomSHA256()) + // The clause is matched, but doesn't mark the command as consumed, so this should error + assertFailsWith { verifyClauses(tx, listOf(clause), listOf(command)) } + } + + /** Check triggering of error if matched */ + @Test + fun errorMatched() { + val clause = object : SingleClause { + override val requiredCommands: Set> + get() = setOf(DummyContract.Commands.Create::class.java) + override val ifMatched: MatchBehaviour + get() = MatchBehaviour.ERROR + override val ifNotMatched: MatchBehaviour + get() = MatchBehaviour.CONTINUE + + override fun verify(tx: TransactionForContract, commands: Collection>): Set + = commands.select().map { it.value }.toSet() + } + var tx = TransactionForContract(emptyList(), emptyList(), emptyList(), emptyList(), SecureHash.randomSHA256()) + + // This should pass as it doesn't match + verifyClauses(tx, listOf(clause), emptyList()) + + // This matches and should throw an error + val command = AuthenticatedObject(emptyList(), emptyList(), DummyContract.Commands.Create()) + tx = TransactionForContract(emptyList(), emptyList(), emptyList(), listOf(command), SecureHash.randomSHA256()) + assertFailsWith { verifyClauses(tx, listOf(clause), listOf(command)) } + } + + /** Check triggering of error if unmatched */ + @Test + fun errorUnmatched() { + val clause = object : SingleClause { + override val requiredCommands: Set> + get() = setOf(DummyContract.Commands.Create::class.java) + override val ifMatched: MatchBehaviour + get() = MatchBehaviour.CONTINUE + override val ifNotMatched: MatchBehaviour + get() = MatchBehaviour.ERROR + + override fun verify(tx: TransactionForContract, commands: Collection>): Set = emptySet() + } + val tx = TransactionForContract(emptyList(), emptyList(), emptyList(), emptyList(), SecureHash.randomSHA256()) + assertFailsWith { verifyClauses(tx, listOf(clause), emptyList()) } + } +} \ No newline at end of file