From 340ea9c11e8e913d56c7d79ba03606e40d7c6a24 Mon Sep 17 00:00:00 2001 From: willhr3 Date: Tue, 28 Apr 2020 13:18:47 +0100 Subject: [PATCH 1/8] Add ent dependency --- build.gradle | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/build.gradle b/build.gradle index 55c1ba59..fd710345 100644 --- a/build.gradle +++ b/build.gradle @@ -4,6 +4,8 @@ buildscript { ext { corda_release_group = 'net.corda' corda_release_version = '4.3' + corda_ent_release_group = 'com.r3.corda' + corda_ent_release_version = '4.5' tokens_release_group = "com.r3.corda.lib.tokens" tokens_release_version = "1.2-SNAPSHOT" corda_gradle_plugins_version = '5.0.8' @@ -13,6 +15,7 @@ buildscript { slf4j_version = '1.7.25' log4j_version = '2.9.1' jackson_version = '2.9.0' + quasar_version = '0.7.11_r3' confidential_id_release_group = "com.r3.corda.lib.ci" confidential_id_release_version = "1.0" aetherVersion = '1.0.0.v20140518' @@ -24,7 +27,10 @@ buildscript { jcenter() mavenCentral() mavenLocal() + maven { url "https://ci-artifactory.corda.r3cev.com/artifactory/corda-dependencies" } maven { url "http://ci-artifactory.corda.r3cev.com/artifactory/corda-releases" } + maven { url "https://ci-artifactory.corda.r3cev.com/artifactory/corda-dependencies-dev" } + maven { url "https://ci-artifactory.corda.r3cev.com/artifactory/corda-dev" } maven { url "https://repo.gradle.org/gradle/libs-releases-local/" } } @@ -71,9 +77,12 @@ subprojects { maven { url "http://ci-artifactory.corda.r3cev.com/artifactory/corda-lib" } maven { url "http://ci-artifactory.corda.r3cev.com/artifactory/corda-lib-dev" } maven { url "http://ci-artifactory.corda.r3cev.com/artifactory/corda-lib" } + maven { url "https://ci-artifactory.corda.r3cev.com/artifactory/corda-dependencies" } + maven { url "https://ci-artifactory.corda.r3cev.com/artifactory/corda-dependencies-dev" } maven { url "https://repo.gradle.org/gradle/libs-releases-local/" } } + apply plugin: 'kotlin' tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile) { From d3eec6b2bd88e78b070a1690efd5dc8b45cac576 Mon Sep 17 00:00:00 2001 From: willhr3 Date: Tue, 28 Apr 2020 14:17:43 +0100 Subject: [PATCH 2/8] Implement the DescribableContract for fungible/ non-fungible --- contracts/build.gradle | 4 +- .../tokens/contracts/AbstractTokenContract.kt | 11 +++-- .../tokens/contracts/FungibleTokenContract.kt | 44 ++++++++++++++++++- .../contracts/NonFungibleTokenContract.kt | 25 ++++++++--- modules/contracts-for-testing/build.gradle | 2 +- modules/money/build.gradle | 2 +- modules/selection/build.gradle | 6 +-- workflows/build.gradle | 4 +- 8 files changed, 77 insertions(+), 21 deletions(-) diff --git a/contracts/build.gradle b/contracts/build.gradle index fda7af50..918c5706 100644 --- a/contracts/build.gradle +++ b/contracts/build.gradle @@ -23,7 +23,7 @@ dependencies { compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" // Corda dependencies. - cordaCompile ("$corda_release_group:corda-core:$corda_release_version"){ + cordaCompile ("$corda_ent_release_group:corda-core:$corda_ent_release_version"){ changing = true } @@ -33,7 +33,7 @@ dependencies { // Testing. testCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version" testCompile "junit:junit:$junit_version" - testCompile "$corda_release_group:corda-node-driver:$corda_release_version" + testCompile "$corda_ent_release_group:corda-node-driver:$corda_ent_release_version" testCompile project(":modules:money") testCompile project(":modules:contracts-for-testing") } diff --git a/contracts/src/main/kotlin/com/r3/corda/lib/tokens/contracts/AbstractTokenContract.kt b/contracts/src/main/kotlin/com/r3/corda/lib/tokens/contracts/AbstractTokenContract.kt index a018b8e8..c1fd8c22 100644 --- a/contracts/src/main/kotlin/com/r3/corda/lib/tokens/contracts/AbstractTokenContract.kt +++ b/contracts/src/main/kotlin/com/r3/corda/lib/tokens/contracts/AbstractTokenContract.kt @@ -35,7 +35,8 @@ abstract class AbstractTokenContract : Contract { inputs: List>, outputs: List>, attachments: List, - references: List> + references: List>, + summary: List ) { // Get the JAR which implements the TokenType for this group. val jarHash: SecureHash? = verifyAllTokensUseSameTypeJar( @@ -49,7 +50,7 @@ abstract class AbstractTokenContract : Contract { // Issuances should only contain one issue command. is IssueTokenCommand -> verifyIssue(commands.single(), inputs, outputs, attachments, references) // Moves may contain more than one move command. - is MoveTokenCommand -> verifyMove(commands, inputs, outputs, attachments, references) + is MoveTokenCommand -> verifyMove(commands, inputs, outputs, attachments, references, summary) // Redeems must only contain one redeem command. is RedeemTokenCommand -> verifyRedeem(commands.single(), inputs, outputs, attachments, references) } @@ -77,7 +78,8 @@ abstract class AbstractTokenContract : Contract { inputs: List>, outputs: List>, attachments: List, - references: List> + references: List>, + summary: List ) /** @@ -94,6 +96,7 @@ abstract class AbstractTokenContract : Contract { ) final override fun verify(tx: LedgerTransaction) { + val summaryOnTx = tx.summaries // Group token amounts by token type. We need to do this because tokens of different types need to be // verified separately. This works for the same token type with different issuers, or different token types // altogether. The grouping function returns a list containing groups of input and output states grouped by @@ -120,7 +123,7 @@ abstract class AbstractTokenContract : Contract { "TokenCommand type per group! For example: You cannot map an Issue AND a Move command " + "to one group of tokens in a transaction." } - dispatchOnCommand(commands, group.inputs, group.outputs, tx.attachments, tx.references) + dispatchOnCommand(commands, group.inputs, group.outputs, tx.attachments, tx.references, tx.summaries) } diff --git a/contracts/src/main/kotlin/com/r3/corda/lib/tokens/contracts/FungibleTokenContract.kt b/contracts/src/main/kotlin/com/r3/corda/lib/tokens/contracts/FungibleTokenContract.kt index 09411d8b..175ffadc 100644 --- a/contracts/src/main/kotlin/com/r3/corda/lib/tokens/contracts/FungibleTokenContract.kt +++ b/contracts/src/main/kotlin/com/r3/corda/lib/tokens/contracts/FungibleTokenContract.kt @@ -1,12 +1,17 @@ package com.r3.corda.lib.tokens.contracts +import com.r3.corda.lib.tokens.contracts.commands.IssueTokenCommand +import com.r3.corda.lib.tokens.contracts.commands.MoveTokenCommand +import com.r3.corda.lib.tokens.contracts.commands.RedeemTokenCommand import com.r3.corda.lib.tokens.contracts.commands.TokenCommand import com.r3.corda.lib.tokens.contracts.states.AbstractToken import com.r3.corda.lib.tokens.contracts.states.FungibleToken import com.r3.corda.lib.tokens.contracts.types.IssuedTokenType import com.r3.corda.lib.tokens.contracts.utilities.sumTokenStatesOrZero import net.corda.core.contracts.* +import net.corda.core.crypto.toStringShort import net.corda.core.internal.uncheckedCast +import net.corda.core.transactions.LedgerTransaction import java.security.PublicKey /** @@ -22,7 +27,7 @@ import java.security.PublicKey * to call the super method to handle the existing commands. * 3. Add a method to handle the new command in the new sub-class contract. */ -open class FungibleTokenContract : AbstractTokenContract() { +open class FungibleTokenContract : AbstractTokenContract(), DescribableContract { override val accepts: Class get() = uncheckedCast(FungibleToken::class.java) companion object { @@ -65,8 +70,11 @@ open class FungibleTokenContract : AbstractTokenContract() { inputs: List>, outputs: List>, attachments: List, - references: List> + references: List>, + summary: List ) { + val ourSummary = describeTransaction(inputs.map{ it.state}, outputs.map { it.state }, moveCommands, attachments, references) + require(ourSummary == summary) { "The summary generated by the contract: '${ourSummary}' does not match the summary present in the tx: '${summary}'" } // Commands are grouped by Token Type, so we just need a token reference. val issuedToken: IssuedTokenType = moveCommands.first().value.token // There must be inputs and outputs present. @@ -138,4 +146,36 @@ open class FungibleTokenContract : AbstractTokenContract() { } } } + + override fun describe(ltx: LedgerTransaction): List { + return emptyList() + } + + override fun describeTransaction( + inputs: List>, + outputs: List>, + commands: List>, + attachments: List, + references: List>): List { + return when(commands.first().value) { + //verify the type jar presence and correctness + // Issuances should only contain one issue command. + is IssueTokenCommand -> listOf("") + // Moves may contain more than one move command. + is MoveTokenCommand -> constructMoveDescription(inputs, outputs) + // Redeems must only contain one redeem command. + is RedeemTokenCommand -> listOf("I AM A REDEPMPTION SONG)") + else -> emptyList() + } + } + + private fun constructMoveDescription(inputs: List>, outputs: List>): List { + val moveFrom = inputs.first().asFungibleToken().holder.owningKey + val moveTo = (outputs.map { it.asFungibleToken().holder }).firstOrNull { p -> p.owningKey != moveFrom }?.owningKey ?: throw IllegalArgumentException("") + val amountToMove = outputs.filter { p -> p.asFungibleToken().holder.owningKey != moveFrom }.first().asFungibleToken().amount + return listOf("Move ${amountToMove.toDecimal()} ${amountToMove.token.tokenType.tokenIdentifier} from key ${moveFrom.toStringShort()} to key ${moveTo.toStringShort()}") + } + + private fun TransactionState.asFungibleToken() = this.data as FungibleToken + } diff --git a/contracts/src/main/kotlin/com/r3/corda/lib/tokens/contracts/NonFungibleTokenContract.kt b/contracts/src/main/kotlin/com/r3/corda/lib/tokens/contracts/NonFungibleTokenContract.kt index 848c8902..e86bf174 100644 --- a/contracts/src/main/kotlin/com/r3/corda/lib/tokens/contracts/NonFungibleTokenContract.kt +++ b/contracts/src/main/kotlin/com/r3/corda/lib/tokens/contracts/NonFungibleTokenContract.kt @@ -2,17 +2,15 @@ package com.r3.corda.lib.tokens.contracts import com.r3.corda.lib.tokens.contracts.commands.TokenCommand import com.r3.corda.lib.tokens.contracts.states.NonFungibleToken -import net.corda.core.contracts.Attachment -import net.corda.core.contracts.CommandWithParties -import net.corda.core.contracts.ContractState -import net.corda.core.contracts.StateAndRef +import net.corda.core.contracts.* import net.corda.core.internal.uncheckedCast +import net.corda.core.transactions.LedgerTransaction import java.security.PublicKey /** * See kdoc for [FungibleTokenContract]. */ -class NonFungibleTokenContract : AbstractTokenContract() { +class NonFungibleTokenContract : AbstractTokenContract(), DescribableContract { override val accepts: Class get() = uncheckedCast(NonFungibleToken::class.java) @@ -47,7 +45,8 @@ class NonFungibleTokenContract : AbstractTokenContract() { inputs: List>, outputs: List>, attachments: List, - references: List> + references: List>, + summary: List ) { // There must be inputs and outputs present. require(inputs.isNotEmpty()) { "When moving a non fungible token, there must be one input state present." } @@ -90,4 +89,18 @@ class NonFungibleTokenContract : AbstractTokenContract() { "Holders of redeemed states must be the signing parties." } } + + override fun describe(ltx: LedgerTransaction): List { + return emptyList() + } + + override fun describeTransaction( + inputs: List>, + outputs: List>, + commands: List>, + attachments: List, + references: List> + ): List { + TODO("Not yet implemented") + } } \ No newline at end of file diff --git a/modules/contracts-for-testing/build.gradle b/modules/contracts-for-testing/build.gradle index 1082ff37..158e808c 100644 --- a/modules/contracts-for-testing/build.gradle +++ b/modules/contracts-for-testing/build.gradle @@ -32,7 +32,7 @@ dependencies { compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" // Corda dependencies. - cordaCompile ("$corda_release_group:corda-core:$corda_release_version"){ + cordaCompile ("$corda_ent_release_group:corda-core:$corda_ent_release_version"){ changing = true } diff --git a/modules/money/build.gradle b/modules/money/build.gradle index ed0f8a51..e3591167 100644 --- a/modules/money/build.gradle +++ b/modules/money/build.gradle @@ -36,7 +36,7 @@ dependencies { compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" // Corda dependencies. - cordaCompile ("$corda_release_group:corda-core:$corda_release_version"){ + cordaCompile ("$corda_ent_release_group:corda-core:$corda_ent_release_version"){ changing = true } diff --git a/modules/selection/build.gradle b/modules/selection/build.gradle index 866f213a..20e2de19 100644 --- a/modules/selection/build.gradle +++ b/modules/selection/build.gradle @@ -32,11 +32,11 @@ dependencies { compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" // Corda dependencies. - cordaCompile ("$corda_release_group:corda-core:$corda_release_version"){ + cordaCompile ("$corda_ent_release_group:corda-core:$corda_ent_release_version"){ changing = true } // Corda dependencies. - cordaCompile ("$corda_release_group:corda-node-api:$corda_release_version"){ + cordaCompile ("$corda_ent_release_group:corda-node-api:$corda_ent_release_version"){ changing = true } @@ -44,7 +44,7 @@ dependencies { testCompile "org.apache.logging.log4j:log4j-slf4j-impl:${log4j_version}" // Testing. - testCompile "$corda_release_group:corda-node-driver:$corda_release_version" + testCompile "$corda_ent_release_group:corda-node-driver:$corda_ent_release_version" testCompile "junit:junit:$junit_version" testCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version" diff --git a/workflows/build.gradle b/workflows/build.gradle index 2e669943..42cada9d 100644 --- a/workflows/build.gradle +++ b/workflows/build.gradle @@ -46,7 +46,7 @@ dependencies { compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" // Corda dependencies. - cordaCompile("$corda_release_group:corda-core:$corda_release_version") { + cordaCompile("$corda_ent_release_group:corda-core:$corda_ent_release_version") { changing = true } @@ -54,7 +54,7 @@ dependencies { testCompile "org.apache.logging.log4j:log4j-slf4j-impl:${log4j_version}" // Testing. - testCompile "$corda_release_group:corda-node-driver:$corda_release_version" + testCompile "$corda_ent_release_group:corda-node-driver:$corda_ent_release_version" testCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version" testCompile "junit:junit:$junit_version" From c4e9fec86bc1227a4cb9dc1a3d70a0a351933df7 Mon Sep 17 00:00:00 2001 From: willhr3 Date: Tue, 5 May 2020 17:16:53 +0100 Subject: [PATCH 3/8] Implement new describeTx method --- .../tokens/contracts/AbstractTokenContract.kt | 4 +--- .../tokens/contracts/FungibleTokenContract.kt | 19 +++++++++++-------- .../contracts/NonFungibleTokenContract.kt | 6 +++--- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/contracts/src/main/kotlin/com/r3/corda/lib/tokens/contracts/AbstractTokenContract.kt b/contracts/src/main/kotlin/com/r3/corda/lib/tokens/contracts/AbstractTokenContract.kt index c1fd8c22..c9bdcb86 100644 --- a/contracts/src/main/kotlin/com/r3/corda/lib/tokens/contracts/AbstractTokenContract.kt +++ b/contracts/src/main/kotlin/com/r3/corda/lib/tokens/contracts/AbstractTokenContract.kt @@ -96,7 +96,6 @@ abstract class AbstractTokenContract : Contract { ) final override fun verify(tx: LedgerTransaction) { - val summaryOnTx = tx.summaries // Group token amounts by token type. We need to do this because tokens of different types need to be // verified separately. This works for the same token type with different issuers, or different token types // altogether. The grouping function returns a list containing groups of input and output states grouped by @@ -123,12 +122,11 @@ abstract class AbstractTokenContract : Contract { "TokenCommand type per group! For example: You cannot map an Issue AND a Move command " + "to one group of tokens in a transaction." } - dispatchOnCommand(commands, group.inputs, group.outputs, tx.attachments, tx.references, tx.summaries) + dispatchOnCommand(commands, group.inputs, group.outputs, tx.attachments, tx.references, tx.summary) } val allMatchedCommands = groupsAndCommands.map { it.first.first() }.toSet() - val extraCommands = (tokenCommands - allMatchedCommands).toSet() } private fun groupMatchesCommand(it: CommandWithParties, group: IndexedInOutGroup): Boolean { diff --git a/contracts/src/main/kotlin/com/r3/corda/lib/tokens/contracts/FungibleTokenContract.kt b/contracts/src/main/kotlin/com/r3/corda/lib/tokens/contracts/FungibleTokenContract.kt index 175ffadc..154a4e30 100644 --- a/contracts/src/main/kotlin/com/r3/corda/lib/tokens/contracts/FungibleTokenContract.kt +++ b/contracts/src/main/kotlin/com/r3/corda/lib/tokens/contracts/FungibleTokenContract.kt @@ -9,6 +9,7 @@ import com.r3.corda.lib.tokens.contracts.states.FungibleToken import com.r3.corda.lib.tokens.contracts.types.IssuedTokenType import com.r3.corda.lib.tokens.contracts.utilities.sumTokenStatesOrZero import net.corda.core.contracts.* +import net.corda.core.crypto.SecureHash import net.corda.core.crypto.toStringShort import net.corda.core.internal.uncheckedCast import net.corda.core.transactions.LedgerTransaction @@ -73,7 +74,7 @@ open class FungibleTokenContract : AbstractTokenContract(), Descr references: List>, summary: List ) { - val ourSummary = describeTransaction(inputs.map{ it.state}, outputs.map { it.state }, moveCommands, attachments, references) + val ourSummary = describeTransaction(inputs.map{ it.state}, outputs.map { it.state }, moveCommands.map { it.value }, attachments.map { it.id }) require(ourSummary == summary) { "The summary generated by the contract: '${ourSummary}' does not match the summary present in the tx: '${summary}'" } // Commands are grouped by Token Type, so we just need a token reference. val issuedToken: IssuedTokenType = moveCommands.first().value.token @@ -152,12 +153,11 @@ open class FungibleTokenContract : AbstractTokenContract(), Descr } override fun describeTransaction( - inputs: List>, - outputs: List>, - commands: List>, - attachments: List, - references: List>): List { - return when(commands.first().value) { + inputs: List>, + outputs: List>, + commands: List, + attachments: List): List { + return when(commands.first()) { //verify the type jar presence and correctness // Issuances should only contain one issue command. is IssueTokenCommand -> listOf("") @@ -169,11 +169,14 @@ open class FungibleTokenContract : AbstractTokenContract(), Descr } } + private fun constructMoveDescription(inputs: List>, outputs: List>): List { val moveFrom = inputs.first().asFungibleToken().holder.owningKey val moveTo = (outputs.map { it.asFungibleToken().holder }).firstOrNull { p -> p.owningKey != moveFrom }?.owningKey ?: throw IllegalArgumentException("") val amountToMove = outputs.filter { p -> p.asFungibleToken().holder.owningKey != moveFrom }.first().asFungibleToken().amount - return listOf("Move ${amountToMove.toDecimal()} ${amountToMove.token.tokenType.tokenIdentifier} from key ${moveFrom.toStringShort()} to key ${moveTo.toStringShort()}") + amountToMove.displayTokenSize + amountToMove.quantity + return listOf("Move ${amountToMove.toDecimal()} ${amountToMove.token.tokenType.tokenIdentifier} from key: ${moveFrom.toStringShort()} to key: ${moveTo.toStringShort()}") } private fun TransactionState.asFungibleToken() = this.data as FungibleToken diff --git a/contracts/src/main/kotlin/com/r3/corda/lib/tokens/contracts/NonFungibleTokenContract.kt b/contracts/src/main/kotlin/com/r3/corda/lib/tokens/contracts/NonFungibleTokenContract.kt index e86bf174..f277cd69 100644 --- a/contracts/src/main/kotlin/com/r3/corda/lib/tokens/contracts/NonFungibleTokenContract.kt +++ b/contracts/src/main/kotlin/com/r3/corda/lib/tokens/contracts/NonFungibleTokenContract.kt @@ -3,6 +3,7 @@ package com.r3.corda.lib.tokens.contracts import com.r3.corda.lib.tokens.contracts.commands.TokenCommand import com.r3.corda.lib.tokens.contracts.states.NonFungibleToken import net.corda.core.contracts.* +import net.corda.core.crypto.SecureHash import net.corda.core.internal.uncheckedCast import net.corda.core.transactions.LedgerTransaction import java.security.PublicKey @@ -97,9 +98,8 @@ class NonFungibleTokenContract : AbstractTokenContract(), Desc override fun describeTransaction( inputs: List>, outputs: List>, - commands: List>, - attachments: List, - references: List> + commands: List, + attachments: List ): List { TODO("Not yet implemented") } From b0c4d1360531b17c436cf0918fb58f9cee0da724 Mon Sep 17 00:00:00 2001 From: adcockalexander Date: Thu, 30 Jul 2020 11:53:57 +0100 Subject: [PATCH 4/8] Move to 4.6-SNAPSHOT, add 'haltForExternalSigning' support --- build.gradle | 4 +- contracts/build.gradle | 6 +-- .../tokens/contracts/FungibleTokenContract.kt | 5 +-- .../contracts/NonFungibleTokenContract.kt | 4 -- modules/contracts-for-testing/build.gradle | 2 +- modules/money/build.gradle | 2 +- modules/selection/build.gradle | 6 +-- workflows/build.gradle | 13 +++--- .../flows/move/AbstractMoveTokensFlow.kt | 6 ++- .../ConfidentialMoveFungibleTokensFlow.kt | 7 +++- .../ConfidentialMoveNonFungibleTokensFlow.kt | 7 +++- .../flows/move/MoveFungibleTokensFlow.kt | 5 ++- .../flows/move/MoveNonFungibleTokensFlow.kt | 5 ++- .../workflows/flows/move/MoveTokensFlow.kt | 5 ++- .../tokens/workflows/flows/rpc/MoveTokens.kt | 20 +++++++-- .../finality/ObserverAwareFinalityFlow.kt | 41 ++++++++++++++++--- 16 files changed, 95 insertions(+), 43 deletions(-) diff --git a/build.gradle b/build.gradle index fd710345..da24b983 100644 --- a/build.gradle +++ b/build.gradle @@ -3,9 +3,7 @@ import static org.gradle.api.JavaVersion.VERSION_1_8 buildscript { ext { corda_release_group = 'net.corda' - corda_release_version = '4.3' - corda_ent_release_group = 'com.r3.corda' - corda_ent_release_version = '4.5' + corda_release_version = '4.6-SNAPSHOT' tokens_release_group = "com.r3.corda.lib.tokens" tokens_release_version = "1.2-SNAPSHOT" corda_gradle_plugins_version = '5.0.8' diff --git a/contracts/build.gradle b/contracts/build.gradle index 918c5706..0e3ddf06 100644 --- a/contracts/build.gradle +++ b/contracts/build.gradle @@ -1,7 +1,7 @@ apply plugin: 'kotlin-jpa' apply plugin: 'net.corda.plugins.cordapp' -if (!(corda_release_version in ['4.1'])) { +if (!(corda_release_version in ['4.1', '4.6-SNAPSHOT'])) { apply from: "${rootProject.projectDir}/deterministic.gradle" } @@ -23,7 +23,7 @@ dependencies { compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" // Corda dependencies. - cordaCompile ("$corda_ent_release_group:corda-core:$corda_ent_release_version"){ + cordaCompile ("$corda_release_group:corda-core:$corda_release_version"){ changing = true } @@ -33,7 +33,7 @@ dependencies { // Testing. testCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version" testCompile "junit:junit:$junit_version" - testCompile "$corda_ent_release_group:corda-node-driver:$corda_ent_release_version" + testCompile "$corda_release_group:corda-node-driver:$corda_release_version" testCompile project(":modules:money") testCompile project(":modules:contracts-for-testing") } diff --git a/contracts/src/main/kotlin/com/r3/corda/lib/tokens/contracts/FungibleTokenContract.kt b/contracts/src/main/kotlin/com/r3/corda/lib/tokens/contracts/FungibleTokenContract.kt index 154a4e30..e3930acf 100644 --- a/contracts/src/main/kotlin/com/r3/corda/lib/tokens/contracts/FungibleTokenContract.kt +++ b/contracts/src/main/kotlin/com/r3/corda/lib/tokens/contracts/FungibleTokenContract.kt @@ -13,6 +13,7 @@ import net.corda.core.crypto.SecureHash import net.corda.core.crypto.toStringShort import net.corda.core.internal.uncheckedCast import net.corda.core.transactions.LedgerTransaction +import net.corda.core.contracts.DescribableContract import java.security.PublicKey /** @@ -148,10 +149,6 @@ open class FungibleTokenContract : AbstractTokenContract(), Descr } } - override fun describe(ltx: LedgerTransaction): List { - return emptyList() - } - override fun describeTransaction( inputs: List>, outputs: List>, diff --git a/contracts/src/main/kotlin/com/r3/corda/lib/tokens/contracts/NonFungibleTokenContract.kt b/contracts/src/main/kotlin/com/r3/corda/lib/tokens/contracts/NonFungibleTokenContract.kt index f277cd69..a99c83cc 100644 --- a/contracts/src/main/kotlin/com/r3/corda/lib/tokens/contracts/NonFungibleTokenContract.kt +++ b/contracts/src/main/kotlin/com/r3/corda/lib/tokens/contracts/NonFungibleTokenContract.kt @@ -91,10 +91,6 @@ class NonFungibleTokenContract : AbstractTokenContract(), Desc } } - override fun describe(ltx: LedgerTransaction): List { - return emptyList() - } - override fun describeTransaction( inputs: List>, outputs: List>, diff --git a/modules/contracts-for-testing/build.gradle b/modules/contracts-for-testing/build.gradle index 158e808c..1082ff37 100644 --- a/modules/contracts-for-testing/build.gradle +++ b/modules/contracts-for-testing/build.gradle @@ -32,7 +32,7 @@ dependencies { compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" // Corda dependencies. - cordaCompile ("$corda_ent_release_group:corda-core:$corda_ent_release_version"){ + cordaCompile ("$corda_release_group:corda-core:$corda_release_version"){ changing = true } diff --git a/modules/money/build.gradle b/modules/money/build.gradle index e3591167..ed0f8a51 100644 --- a/modules/money/build.gradle +++ b/modules/money/build.gradle @@ -36,7 +36,7 @@ dependencies { compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" // Corda dependencies. - cordaCompile ("$corda_ent_release_group:corda-core:$corda_ent_release_version"){ + cordaCompile ("$corda_release_group:corda-core:$corda_release_version"){ changing = true } diff --git a/modules/selection/build.gradle b/modules/selection/build.gradle index 20e2de19..866f213a 100644 --- a/modules/selection/build.gradle +++ b/modules/selection/build.gradle @@ -32,11 +32,11 @@ dependencies { compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" // Corda dependencies. - cordaCompile ("$corda_ent_release_group:corda-core:$corda_ent_release_version"){ + cordaCompile ("$corda_release_group:corda-core:$corda_release_version"){ changing = true } // Corda dependencies. - cordaCompile ("$corda_ent_release_group:corda-node-api:$corda_ent_release_version"){ + cordaCompile ("$corda_release_group:corda-node-api:$corda_release_version"){ changing = true } @@ -44,7 +44,7 @@ dependencies { testCompile "org.apache.logging.log4j:log4j-slf4j-impl:${log4j_version}" // Testing. - testCompile "$corda_ent_release_group:corda-node-driver:$corda_ent_release_version" + testCompile "$corda_release_group:corda-node-driver:$corda_release_version" testCompile "junit:junit:$junit_version" testCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version" diff --git a/workflows/build.gradle b/workflows/build.gradle index 42cada9d..9c51cf1a 100644 --- a/workflows/build.gradle +++ b/workflows/build.gradle @@ -3,8 +3,8 @@ apply plugin: 'net.corda.plugins.quasar-utils' apply plugin: 'net.corda.plugins.cordapp' cordapp { - targetPlatformVersion 5 - minimumPlatformVersion 5 + targetPlatformVersion 6 + minimumPlatformVersion 6 workflow { name "Token SDK Workflows" vendor "R3" @@ -45,16 +45,15 @@ dependencies { // Kotlin. compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - // Corda dependencies. - cordaCompile("$corda_ent_release_group:corda-core:$corda_ent_release_version") { - changing = true - } + // Corda integration dependencies + cordaCompile("net.corda:corda-core:$corda_release_version") + testCompile "$corda_release_group:corda-node-driver:$corda_release_version" // Logging. testCompile "org.apache.logging.log4j:log4j-slf4j-impl:${log4j_version}" // Testing. - testCompile "$corda_ent_release_group:corda-node-driver:$corda_ent_release_version" + testCompile "$corda_release_group:corda-node-driver:$corda_release_version" testCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version" testCompile "junit:junit:$junit_version" diff --git a/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/move/AbstractMoveTokensFlow.kt b/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/move/AbstractMoveTokensFlow.kt index 498c4572..170a79db 100644 --- a/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/move/AbstractMoveTokensFlow.kt +++ b/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/move/AbstractMoveTokensFlow.kt @@ -21,10 +21,13 @@ import net.corda.core.utilities.ProgressTracker * * @property participantSessions a list of flow participantSessions for the transaction participants. * @property observerSessions a list of flow participantSessions for the transaction observers. + * @property haltForExternalSigning whether to halt the flow thread while waiting for signatures if a call to an external + * service is required to obtain them, to prevent blocking other work */ abstract class AbstractMoveTokensFlow : FlowLogic() { abstract val participantSessions: List abstract val observerSessions: List + abstract val haltForExternalSigning: Boolean companion object { object GENERATE : ProgressTracker.Step("Generating tokens to move.") @@ -58,7 +61,8 @@ abstract class AbstractMoveTokensFlow : FlowLogic() { val signedTransaction = subFlow( ObserverAwareFinalityFlow( transactionBuilder = transactionBuilder, - allSessions = participantSessions + observerSessions + allSessions = participantSessions + observerSessions, + haltForExternalSigning = haltForExternalSigning ) ) progressTracker.currentStep = UPDATING diff --git a/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/move/ConfidentialMoveFungibleTokensFlow.kt b/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/move/ConfidentialMoveFungibleTokensFlow.kt index 57300226..b5777660 100644 --- a/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/move/ConfidentialMoveFungibleTokensFlow.kt +++ b/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/move/ConfidentialMoveFungibleTokensFlow.kt @@ -26,6 +26,8 @@ import net.corda.core.transactions.SignedTransaction * @param changeHolder holder of the change outputs, it can be confidential identity * @param observerSessions optional sessions with the observer nodes, to witch the transaction will be broadcasted * @param queryCriteria additional criteria for token selection + * @param haltForExternalSigning optional - halt the flow thread while waiting for signatures if a call to an external + * service is required to obtain them, to prevent blocking other work */ class ConfidentialMoveFungibleTokensFlow @JvmOverloads @@ -34,7 +36,8 @@ constructor( val participantSessions: List, val changeHolder: AbstractParty, val observerSessions: List = emptyList(), - val queryCriteria: QueryCriteria? = null + val queryCriteria: QueryCriteria? = null, + val haltForExternalSigning: Boolean = false ) : FlowLogic() { @JvmOverloads @@ -61,6 +64,6 @@ constructor( participantSessions.forEach { it.send(TransactionRole.PARTICIPANT) } observerSessions.forEach { it.send(TransactionRole.OBSERVER) } val confidentialOutputs = subFlow(ConfidentialTokensFlow(outputs, participantSessions)) - return subFlow(MoveTokensFlow(inputs, confidentialOutputs, participantSessions, observerSessions)) + return subFlow(MoveTokensFlow(inputs, confidentialOutputs, participantSessions, observerSessions, haltForExternalSigning)) } } diff --git a/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/move/ConfidentialMoveNonFungibleTokensFlow.kt b/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/move/ConfidentialMoveNonFungibleTokensFlow.kt index c5916038..34fe6fcd 100644 --- a/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/move/ConfidentialMoveNonFungibleTokensFlow.kt +++ b/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/move/ConfidentialMoveNonFungibleTokensFlow.kt @@ -22,6 +22,8 @@ import net.corda.core.transactions.SignedTransaction * @param participantSessions sessions with the participants of move transaction * @param observerSessions optional sessions with the observer nodes, to witch the transaction will be broadcasted * @param queryCriteria additional criteria for token selection + * @param haltForExternalSigning optional - halt the flow thread while waiting for signatures if a call to an external + * service is required to obtain them, to prevent blocking other work */ class ConfidentialMoveNonFungibleTokensFlow @JvmOverloads @@ -29,7 +31,8 @@ constructor( val partyAndToken: PartyAndToken, val participantSessions: List, val observerSessions: List = emptyList(), - val queryCriteria: QueryCriteria? = null + val queryCriteria: QueryCriteria? = null, + val haltForExternalSigning: Boolean = false ) : FlowLogic() { @Suspendable override fun call(): SignedTransaction { @@ -38,6 +41,6 @@ constructor( participantSessions.forEach { it.send(TransactionRole.PARTICIPANT) } observerSessions.forEach { it.send(TransactionRole.OBSERVER) } val confidentialOutput = subFlow(ConfidentialTokensFlow(listOf(output), participantSessions)).single() - return subFlow(MoveTokensFlow(input, confidentialOutput, participantSessions, observerSessions)) + return subFlow(MoveTokensFlow(listOf(input), listOf(confidentialOutput), participantSessions, observerSessions, haltForExternalSigning)) } } diff --git a/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/move/MoveFungibleTokensFlow.kt b/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/move/MoveFungibleTokensFlow.kt index d45918a6..0a7c0ad6 100644 --- a/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/move/MoveFungibleTokensFlow.kt +++ b/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/move/MoveFungibleTokensFlow.kt @@ -21,6 +21,8 @@ import net.corda.core.transactions.TransactionBuilder * @param queryCriteria additional criteria for token selection * @param changeHolder optional holder of the change outputs, it can be confidential identity, if not specified it * defaults to caller's legal identity + * @param haltForExternalSigning optional - halt the flow thread while waiting for signatures if a call to an external + * service is required to obtain them, to prevent blocking other work */ class MoveFungibleTokensFlow @JvmOverloads @@ -29,7 +31,8 @@ constructor( override val participantSessions: List, override val observerSessions: List = emptyList(), val queryCriteria: QueryCriteria? = null, - val changeHolder: AbstractParty? = null + val changeHolder: AbstractParty? = null, + override val haltForExternalSigning: Boolean = false ) : AbstractMoveTokensFlow() { @JvmOverloads diff --git a/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/move/MoveNonFungibleTokensFlow.kt b/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/move/MoveNonFungibleTokensFlow.kt index 4b4ea3ac..ff3a4897 100644 --- a/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/move/MoveNonFungibleTokensFlow.kt +++ b/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/move/MoveNonFungibleTokensFlow.kt @@ -18,6 +18,8 @@ import net.corda.core.transactions.TransactionBuilder * @param participantSessions sessions with the participants of move transaction * @param observerSessions optional sessions with the observer nodes, to witch the transaction will be broadcasted * @param queryCriteria additional criteria for token selection + * @param haltForExternalSigning optional - halt the flow thread while waiting for signatures if a call to an external + * service is required to obtain them, to prevent blocking other work */ class MoveNonFungibleTokensFlow @JvmOverloads @@ -25,7 +27,8 @@ constructor( val partyAndToken: PartyAndToken, override val participantSessions: List, override val observerSessions: List = emptyList(), - val queryCriteria: QueryCriteria? + val queryCriteria: QueryCriteria?, + override val haltForExternalSigning: Boolean = false ) : AbstractMoveTokensFlow() { @Suspendable override fun addMove(transactionBuilder: TransactionBuilder) { diff --git a/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/move/MoveTokensFlow.kt b/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/move/MoveTokensFlow.kt index 43ed0be0..aacf2c53 100644 --- a/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/move/MoveTokensFlow.kt +++ b/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/move/MoveTokensFlow.kt @@ -18,6 +18,8 @@ import net.corda.core.transactions.TransactionBuilder * @param outputs list of result token outputs * @param participantSessions session with the participants of move tokens transaction * @param observerSessions session with optional observers of the redeem transaction + * @param haltForExternalSigning optional - halt the flow thread while waiting for signatures if a call to an external + * service is required to obtain them, to prevent blocking other work */ class MoveTokensFlow @JvmOverloads @@ -25,7 +27,8 @@ constructor( val inputs: List>, val outputs: List, override val participantSessions: List, - override val observerSessions: List = emptyList() + override val observerSessions: List = emptyList(), + override val haltForExternalSigning: Boolean = false ) : AbstractMoveTokensFlow() { @JvmOverloads constructor( diff --git a/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/rpc/MoveTokens.kt b/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/rpc/MoveTokens.kt index d65907b5..c928e8a2 100644 --- a/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/rpc/MoveTokens.kt +++ b/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/rpc/MoveTokens.kt @@ -26,6 +26,8 @@ import net.corda.core.transactions.SignedTransaction * @param queryCriteria additional criteria for token selection * @param changeHolder optional holder of the change outputs, it can be confidential identity, if not specified it * defaults to caller's legal identity + * @param haltForExternalSigning optional - halt the flow thread while waiting for signatures if a call to an external + * service is required to obtain them, to prevent blocking other work */ @StartableByService @StartableByRPC @@ -36,7 +38,8 @@ constructor( val partiesAndAmounts: List>, val observers: List = emptyList(), val queryCriteria: QueryCriteria? = null, - val changeHolder: AbstractParty? = null + val changeHolder: AbstractParty? = null, + val haltForExternalSigning: Boolean = false ) : FlowLogic() { @JvmOverloads @@ -83,6 +86,8 @@ class MoveFungibleTokensHandler(val otherSession: FlowSession) : FlowLogic * @param partyAndToken pairing party - token that is to be moved to that party * @param observers optional observing parties to which the transaction will be broadcast * @param queryCriteria additional criteria for token selection + * @param haltForExternalSigning optional - halt the flow thread while waiting for signatures if a call to an external + * service is required to obtain them, to prevent blocking other work */ @StartableByService @StartableByRPC @@ -92,7 +97,8 @@ class MoveNonFungibleTokens constructor( val partyAndToken: PartyAndToken, val observers: List = emptyList(), - val queryCriteria: QueryCriteria? = null + val queryCriteria: QueryCriteria? = null, + val haltForExternalSigning: Boolean = false ) : FlowLogic() { @Suspendable override fun call(): SignedTransaction { @@ -129,6 +135,8 @@ class MoveNonFungibleTokensHandler(val otherSession: FlowSession) : FlowLogic>, val observers: List, val queryCriteria: QueryCriteria? = null, - val changeHolder: AbstractParty? = null + val changeHolder: AbstractParty? = null, + val haltForExternalSigning: Boolean = false ) : FlowLogic() { constructor( @@ -191,6 +200,8 @@ class ConfidentialMoveFungibleTokensHandler(val otherSession: FlowSession) : Flo * @param partyAndToken list of pairing party - token that is to be moved to that party * @param observers optional observing parties to which the transaction will be broadcast * @param queryCriteria additional criteria for token selection + * @param haltForExternalSigning optional - halt the flow thread while waiting for signatures if a call to an external + * service is required to obtain them, to prevent blocking other work */ @StartableByService @StartableByRPC @@ -198,7 +209,8 @@ class ConfidentialMoveFungibleTokensHandler(val otherSession: FlowSession) : Flo class ConfidentialMoveNonFungibleTokens( val partyAndToken: PartyAndToken, val observers: List, - val queryCriteria: QueryCriteria? = null + val queryCriteria: QueryCriteria? = null, + val haltForExternalSigning: Boolean = false ) : FlowLogic() { @Suspendable override fun call(): SignedTransaction { diff --git a/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/internal/flows/finality/ObserverAwareFinalityFlow.kt b/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/internal/flows/finality/ObserverAwareFinalityFlow.kt index 8046ac6f..7356ac57 100644 --- a/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/internal/flows/finality/ObserverAwareFinalityFlow.kt +++ b/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/internal/flows/finality/ObserverAwareFinalityFlow.kt @@ -8,13 +8,19 @@ import com.r3.corda.lib.tokens.workflows.utilities.requireSessionsForParticipant import com.r3.corda.lib.tokens.workflows.utilities.toWellKnownParties import net.corda.core.contracts.CommandWithParties import net.corda.core.flows.FinalityFlow +import net.corda.core.flows.FlowExternalAsyncOperation import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowSession import net.corda.core.identity.AbstractParty import net.corda.core.identity.Party +import net.corda.core.node.ServiceHub import net.corda.core.transactions.LedgerTransaction import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.TransactionBuilder +import java.security.PublicKey +import java.util.concurrent.CompletableFuture +import java.util.concurrent.Executors +import java.util.function.Supplier /** * This flow is a wrapper around [FinalityFlow] and properly handles broadcasting transactions to observers (those which @@ -35,12 +41,16 @@ import net.corda.core.transactions.TransactionBuilder class ObserverAwareFinalityFlow private constructor( val allSessions: List, val signedTransaction: SignedTransaction? = null, - val transactionBuilder: TransactionBuilder? = null + val transactionBuilder: TransactionBuilder? = null, + val haltForExternalSigning: Boolean = false ) : FlowLogic() { constructor(transactionBuilder: TransactionBuilder, allSessions: List) : this(allSessions, null, transactionBuilder) + constructor(transactionBuilder: TransactionBuilder, allSessions: List, haltForExternalSigning: Boolean) + : this(allSessions, null, transactionBuilder, haltForExternalSigning) + constructor(signedTransaction: SignedTransaction, allSessions: List) : this(allSessions, signedTransaction) @@ -68,10 +78,31 @@ class ObserverAwareFinalityFlow private constructor( } // Sign and finalise the transaction, obtaining the signing keys required from the LedgerTransaction. val ourSigningKeys = ledgerTransaction.ourSigningKeys(serviceHub) - val stx = transactionBuilder?.let { - serviceHub.signInitialTransaction(it, signingPubKeys = ourSigningKeys) - } ?: signedTransaction - ?: throw IllegalArgumentException("Didn't provide transactionBuilder nor signedTransaction to the flow.") + + val stx = if (haltForExternalSigning) { + await(SignTransactionOperation(transactionBuilder!!, ourSigningKeys, serviceHub)) + } else { + transactionBuilder.let { + serviceHub.signInitialTransaction(it!!, signingPubKeys = ourSigningKeys) + } + } + return subFlow(FinalityFlow(transaction = stx, sessions = finalSessions)) } + +} + +class SignTransactionOperation(private val transactionBuilder: TransactionBuilder, private val signingKeys: List, + private val serviceHub: ServiceHub) : FlowExternalAsyncOperation { + override fun execute(deduplicationId: String) : CompletableFuture { + return CompletableFuture.supplyAsync( + Supplier { + transactionBuilder.let { + serviceHub.signInitialTransaction(it, signingPubKeys = signingKeys) + } + }, + Executors.newFixedThreadPool(1) + ) + } + } \ No newline at end of file From cdc9bef5e51a28883d91790e6b8c180229c7ba83 Mon Sep 17 00:00:00 2001 From: adcockalexander Date: Thu, 30 Jul 2020 11:59:44 +0100 Subject: [PATCH 5/8] Add illegal argument / operation checks --- .../internal/flows/finality/ObserverAwareFinalityFlow.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/internal/flows/finality/ObserverAwareFinalityFlow.kt b/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/internal/flows/finality/ObserverAwareFinalityFlow.kt index 7356ac57..19acc139 100644 --- a/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/internal/flows/finality/ObserverAwareFinalityFlow.kt +++ b/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/internal/flows/finality/ObserverAwareFinalityFlow.kt @@ -80,11 +80,15 @@ class ObserverAwareFinalityFlow private constructor( val ourSigningKeys = ledgerTransaction.ourSigningKeys(serviceHub) val stx = if (haltForExternalSigning) { + if (transactionBuilder == null) { + throw UnsupportedOperationException("You cannot halt for external signing without providing a transaction builder to the flow.") + } await(SignTransactionOperation(transactionBuilder!!, ourSigningKeys, serviceHub)) } else { transactionBuilder.let { serviceHub.signInitialTransaction(it!!, signingPubKeys = ourSigningKeys) - } + } ?: signedTransaction + ?: throw IllegalArgumentException("Didn't provide transactionBuilder nor signedTransaction to the flow.") } return subFlow(FinalityFlow(transaction = stx, sessions = finalSessions)) From babe100baf9dd70fd435ed992973c12d59acf3fc Mon Sep 17 00:00:00 2001 From: adcockalexander Date: Thu, 30 Jul 2020 12:01:20 +0100 Subject: [PATCH 6/8] fix null check --- .../internal/flows/finality/ObserverAwareFinalityFlow.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/internal/flows/finality/ObserverAwareFinalityFlow.kt b/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/internal/flows/finality/ObserverAwareFinalityFlow.kt index 19acc139..f9637ea3 100644 --- a/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/internal/flows/finality/ObserverAwareFinalityFlow.kt +++ b/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/internal/flows/finality/ObserverAwareFinalityFlow.kt @@ -85,7 +85,7 @@ class ObserverAwareFinalityFlow private constructor( } await(SignTransactionOperation(transactionBuilder!!, ourSigningKeys, serviceHub)) } else { - transactionBuilder.let { + transactionBuilder?.let { serviceHub.signInitialTransaction(it!!, signingPubKeys = ourSigningKeys) } ?: signedTransaction ?: throw IllegalArgumentException("Didn't provide transactionBuilder nor signedTransaction to the flow.") From 5b68519c2a913da735cb9abd7e73006e7c1b0bf2 Mon Sep 17 00:00:00 2001 From: adcockalexander Date: Fri, 21 Aug 2020 12:04:19 +0100 Subject: [PATCH 7/8] add timeout to async op, ensure all flows can use it --- workflows/build.gradle | 2 +- .../ConfidentialMoveFungibleTokensFlow.kt | 6 ++--- .../flows/move/MoveFungibleTokensFlow.kt | 5 ++-- .../workflows/flows/move/MoveTokensFlow.kt | 5 ++-- .../tokens/workflows/flows/rpc/MoveTokens.kt | 22 +++++++++++------- .../finality/ObserverAwareFinalityFlow.kt | 23 ++++++++++++++----- 6 files changed, 41 insertions(+), 22 deletions(-) diff --git a/workflows/build.gradle b/workflows/build.gradle index 9c51cf1a..f0e848b8 100644 --- a/workflows/build.gradle +++ b/workflows/build.gradle @@ -46,7 +46,7 @@ dependencies { compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" // Corda integration dependencies - cordaCompile("net.corda:corda-core:$corda_release_version") + cordaCompile("$corda_release_group:corda-core:$corda_release_version") testCompile "$corda_release_group:corda-node-driver:$corda_release_version" // Logging. diff --git a/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/move/ConfidentialMoveFungibleTokensFlow.kt b/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/move/ConfidentialMoveFungibleTokensFlow.kt index b5777660..bf57ac99 100644 --- a/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/move/ConfidentialMoveFungibleTokensFlow.kt +++ b/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/move/ConfidentialMoveFungibleTokensFlow.kt @@ -46,9 +46,9 @@ constructor( participantSessions: List, changeHolder: AbstractParty, queryCriteria: QueryCriteria? = null, - observerSessions: List = emptyList() - - ) : this(listOf(partyAndAmount), participantSessions, changeHolder, observerSessions, queryCriteria) + observerSessions: List = emptyList(), + haltForExternalSigning: Boolean = false + ) : this(listOf(partyAndAmount), participantSessions, changeHolder, observerSessions, queryCriteria, haltForExternalSigning) @Suspendable override fun call(): SignedTransaction { diff --git a/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/move/MoveFungibleTokensFlow.kt b/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/move/MoveFungibleTokensFlow.kt index 0a7c0ad6..c7dc26fb 100644 --- a/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/move/MoveFungibleTokensFlow.kt +++ b/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/move/MoveFungibleTokensFlow.kt @@ -41,8 +41,9 @@ constructor( queryCriteria: QueryCriteria? = null, participantSessions: List, observerSessions: List = emptyList(), - changeHolder: AbstractParty? = null - ) : this(listOf(partyAndAmount), participantSessions, observerSessions, queryCriteria, changeHolder) + changeHolder: AbstractParty? = null, + haltForExternalSigning: Boolean = false + ) : this(listOf(partyAndAmount), participantSessions, observerSessions, queryCriteria, changeHolder, haltForExternalSigning) @Suspendable override fun addMove(transactionBuilder: TransactionBuilder) { diff --git a/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/move/MoveTokensFlow.kt b/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/move/MoveTokensFlow.kt index aacf2c53..1dc3aeb2 100644 --- a/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/move/MoveTokensFlow.kt +++ b/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/move/MoveTokensFlow.kt @@ -35,8 +35,9 @@ constructor( input: StateAndRef, output: AbstractToken, participantSessions: List, - observerSessions: List = emptyList() - ) : this(listOf(input), listOf(output), participantSessions, observerSessions) + observerSessions: List = emptyList(), + haltForExternalSigning: Boolean = false + ) : this(listOf(input), listOf(output), participantSessions, observerSessions, haltForExternalSigning) @Suspendable override fun addMove(transactionBuilder: TransactionBuilder) { diff --git a/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/rpc/MoveTokens.kt b/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/rpc/MoveTokens.kt index c928e8a2..effe7917 100644 --- a/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/rpc/MoveTokens.kt +++ b/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/flows/rpc/MoveTokens.kt @@ -47,8 +47,9 @@ constructor( partyAndAmount: PartyAndAmount, observers: List = emptyList(), queryCriteria: QueryCriteria? = null, - changeHolder: AbstractParty? = null - ) : this(listOf(partyAndAmount), observers, queryCriteria, changeHolder) + changeHolder: AbstractParty? = null, + haltForExternalSigning: Boolean = false + ) : this(listOf(partyAndAmount), observers, queryCriteria, changeHolder, haltForExternalSigning) constructor(amount: Amount, holder: AbstractParty) : this(PartyAndAmount(holder, amount), emptyList()) @@ -62,7 +63,8 @@ constructor( participantSessions = participantSessions, observerSessions = observerSessions, queryCriteria = queryCriteria, - changeHolder = changeHolder + changeHolder = changeHolder, + haltForExternalSigning = haltForExternalSigning )) } } @@ -108,7 +110,8 @@ constructor( partyAndToken = partyAndToken, participantSessions = participantSessions, observerSessions = observerSessions, - queryCriteria = queryCriteria + queryCriteria = queryCriteria, + haltForExternalSigning = haltForExternalSigning )) } } @@ -153,8 +156,9 @@ class ConfidentialMoveFungibleTokens( partyAndAmount: PartyAndAmount, observers: List, queryCriteria: QueryCriteria? = null, - changeHolder: AbstractParty? = null - ) : this(listOf(partyAndAmount), observers, queryCriteria, changeHolder) + changeHolder: AbstractParty? = null, + haltForExternalSigning: Boolean = false + ) : this(listOf(partyAndAmount), observers, queryCriteria, changeHolder, haltForExternalSigning) @Suspendable override fun call(): SignedTransaction { @@ -176,7 +180,8 @@ class ConfidentialMoveFungibleTokens( participantSessions = participantSessions, observerSessions = observerSessions, queryCriteria = queryCriteria, - changeHolder = confidentialHolder + changeHolder = confidentialHolder, + haltForExternalSigning = haltForExternalSigning )) } } @@ -220,7 +225,8 @@ class ConfidentialMoveNonFungibleTokens( partyAndToken = partyAndToken, participantSessions = participantSessions, observerSessions = observerSessions, - queryCriteria = queryCriteria + queryCriteria = queryCriteria, + haltForExternalSigning = haltForExternalSigning )) } } diff --git a/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/internal/flows/finality/ObserverAwareFinalityFlow.kt b/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/internal/flows/finality/ObserverAwareFinalityFlow.kt index f9637ea3..d3f154fb 100644 --- a/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/internal/flows/finality/ObserverAwareFinalityFlow.kt +++ b/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/internal/flows/finality/ObserverAwareFinalityFlow.kt @@ -18,8 +18,11 @@ import net.corda.core.transactions.LedgerTransaction import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.TransactionBuilder import java.security.PublicKey +import java.util.concurrent.Callable import java.util.concurrent.CompletableFuture import java.util.concurrent.Executors +import java.util.concurrent.TimeUnit +import java.util.concurrent.TimeoutException import java.util.function.Supplier /** @@ -37,6 +40,8 @@ import java.util.function.Supplier * transaction with observers, notice that this flow can be called either with [transactionBuilder] or * [signedTransaction] * @property allSessions a set of sessions for, at least, all the transaction participants and maybe observers + * @property haltForExternalSigning optional - halt the flow thread while waiting for signatures if a call to an external + * service is required to obtain them, to prevent blocking other work */ class ObserverAwareFinalityFlow private constructor( val allSessions: List, @@ -80,13 +85,10 @@ class ObserverAwareFinalityFlow private constructor( val ourSigningKeys = ledgerTransaction.ourSigningKeys(serviceHub) val stx = if (haltForExternalSigning) { - if (transactionBuilder == null) { - throw UnsupportedOperationException("You cannot halt for external signing without providing a transaction builder to the flow.") - } await(SignTransactionOperation(transactionBuilder!!, ourSigningKeys, serviceHub)) } else { transactionBuilder?.let { - serviceHub.signInitialTransaction(it!!, signingPubKeys = ourSigningKeys) + serviceHub.signInitialTransaction(it, signingPubKeys = ourSigningKeys) } ?: signedTransaction ?: throw IllegalArgumentException("Didn't provide transactionBuilder nor signedTransaction to the flow.") } @@ -98,14 +100,23 @@ class ObserverAwareFinalityFlow private constructor( class SignTransactionOperation(private val transactionBuilder: TransactionBuilder, private val signingKeys: List, private val serviceHub: ServiceHub) : FlowExternalAsyncOperation { + override fun execute(deduplicationId: String) : CompletableFuture { + val executor = Executors.newFixedThreadPool(2) return CompletableFuture.supplyAsync( Supplier { transactionBuilder.let { - serviceHub.signInitialTransaction(it, signingPubKeys = signingKeys) + val future = executor.submit(Callable { + serviceHub.signInitialTransaction(it, signingPubKeys = signingKeys) + }) + try { + future.get(5, TimeUnit.MINUTES) + } finally { + future.cancel(true) + } } }, - Executors.newFixedThreadPool(1) + executor ) } From 4a7681b0b0a626f6a3de448fa87aca677eb0914f Mon Sep 17 00:00:00 2001 From: adcockalexander Date: Tue, 25 Aug 2020 10:52:50 +0100 Subject: [PATCH 8/8] Update ObserverAwareFinalityFlow.kt --- .../internal/flows/finality/ObserverAwareFinalityFlow.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/internal/flows/finality/ObserverAwareFinalityFlow.kt b/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/internal/flows/finality/ObserverAwareFinalityFlow.kt index d3f154fb..cfb87bc4 100644 --- a/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/internal/flows/finality/ObserverAwareFinalityFlow.kt +++ b/workflows/src/main/kotlin/com/r3/corda/lib/tokens/workflows/internal/flows/finality/ObserverAwareFinalityFlow.kt @@ -110,9 +110,10 @@ class SignTransactionOperation(private val transactionBuilder: TransactionBuilde serviceHub.signInitialTransaction(it, signingPubKeys = signingKeys) }) try { - future.get(5, TimeUnit.MINUTES) + future.get(30, TimeUnit.MINUTES) } finally { future.cancel(true) + executor.shutdown() } } },