问题
I have the scenario where One party needs to read a list of states ( DEAL STATE for ex.), Then iterate through the list to find out the matching records. If it is matching, we need to create new output state by combining the matched fields.
So once the matching is performed within the loop, we can get the list of input and output states.
But I am confused on collecting the signature from other parties since the counterparties will be different for each of the record. Also, how will I call the finality flow for multiple transactions within single flow call method?
@joel, Another problem - Suppose outputstate1 particicpants are say A, B, C, and outputstate2 paticipants are B, C ,D ,ie B & C are involved in 2 transactions. So within matching states loop, when we make flowsessions map, it will have the signers are A, B, C, D. But when we call CollectSignaturesFlow, we need to pass each of the partialsigned trxn and sessions. So how to pass the session corresponding to a trxn ?
回答1:
Here's an example of how we could collect the signatures for each state:
val flowSessionMap = mutableMapOf<Party, FlowSession>()
val fullySignedTransactions = matchingStates.forEach { matchingState ->
val requiredSigners: List<Party> = TODO("Derive this from the matching state somehow.")
val signedTransaction: SignedTransaction = TODO("Build transaction.")
val sessions = requiredSigners.map { signer ->
flowSessionMap.getOrPut(signer) {
initiateFlow(signer)
}
}
val fullySignedTransaction = subFlow(CollectSignaturesInitiatingFlow(
signedTransaction, sessions)
)
}
Where CollectSignaturesInitiatingFlow
is defined as follows:
@InitiatingFlow
class CollectSignaturesInitiatingFlow(val signedTransaction: SignedTransaction, val sessions: List<FlowSession>): FlowLogic<SignedTransaction>() {
override fun call(): SignedTransaction {
return subFlow(CollectSignaturesFlow(signedTransaction, sessions))
}
}
And the responder for CollectSignaturesInitiatingFlow
is defined as follows:
@InitiatedBy(CollectSignaturesInitiatingFlow::class)
class CollectSignaturesInitiatingFlowResponder(val otherPartyFlow: FlowSession) : FlowLogic<SignedTransaction>() {
@Suspendable
override fun call(): SignedTransaction {
val signTransactionFlow = object : SignTransactionFlow(otherPartyFlow) {
override fun checkTransaction(stx: SignedTransaction) {
TODO("Check the transaction here.")
}
}
return subFlow(signTransactionFlow)
}
}
Note that:
- We're being careful to only create one session per counterparty. As of Corda 3, an error will be thrown if a flow creates multiple sessions per counterparty
- We're wrapping the call to
CollectSignaturesFlow
inCollectSignaturesInitiatingFlow
. Why? In Corda, there are two types of flow:Initiating
and inlined. EachInitiating
flow instance has a unique ID, while each inlined flow inherits the ID of the flow that called it as a subflow. As of Corda 3, an exception is thrown if a responder is invoked twice for the same flow ID. By wrappingCollectSignaturesFlow
(an inlined flow) insideCollectSignaturesInitiatingFlow
(anInitiating
flow), we create a new flow ID for each attempt to gather signatures, and no exception is thrown
Once you have the fully-signed transactions, you can call FinalityFlow
in a loop:
for (transaction in fullySignedTransactions) {
subFlow(FinalityFlow(transaction))
}
来源:https://stackoverflow.com/questions/50797667/corda-returning-multiple-transactions-in-a-single-flow-call