corda - 如何在一个流程中多次从同一对手方获取签名?
问题描述
我需要实现这样的场景,比如有 CentralParty、PartyA、PartyB。CentralParty 需要发起一个流程,循环中会有 3 笔交易,发起者始终是 Central 方,另一方是 A 方 2 次。
即我正在尝试通过参考以下链接从单个流程中多次从同一交易对手那里收集签名
val flowSessionMap = mutableMapOf<Party, FlowSession>()
var ftx:MutableList<SignedTransaction> = mutableListOf<SignedTransaction>()
var signedTransaction:SignedTransaction
val fullySignedTransactions = matchingStateList.forEach { matchingState ->
val txCommand = Command(IOUContract.Commands.Matching(), matchingState.participants.map { it.owningKey })
val txBuilder = TransactionBuilder(notary)
.addOutputState(matchingState, IOU_CONTRACT_ID)
.addCommand(txCommand)
// Stage 2.
progressTracker.currentStep = VERIFYING_TRANSACTION
// Verify that the transaction is valid.
txBuilder.verify(serviceHub)
// Stage 3.
progressTracker.currentStep = SIGNING_TRANSACTION
// Sign the transaction.
val partSignedTx = serviceHub.signInitialTransaction(txBuilder, ourIdentity.owningKey)
val sessions = (listOf(PartyA).map { signer ->
flowSessionMap.getOrPut(signer) {
initiateFlow(signer)
}
})
val fullySignedTransaction = subFlow(CollectSignaturesInitiatingFlow(
partSignedTx, sessions)
)
signedTransaction = fullySignedTransaction
ftx.add(signedTransaction)
}
for (transaction in ftx) {
subFlow(FinalityFlow(transaction))
}
响应者流定义如下:
class Acceptor(val otherPartyFlow: FlowSession) : FlowLogic<SignedTransaction>() {
@Suspendable
override fun call(): SignedTransaction {
val signTransactionFlow = object : SignTransactionFlow(otherPartyFlow) {
override fun checkTransaction(stx: SignedTransaction) = requireThat {
val output = stx.tx.outputs.single().data
"This must be an Matching State transaction." using (output is MatchingState)
val Match = output as MatchingState
"I won't accept IOUs with a value over 100." using (iou.value <= 100)
}
}
return subFlow(signTransactionFlow)
}
}
其中 CollectSignaturesInitiatingFlow 定义如下:
@InitiatingFlow
class CollectSignaturesInitiatingFlow(val signedTransaction: SignedTransaction, val sessions: List<FlowSession>): FlowLogic<SignedTransaction>() {
override fun call(): SignedTransaction {
return subFlow(CollectSignaturesFlow(signedTransaction, sessions))
}
}
CollectSignaturesInitiatingFlow 的响应者定义如下:
@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)
}
}
在运行相同的代码时,我遇到了一个错误,例如
[WARN ] 15:43:18,817 [Node thread-1] (FlowStateMachineImpl.kt:111) flow.[82900238-9223-4ace-ba78-9ecc45121b11].run - Terminated by unexpected exception {}
net.corda.core.flows.UnexpectedFlowEndException: Counterparty flow on O=PartyA, L=London, C=GB has completed without sending data
at net.corda.node.services.statemachine.FlowStateMachineImpl.confirmNoError(FlowStateMachineImpl.kt:488) ~[corda-node-3.2-corda.jar:?]
at net.corda.node.services.statemachine.FlowStateMachineImpl.waitForMessage(FlowStateMachineImpl.kt:444) ~[corda-node-3.2-corda.jar:?]
at net.corda.node.services.statemachine.FlowStateMachineImpl.sendAndReceiveInternal(FlowStateMachineImpl.kt:385) ~[corda-node-3.2-corda.jar:?]
at net.corda.node.services.statemachine.FlowStateMachineImpl.sendAndReceive(FlowStateMachineImpl.kt:203) ~[corda-node-3.2-corda.jar:?]
at net.corda.node.services.statemachine.FlowSessionImpl.sendAndReceive(FlowSessionImpl.kt:29) ~[corda-node-3.2-corda.jar:?]
at net.corda.node.services.statemachine.FlowSessionImpl.sendAndReceive(FlowSessionImpl.kt:40) ~[corda-node-3.2-corda.jar:?]
at net.corda.core.flows.DataVendingFlow.sendPayloadAndReceiveDataRequest(SendTransactionFlow.kt:70) ~[corda-core-3.2-corda.jar:?]
at net.corda.core.flows.DataVendingFlow.call(SendTransactionFlow.kt:48) ~[corda-core-3.2-corda.jar:?]
at net.corda.core.flows.DataVendingFlow.call(SendTransactionFlow.kt:31) ~[corda-core-3.2-corda.jar:?]
at net.corda.core.flows.FlowLogic.subFlow(FlowLogic.kt:290) ~[corda-core-3.2-corda.jar:?]
at net.corda.core.flows.CollectSignatureFlow.call(CollectSignaturesFlow.kt:142) ~[corda-core-3.2-corda.jar:?]
at net.corda.core.flows.CollectSignatureFlow.call(CollectSignaturesFlow.kt:135) ~[corda-core-3.2-corda.jar:?]
at net.corda.core.flows.FlowLogic.subFlow(FlowLogic.kt:290) ~[corda-core-3.2-corda.jar:?]
at net.corda.core.flows.CollectSignaturesFlow.call(CollectSignaturesFlow.kt:114) ~[corda-core-3.2-corda.jar:?]
at net.corda.core.flows.CollectSignaturesFlow.call(CollectSignaturesFlow.kt:64) ~[corda-core-3.2-corda.jar:?]
at net.corda.core.flows.FlowLogic.subFlow(FlowLogic.kt:290) ~[corda-core-3.2-corda.jar:?]
at com.example.flow.ExampleFlowMatching$CollectSignaturesInitiatingFlow.call(ExampleFlowMatching.kt:260) ~[classes/:?]
at com.example.flow.ExampleFlowMatching$CollectSignaturesInitiatingFlow.call(ExampleFlowMatching.kt:258) ~[classes/:?]
at net.corda.core.flows.FlowLogic.subFlow(FlowLogic.kt:290) ~[corda-core-3.2-corda.jar:?]
at com.example.flow.ExampleFlowMatching$ExampleFlowMatchingInitiator.call(ExampleFlowMatching.kt:202) ~[classes/:?]
at com.example.flow.ExampleFlowMatching$ExampleFlowMatchingInitiator.call(ExampleFlowMatching.kt:45) ~[classes/:?]
at net.corda.node.services.statemachine.FlowStateMachineImpl.run(FlowStateMachineImpl.kt:96) [corda-node-3.2-corda.jar:?]
at net.corda.node.services.statemachine.FlowStateMachineImpl.run(FlowStateMachineImpl.kt:44) [corda-node-3.2-corda.jar:?]
at co.paralleluniverse.fibers.Fiber.run1(Fiber.java:1092) [quasar-core-0.7.9-jdk8.jar:0.7.9]
at co.paralleluniverse.fibers.Fiber.exec(Fiber.java:788) [quasar-core-0.7.9-jdk8.jar:0.7.9]
at co.paralleluniverse.fibers.RunnableFiberTask.doExec(RunnableFiberTask.java:100) [quasar-core-0.7.9-jdk8.jar:0.7.9]
at co.paralleluniverse.fibers.RunnableFiberTask.run(RunnableFiberTask.java:91) [quasar-core-0.7.9-jdk8.jar:0.7.9]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [?:1.8.0_191]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) [?:1.8.0_191]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) [?:1.8.0_191]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) [?:1.8.0_191]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:1.8.0_191]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:1.8.0_191]
at net.corda.node.utilities.AffinityExecutor$ServiceAffinityExecutor$1$thread$1.run(AffinityExecutor.kt:62) [corda-node-3.2-corda.jar:?]
解决方案
问题是您在主要流程中启动流程会话ExampleFlowMatchingInitiator
,而不是在内部CollectSignaturesInitiatingFlow
。
当您调用时initiateFlow
,它会在当前InitiatingFlow
. 所以当你打电话initiateFlow
时ExampleFlowMatchingInitiator
,对方会检查它是否有任何响应者注册ExampleFlowMatchingInitiator
。它确实 -Acceptor
所以它开始一个流程会话来与使用Acceptor
.
如果您改为在initiateFlow
内部调用CollectSignaturesInitiatingFlow
,则交易对手将检查是否有任何响应者注册CollectSignaturesInitiatingFlow
。它确实 - - 所以它开始一个流程会话来与使用相反CollectSignaturesInitiatingFlowResponder
的交易对手交谈。CollectSignaturesInitiatingFlowResponder
推荐阅读
- javascript - Vue:从模板中删除“this”的 ESlint 规则
- flutter - 我想创建一个搜索栏,但有一些错误。代码如下
- r - 如何在 shinyapp 传单地图中使用 clusterOptions?
- python - 无法从 Python 连接到 Postgres
- python - 当列表中的一个键存在时,从字典中删除一个项目
- react-native - 反应原生 - 功能评估
- c# - && 和 || 在同一个表达式中
- python - 如何计算 numpy64float 类型的数组的平均值?
- angular - Angular网站移动浏览器页面速度
- google-chrome-extension - Chrome 扩展程序 | 多个警报同时响起