From 252118de10f6224841074380ec671cfc59fad15c Mon Sep 17 00:00:00 2001 From: Ian Lloyd Date: Thu, 16 May 2019 10:33:38 +0800 Subject: [PATCH 1/2] Add progress trackers to all responder flows. Allow passing a child progress tracker to Issue and Move Token flows to support confidential identity swapping. --- .../flows/ConfidentialIssueMoveFlows.kt | 92 +++++++++++++++++-- .../workflow/flows/CreateEvolvableToken.kt | 20 +++- .../flows/CreateEvolvableTokenResponder.kt | 27 +++++- .../sdk/token/workflow/flows/IssueToken.kt | 24 +++-- .../sdk/token/workflow/flows/MoveToken.kt | 38 +++++--- .../sdk/token/workflow/flows/RedeemToken.kt | 76 +++++++++++++-- .../workflow/flows/UpdateEvolvableToken.kt | 20 +++- .../flows/UpdateEvolvableTokenResponder.kt | 23 ++++- 8 files changed, 267 insertions(+), 53 deletions(-) diff --git a/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/ConfidentialIssueMoveFlows.kt b/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/ConfidentialIssueMoveFlows.kt index 87b14edb..d10aa76a 100644 --- a/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/ConfidentialIssueMoveFlows.kt +++ b/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/ConfidentialIssueMoveFlows.kt @@ -9,6 +9,7 @@ import net.corda.core.flows.InitiatedBy import net.corda.core.flows.InitiatingFlow import net.corda.core.identity.Party import net.corda.core.transactions.SignedTransaction +import net.corda.core.utilities.ProgressTracker object ConfidentialIssueFlow { @InitiatingFlow @@ -16,22 +17,61 @@ object ConfidentialIssueFlow { val token: T, val holder: Party, val notary: Party, - val amount: Amount? = null + val amount: Amount? = null, + override val progressTracker: ProgressTracker = tracker() ) : FlowLogic() { + @Suspendable override fun call(): SignedTransaction { val holderSession = initiateFlow(holder) + progressTracker.currentStep = REQUESTING_IDENTITY val confidentialHolder = subFlow(RequestConfidentialIdentity.Initiator(holderSession)).party.anonymise() - return subFlow(IssueToken.Initiator(token, confidentialHolder, notary, amount, holderSession)) + progressTracker.currentStep = ISSUING_TOKEN + return subFlow(IssueToken.Initiator( + token, + confidentialHolder, + notary, + amount, + holderSession, + progressTracker = ISSUING_TOKEN.childProgressTracker() + )) + } + + companion object { + object REQUESTING_IDENTITY : ProgressTracker.Step("Requesting a confidential identity.") + + object ISSUING_TOKEN : ProgressTracker.Step("Issuing token.") { + override fun childProgressTracker() = IssueToken.Initiator.tracker() + } + + fun tracker() = ProgressTracker(REQUESTING_IDENTITY, ISSUING_TOKEN) } } @InitiatedBy(Initiator::class) - class Responder(val otherSession: FlowSession) : FlowLogic() { + class Responder( + val otherSession: FlowSession, + override val progressTracker: ProgressTracker = tracker() + ) : FlowLogic() { + + constructor(otherSession: FlowSession) : this(otherSession, tracker()) + @Suspendable override fun call() { + progressTracker.currentStep = REQUESTING_IDENTITY subFlow(RequestConfidentialIdentity.Responder(otherSession)) - subFlow(IssueToken.Responder(otherSession)) + progressTracker.currentStep = ISSUING_TOKEN + subFlow(IssueToken.Responder(otherSession, progressTracker = ISSUING_TOKEN.childProgressTracker())) + } + + companion object { + object REQUESTING_IDENTITY : ProgressTracker.Step("Requesting a confidential identity.") + + object ISSUING_TOKEN : ProgressTracker.Step("Issuing token.") { + override fun childProgressTracker() = IssueToken.Responder.tracker() + } + + fun tracker() = ProgressTracker(REQUESTING_IDENTITY, ISSUING_TOKEN) } } } @@ -41,26 +81,60 @@ object ConfidentialMoveFlow { class Initiator( val ownedToken: T, val holder: Party, - val amount: Amount? = null + val amount: Amount? = null, + override val progressTracker: ProgressTracker = tracker() ) : FlowLogic() { + @Suspendable override fun call(): SignedTransaction { val holderSession = initiateFlow(holder) + progressTracker.currentStep = REQUESTING_IDENTITY val confidentialHolder = subFlow(RequestConfidentialIdentity.Initiator(holderSession)).party.anonymise() + progressTracker.currentStep = MOVING_TOKEN return if (amount == null) { - subFlow(MoveTokenNonFungible(ownedToken, holder, holderSession)) + subFlow(MoveTokenNonFungible(ownedToken, holder, holderSession, progressTracker = MOVING_TOKEN.childProgressTracker())) } else { - subFlow(MoveTokenFungible(amount, confidentialHolder, holderSession)) + subFlow(MoveTokenFungible(amount, confidentialHolder, holderSession, progressTracker = MOVING_TOKEN.childProgressTracker())) } } + + companion object { + object REQUESTING_IDENTITY : ProgressTracker.Step("Requesting a confidential identity.") + + object MOVING_TOKEN : ProgressTracker.Step("Moving token.") { + override fun childProgressTracker() = MoveToken.Initiator.tracker() + } + + fun tracker() = ProgressTracker(REQUESTING_IDENTITY, MOVING_TOKEN) + } + } @InitiatedBy(Initiator::class) - class Responder(val otherSession: FlowSession) : FlowLogic() { + class Responder( + val otherSession: FlowSession, + override val progressTracker: ProgressTracker = tracker() + ) : FlowLogic() { + + constructor(otherSession: FlowSession) : this(otherSession, tracker()) + @Suspendable override fun call() { + progressTracker.currentStep = REQUESTING_IDENTITY subFlow(RequestConfidentialIdentity.Responder(otherSession)) - subFlow(MoveToken.Responder(otherSession)) + progressTracker.currentStep = MOVING_TOKEN + subFlow(MoveToken.Responder(otherSession, progressTracker = MOVING_TOKEN.childProgressTracker())) } + + companion object { + object REQUESTING_IDENTITY : ProgressTracker.Step("Requesting a confidential identity.") + + object MOVING_TOKEN : ProgressTracker.Step("Moving token.") { + override fun childProgressTracker() = MoveToken.Responder.tracker() + } + + fun tracker() = ProgressTracker(REQUESTING_IDENTITY, MOVING_TOKEN) + } + } } \ No newline at end of file diff --git a/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/CreateEvolvableToken.kt b/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/CreateEvolvableToken.kt index d0678f55..e7e5322e 100644 --- a/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/CreateEvolvableToken.kt +++ b/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/CreateEvolvableToken.kt @@ -37,15 +37,19 @@ class CreateEvolvableToken( object SIGNING : ProgressTracker.Step("Signing transaction proposal.") + object NOTIFYING_MAINTAINERS : ProgressTracker.Step("Notifying all maintainers.") + object COLLECTING : ProgressTracker.Step("Gathering counterparty signature.") { override fun childProgressTracker() = CollectSignaturesFlow.tracker() } + object NOTIFYING_OBSERVERS : ProgressTracker.Step("Notifying all observers.") + object RECORDING : ProgressTracker.Step("Recording signed transaction.") { override fun childProgressTracker() = FinalityFlow.tracker() } - fun tracker() = ProgressTracker(CREATING, SIGNING, COLLECTING, RECORDING) + fun tracker() = ProgressTracker(CREATING, SIGNING, NOTIFYING_MAINTAINERS, COLLECTING, NOTIFYING_OBSERVERS, RECORDING) } override val progressTracker: ProgressTracker = tracker() @@ -60,20 +64,26 @@ class CreateEvolvableToken( progressTracker.currentStep = SIGNING val stx: SignedTransaction = serviceHub.signInitialTransaction(utx) - // Gather signatures from other maintainers - progressTracker.currentStep = COLLECTING + // Notify maintainers of proposed transaction + progressTracker.currentStep = NOTIFYING_MAINTAINERS val otherMaintainerSessions = otherMaintainers().map { initiateFlow(it) } otherMaintainerSessions.forEach { it.send(Notification(signatureRequired = true)) } + + // Gather signatures from other maintainers + progressTracker.currentStep = COLLECTING val tx = subFlow(CollectSignaturesFlow( partiallySignedTx = stx, sessionsToCollectFrom = otherMaintainerSessions, progressTracker = COLLECTING.childProgressTracker() )) - // Finalise with all participants, including maintainers, participants, and subscribers (via distribution list) - progressTracker.currentStep = RECORDING + // Notify all observers (non-maintainers) of proposed transaction + progressTracker.currentStep = NOTIFYING_OBSERVERS val observerSessions = wellKnownObservers().map { initiateFlow(it) } observerSessions.forEach { it.send(Notification(signatureRequired = false)) } + + // Finalise with all participants, including maintainers, participants, and subscribers (via distribution list) + progressTracker.currentStep = RECORDING return subFlow(FinalityFlow( transaction = tx, sessions = (otherMaintainerSessions + observerSessions), diff --git a/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/CreateEvolvableTokenResponder.kt b/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/CreateEvolvableTokenResponder.kt index ba65486d..16fd8456 100644 --- a/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/CreateEvolvableTokenResponder.kt +++ b/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/CreateEvolvableTokenResponder.kt @@ -1,30 +1,47 @@ package com.r3.corda.sdk.token.workflow.flows import co.paralleluniverse.fibers.Suspendable -import net.corda.core.contracts.requireThat import net.corda.core.flows.* import net.corda.core.node.StatesToRecord import net.corda.core.transactions.SignedTransaction +import net.corda.core.utilities.ProgressTracker import net.corda.core.utilities.unwrap @InitiatedBy(CreateEvolvableToken::class) class CreateEvolvableTokenResponder(val otherSession: FlowSession) : FlowLogic() { + + companion object { + object PREPARING : ProgressTracker.Step("Preparing for evolvable token creation transaction.") + + object SIGNING : ProgressTracker.Step("Signing transaction proposal.") { + override fun childProgressTracker() = SignTransactionFlow.tracker() + } + + object RECORDING : ProgressTracker.Step("Recording signed transaction.") + + fun tracker() = ProgressTracker(PREPARING, SIGNING, RECORDING) + } + + override val progressTracker: ProgressTracker = tracker() + + @Suspendable override fun call(): SignedTransaction { // Receive the notification + progressTracker.currentStep = PREPARING val notification = otherSession.receive().unwrap { it } // Sign the transaction proposal, if required if (notification.signatureRequired) { - val signTransactionFlow = object : SignTransactionFlow(otherSession) { - override fun checkTransaction(stx: SignedTransaction) = requireThat { - // TODO - } + progressTracker.currentStep = SIGNING + val signTransactionFlow = object : SignTransactionFlow(otherSession, progressTracker = SIGNING.childProgressTracker()) { + override fun checkTransaction(stx: SignedTransaction) = Unit } subFlow(signTransactionFlow) } // Resolve the creation transaction. + progressTracker.currentStep = RECORDING return subFlow(ReceiveFinalityFlow(otherSideSession = otherSession, statesToRecord = StatesToRecord.ONLY_RELEVANT)) } } \ No newline at end of file diff --git a/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/IssueToken.kt b/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/IssueToken.kt index d7e42917..0a7a79b0 100644 --- a/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/IssueToken.kt +++ b/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/IssueToken.kt @@ -62,7 +62,8 @@ object IssueToken { val issueTo: AbstractParty, val notary: Party, val amount: Amount? = null, - val session: FlowSession? = null + val session: FlowSession? = null, + override val progressTracker: ProgressTracker = tracker() ) : FlowLogic() { companion object { object DIST_LIST : ProgressTracker.Step("Adding party to distribution list.") @@ -74,8 +75,6 @@ object IssueToken { fun tracker() = ProgressTracker(DIST_LIST, SIGNING, RECORDING) } - override val progressTracker: ProgressTracker = tracker() - @Suspendable override fun call(): SignedTransaction { // This is the identity which will be used to issue tokens. @@ -124,17 +123,30 @@ object IssueToken { // Can issue to yourself, but finality flow doesn't take a session then. val sessions = if (me == holderParty) emptyList() else listOf(holderSession) return subFlow(FinalityFlow(transaction = stx, - progressTracker = RECORDING.childProgressTracker(), - sessions = sessions + sessions = sessions, + progressTracker = RECORDING.childProgressTracker() )) } } @InitiatedBy(Initiator::class) - class Responder(val otherSession: FlowSession) : FlowLogic() { + class Responder( + val otherSession: FlowSession, + override val progressTracker: ProgressTracker = tracker() + ) : FlowLogic() { + + constructor(otherSession: FlowSession) : this(otherSession, tracker()) + + companion object { + object RECORDING : ProgressTracker.Step("Recording token issuance transaction.") + + fun tracker() = ProgressTracker(RECORDING) + } + @Suspendable override fun call() { // We must do this check because FinalityFlow does not send locally and we want to be able to issue to ourselves. + progressTracker.currentStep = RECORDING if (!serviceHub.myInfo.isLegalIdentity(otherSession.counterparty)) { // Resolve the issuance transaction. subFlow(ReceiveFinalityFlow(otherSideSession = otherSession, statesToRecord = StatesToRecord.ONLY_RELEVANT)) diff --git a/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/MoveToken.kt b/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/MoveToken.kt index caf39a6d..3e154518 100644 --- a/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/MoveToken.kt +++ b/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/MoveToken.kt @@ -6,13 +6,7 @@ import com.r3.corda.sdk.token.contracts.types.TokenType import com.r3.corda.sdk.token.workflow.selection.TokenSelection import com.r3.corda.sdk.token.workflow.selection.generateMoveNonFungible import net.corda.core.contracts.Amount -import net.corda.core.flows.FinalityFlow -import net.corda.core.flows.FlowLogic -import net.corda.core.flows.FlowSession -import net.corda.core.flows.InitiatedBy -import net.corda.core.flows.InitiatingFlow -import net.corda.core.flows.ReceiveFinalityFlow -import net.corda.core.flows.StartableByRPC +import net.corda.core.flows.* import net.corda.core.identity.AbstractParty import net.corda.core.node.StatesToRecord import net.corda.core.transactions.SignedTransaction @@ -27,7 +21,8 @@ object MoveToken { abstract class Initiator( val token: T, val holder: AbstractParty, - val session: FlowSession? = null + val session: FlowSession? = null, + override val progressTracker: ProgressTracker = tracker() ) : FlowLogic() { companion object { object GENERATE_MOVE : ProgressTracker.Step("Generating tokens move.") @@ -39,8 +34,6 @@ object MoveToken { fun tracker() = ProgressTracker(GENERATE_MOVE, SIGNING, RECORDING) } - override val progressTracker: ProgressTracker = tracker() - @Suspendable abstract fun generateMove(): Pair> @@ -70,22 +63,36 @@ object MoveToken { } @InitiatedBy(Initiator::class) - class Responder(val otherSession: FlowSession) : FlowLogic() { + class Responder( + val otherSession: FlowSession, + override val progressTracker: ProgressTracker = tracker() + ) : FlowLogic() { + + constructor(otherSession: FlowSession) : this(otherSession, tracker()) + @Suspendable override fun call() { // Resolve the move transaction. + progressTracker.currentStep = RECORDING if (!serviceHub.myInfo.isLegalIdentity(otherSession.counterparty)) { subFlow(ReceiveFinalityFlow(otherSideSession = otherSession, statesToRecord = StatesToRecord.ONLY_RELEVANT)) } } + + companion object { + object RECORDING : ProgressTracker.Step("Recording token movement transaction.") + + fun tracker() = ProgressTracker(RECORDING) + } } } class MoveTokenNonFungible( val ownedToken: T, holder: AbstractParty, - session: FlowSession? = null -) : MoveToken.Initiator(ownedToken, holder, session) { + session: FlowSession? = null, + progressTracker: ProgressTracker = tracker() +) : MoveToken.Initiator(ownedToken, holder, session, progressTracker) { @Suspendable override fun generateMove(): Pair> { return generateMoveNonFungible(serviceHub.vaultService, ownedToken, holder) @@ -95,8 +102,9 @@ class MoveTokenNonFungible( open class MoveTokenFungible( val amount: Amount, holder: AbstractParty, - session: FlowSession? = null -) : MoveToken.Initiator(amount.token, holder, session) { + session: FlowSession? = null, + progressTracker: ProgressTracker = tracker() +) : MoveToken.Initiator(amount.token, holder, session, progressTracker) { @Suspendable override fun generateMove(): Pair> { val tokenSelection = TokenSelection(serviceHub) diff --git a/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/RedeemToken.kt b/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/RedeemToken.kt index c165e9b8..d262b5b1 100644 --- a/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/RedeemToken.kt +++ b/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/RedeemToken.kt @@ -43,7 +43,10 @@ object RedeemToken { object SELECTING_STATES : ProgressTracker.Step("Selecting states to redeem.") object SEND_STATE_REF : ProgressTracker.Step("Sending states to the issuer for redeeming.") object SYNC_IDS : ProgressTracker.Step("Synchronising confidential identities.") - object SIGNING_TX : ProgressTracker.Step("Signing transaction") + object SIGNING_TX : ProgressTracker.Step("Signing transaction") { + override fun childProgressTracker() = SignTransactionFlow.tracker() + } + object FINALISING_TX : ProgressTracker.Step("Finalising transaction") fun tracker() = ProgressTracker(REDEEM_NOTIFICATION, CONF_ID, SELECTING_STATES, SEND_STATE_REF, SYNC_IDS, SIGNING_TX, FINALISING_TX) @@ -92,7 +95,7 @@ object RedeemToken { val fakeWireTx = TransactionBuilder(notary = notary).withItems(*exitStateAndRefs.toTypedArray()).addCommand(DummyCommand(), ourIdentity.owningKey).toWireTransaction(serviceHub) subFlow(IdentitySyncFlow.Send(issuerSession, fakeWireTx)) progressTracker.currentStep = SIGNING_TX - subFlow(object : SignTransactionFlow(issuerSession) { + subFlow(object : SignTransactionFlow(issuerSession, progressTracker = SIGNING_TX.childProgressTracker()) { // TODO Add some additional checks. override fun checkTransaction(stx: SignedTransaction) = Unit }) @@ -107,27 +110,71 @@ object RedeemToken { // Called on Issuer side. @InitiatedBy(InitiateRedeem::class) - class IssuerResponder(val otherSession: FlowSession) : FlowLogic() { + class IssuerResponder( + val otherSession: FlowSession, + override val progressTracker: ProgressTracker = tracker() + ) : FlowLogic() { + + constructor(otherSession: FlowSession) : this(otherSession, tracker()) + + companion object { + object PREPARING : ProgressTracker.Step("Preparing for token redemption.") + + object REQUESTING_IDENTITY : ProgressTracker.Step("Sharing a new confidential identity.") + + object RECEIVING_STATES : ProgressTracker.Step("Receiving states to redeem.") + + object SWAPPING_IDENTITIES : ProgressTracker.Step("Synchronising confidential identities.") + + object CHECKING : ProgressTracker.Step("Checking proposed redemption states.") + + object ASSEMBLING : ProgressTracker.Step("Assembling the redemption proposal.") + + object SIGNING : ProgressTracker.Step("Signing transaction") + + object COLLECTING : ProgressTracker.Step("Collecting signatures") { + override fun childProgressTracker() = CollectSignaturesFlow.tracker() + } + + object FINALISING : ProgressTracker.Step("Finalising transaction") { + override fun childProgressTracker() = FinalityFlow.tracker() + } + + fun tracker() = ProgressTracker(PREPARING, REQUESTING_IDENTITY, RECEIVING_STATES, SWAPPING_IDENTITIES, CHECKING, ASSEMBLING, SIGNING, COLLECTING, FINALISING) + } + @Suspendable override fun call(): SignedTransaction { // Receive a redeem notification from the party. It tells us if we need to sign up for token updates or // generate a confidential identity. + progressTracker.currentStep = PREPARING val redeemNotification = otherSession.receive>().unwrap { it } // Request confidential identity, if necessary. val otherIdentity = if (redeemNotification.anonymous) { + progressTracker.currentStep = REQUESTING_IDENTITY subFlow(RequestConfidentialIdentity.Initiator(otherSession)).party.anonymise() } else otherSession.counterparty + // Receive states for redemption + progressTracker.currentStep = RECEIVING_STATES val stateAndRefsToRedeem = subFlow(ReceiveStateAndRefFlow>(otherSession)) - // Synchronise identities. + + // Synchronise identities + progressTracker.currentStep = SWAPPING_IDENTITIES subFlow(IdentitySyncFlow.Receive(otherSession)) + + // Check states for redemption + progressTracker.currentStep = CHECKING check(stateAndRefsToRedeem.isNotEmpty()) { "Received empty list of states to redeem." } checkSameIssuer(stateAndRefsToRedeem, ourIdentity) checkSameNotary(stateAndRefsToRedeem) checkOwner(serviceHub.identityService, stateAndRefsToRedeem, otherSession.counterparty) + + // Assemble transaction proposal + progressTracker.currentStep = ASSEMBLING val notary = stateAndRefsToRedeem.first().state.notary val txBuilder = TransactionBuilder(notary = notary) if (redeemNotification.amount == null) { @@ -140,9 +187,26 @@ object RedeemToken { changeOwner = otherIdentity ) } + + // Prepare partially signed transaction + progressTracker.currentStep = SIGNING val partialStx = serviceHub.signInitialTransaction(txBuilder, ourIdentity.owningKey) - val stx = subFlow(CollectSignaturesFlow(partialStx, listOf(otherSession))) - return subFlow(FinalityFlow(transaction = stx, sessions = listOf(otherSession))) + + // Get signatures + progressTracker.currentStep = COLLECTING + val stx = subFlow(CollectSignaturesFlow( + partialStx, + listOf(otherSession), + progressTracker = COLLECTING.childProgressTracker() + )) + + // Finalise transaction + progressTracker.currentStep = FINALISING + return subFlow(FinalityFlow( + transaction = stx, + sessions = listOf(otherSession), + progressTracker = FINALISING.childProgressTracker() + )) } } diff --git a/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/UpdateEvolvableToken.kt b/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/UpdateEvolvableToken.kt index c0f1c2b7..5099ec0b 100644 --- a/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/UpdateEvolvableToken.kt +++ b/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/UpdateEvolvableToken.kt @@ -25,15 +25,19 @@ class UpdateEvolvableToken( object SIGNING : ProgressTracker.Step("Signing transaction proposal.") + object NOTIFYING_MAINTAINERS : ProgressTracker.Step("Notifying all maintainers.") + object COLLECTING : ProgressTracker.Step("Gathering counterparty signatures.") { override fun childProgressTracker() = CollectSignaturesFlow.tracker() } + object NOTIFYING_OBSERVERS : ProgressTracker.Step("Notifying all observers.") + object RECORDING : ProgressTracker.Step("Recording signed transaction.") { override fun childProgressTracker() = FinalityFlow.tracker() } - fun tracker() = ProgressTracker(CREATING, SIGNING, COLLECTING, RECORDING) + fun tracker() = ProgressTracker(CREATING, SIGNING, NOTIFYING_MAINTAINERS, COLLECTING, NOTIFYING_OBSERVERS, RECORDING) } override val progressTracker: ProgressTracker = tracker() @@ -62,20 +66,26 @@ class UpdateEvolvableToken( progressTracker.currentStep = SIGNING val ptx: SignedTransaction = serviceHub.signInitialTransaction(utx) - // Gather signatures from other maintainers - progressTracker.currentStep = COLLECTING + // Notify maintainers of proposed transaction + progressTracker.currentStep = NOTIFYING_MAINTAINERS val otherMaintainerSessions = otherMaintainers().map { initiateFlow(it) } otherMaintainerSessions.forEach { it.send(Notification(signatureRequired = true)) } + + // Gather signatures from other maintainers + progressTracker.currentStep = COLLECTING val stx = subFlow(CollectSignaturesFlow( partiallySignedTx = ptx, sessionsToCollectFrom = otherMaintainerSessions, progressTracker = COLLECTING.childProgressTracker() )) - // Distribute to all observers, including maintainers, participants, and subscribers (via distribution list) - progressTracker.currentStep = RECORDING + // Notify observers (non-maintainers) of proposed transaction + progressTracker.currentStep = NOTIFYING_MAINTAINERS val observerSessions = wellKnownObservers().map { initiateFlow(it) } observerSessions.forEach { it.send(Notification(signatureRequired = false)) } + + // Distribute to all observers, including maintainers, participants, and subscribers (via distribution list) + progressTracker.currentStep = RECORDING return subFlow(FinalityFlow( transaction = stx, sessions = (otherMaintainerSessions + observerSessions), diff --git a/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/UpdateEvolvableTokenResponder.kt b/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/UpdateEvolvableTokenResponder.kt index 2212c4fd..d95e714b 100644 --- a/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/UpdateEvolvableTokenResponder.kt +++ b/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/UpdateEvolvableTokenResponder.kt @@ -5,26 +5,45 @@ import net.corda.core.contracts.requireThat import net.corda.core.flows.* import net.corda.core.node.StatesToRecord import net.corda.core.transactions.SignedTransaction +import net.corda.core.utilities.ProgressTracker import net.corda.core.utilities.unwrap @InitiatedBy(UpdateEvolvableToken::class) class UpdateEvolvableTokenResponder(val otherSession: FlowSession) : FlowLogic() { + + companion object { + object PREPARING : ProgressTracker.Step("Preparing for evolvable token update transaction.") + + object SIGNING : ProgressTracker.Step("Signing transaction proposal.") { + override fun childProgressTracker() = SignTransactionFlow.tracker() + } + + object RECORDING : ProgressTracker.Step("Recording signed transaction.") + + fun tracker() = ProgressTracker(PREPARING, SIGNING, RECORDING) + } + + override val progressTracker: ProgressTracker = tracker() + @Suspendable override fun call(): SignedTransaction { // Receive the notification + progressTracker.currentStep = PREPARING val notification = otherSession.receive().unwrap { it } // Sign the transaction proposal, if required if (notification.signatureRequired) { - val signTransactionFlow = object : SignTransactionFlow(otherSession) { + progressTracker.currentStep = SIGNING + val signTransactionFlow = object : SignTransactionFlow(otherSession, progressTracker = SIGNING.childProgressTracker()) { override fun checkTransaction(stx: SignedTransaction) = requireThat { - // TODO + // TODO: Add any appropriate verification checks; in the default flow, no checks required. } } subFlow(signTransactionFlow) } // Resolve the creation transaction. + progressTracker.currentStep = RECORDING return subFlow(ReceiveFinalityFlow(otherSideSession = otherSession, statesToRecord = StatesToRecord.ALL_VISIBLE)) } } \ No newline at end of file From 3a9027b8c0ba0015509323cb86fcd927ec63e6bd Mon Sep 17 00:00:00 2001 From: przemolb Date: Sat, 8 Jun 2019 09:35:03 +0100 Subject: [PATCH 2/2] Trigger cicd --- .../sdk/token/workflow/flows/ConfidentialIssueMoveFlows.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/ConfidentialIssueMoveFlows.kt b/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/ConfidentialIssueMoveFlows.kt index d10aa76a..a30cf7bb 100644 --- a/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/ConfidentialIssueMoveFlows.kt +++ b/workflow/src/main/kotlin/com/r3/corda/sdk/token/workflow/flows/ConfidentialIssueMoveFlows.kt @@ -11,6 +11,7 @@ import net.corda.core.identity.Party import net.corda.core.transactions.SignedTransaction import net.corda.core.utilities.ProgressTracker + object ConfidentialIssueFlow { @InitiatingFlow class Initiator( @@ -137,4 +138,4 @@ object ConfidentialMoveFlow { } } -} \ No newline at end of file +}