在 Cordapp 中,我想更新第二条链作为正常交易的一部分。由于数据是在两个不同的状态下由不同的参与者跟踪的,因此这需要在两个事务中完成。
为了讨论的目的,我们有 A 和 B 两方。A 向 B 发起交易 1。收到交易 1 后,B 方启动交易 2 以更新另一个状态。如何确保两笔交易均成功完成?
有两种方法可以解决这个问题:
subFlow事务 2 内联流响应程序。vaultTrack响应已提交的事务 1 并启动subFlowfor 事务 2。以下是选项 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
}
}
Run Code Online (Sandbox Code Playgroud)
每种方法的优点和缺点是什么?
我对选项 1 的担忧是单个流中的两个事务不是原子的。两个事务之一可能会失败,而另一个会成功,这将使数据处于不一致的状态。例如:subFlow上述响应者内部的事务 2 可能会成功,但事务 1 可能因双重支出问题而因公证而失败。在这种情况下,第二条链可能会被不正确地更新。
使用vaultTrack会更安全,因为事务 1 将成功,但无法保证事务 2 最终完成。
首先,你说:
由于数据是在两个不同的状态下由不同的参与者跟踪的,因此这需要在两个事务中完成。
这不一定是真的。具有不同参与者的两个独立状态可以是同一事务的一部分。但是,我们假设您有理由将它们分开(例如隐私)。
从 Corda 4 开始,该平台不提供多事务原子性保证。没有内置方法可以确保仅在提交另一个事务时才提交给定事务(但请参阅下面的 PS)。
所以你的选择都不能保证多事务原子性。我仍然相信选项 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
}
}
Run Code Online (Sandbox Code Playgroud)
PS 实现多事务原子性的一种可能方法是使用产权负担,如下所示:
然而,我想到的一种攻击是FinalityFlowTx1 的调用者没有在 Tx1 上分发公证人的签名,从而允许他们在不放弃 Tx1 的情况下索取 Tx2。如果公证人将其所有签名发布到某个公告板上,而不是依靠调用者FinalityFlow来分发它们,那么这个问题就可以解决。
| 归档时间: |
|
| 查看次数: |
674 次 |
| 最近记录: |