在Cordapp中,我想更新第二条链作为正常交易的一部分。由于在具有不同参与者的两个单独状态下跟踪数据,因此需要在两个事务中完成。
出于讨论的目的,我们有两个甲方和乙方。A与B发起事务1。在收到事务1时,乙方启动事务2以更新另一个状态。我们如何确保两项交易成功完成?
有两种方法可以解决此问题:
subFlow
。vaultTrack
来响应已提交的事务1,并为事务2启动subFlow
。以下是选项1的一些示例代码:
class CustomerIssueFlowResponder(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 CustomerState." using (output is CustomerState)
}
}
// signing transaction 1
val stx = subFlow(signTransactionFlow)
val customerState = stx.tx.outputs.single().data as CustomerState
// initiating transaction 2
subFlow(CustomerIssueOrUpdateFlow(customerState))
return stx
}
}
每种方法的优缺点是什么?
我对选项1的担心是,单个流程中的两个事务不是原子的。两个事务之一可能失败,另一个事务成功,这将使数据处于不一致状态。例如:上方响应者中的subFlow
对于事务2可能成功,但是事务1在两次花销问题上经过公证时可能失败。在这种情况下,第二条链将被不正确地更新。
使用vaultTrack
会更安全,因为事务1将成功完成,但是没有什么可以保证事务2最终将完成。
答案 0 :(得分:2)
首先,您说:
由于在两个不同的状态下跟踪数据,因此状态不同 参与者这需要分两次完成。
这不一定是正确的。具有不同参与者的两个独立状态可以成为同一事务的一部分。但是,假设您有理由在此处将它们分开(例如隐私)。
从Corda 4开始,该平台不提供多重交易原子性保证。没有内置的方法可以确保仅在提交另一笔交易时才提交给定的交易(但请参见下面的P.S。)。
因此,您的任何选择都不保证多重交易原子性。我仍然相信选项1会更可取,因为您将获得流程将被调用的保证。您担心的是,即使第一个事务失败,响应者也会调用创建第二个事务的流程。可以避免使用waitForLedgerCommit
来确保事务1在启动流程以创建第二个事务之前已提交:
class CustomerIssueFlowResponder(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 CustomerState." using (output is CustomerState)
}
}
// signing transaction 1
val stx = subFlow(signTransactionFlow)
val customerState = stx.tx.outputs.single().data as CustomerState
// initiating transaction 2 once transaction 1 is committed
waitForLedgerCommit(stx.id)
subFlow(CustomerIssueOrUpdateFlow(customerState))
return stx
}
}
P.S。实现多事务原子性的一种可能方法是使用保留,如下所示:
但是,想到的一种攻击是FinalityFlow
的调用者为Tx1没有在Tx1上分配公证人的签名,从而使他们可以在不放弃Tx1的情况下主张Tx2。如果公证人将所有签名发布到某个公告板上,而不是依靠FinalityFlow
的调用者来分发它们,则可以解决此问题。