在 Cordapp 中,我想更新第二条链作为正常交易的一部分。由于数据在具有不同参与者的两个不同状态中被跟踪,因此这需要在两个事务中完成。
出于讨论的目的,我们有两方 A 和 B。A 向 B 发起事务 1。在接收事务 1 后,B 方启动事务 2 以更新另一个状态。我们如何确保两个事务都成功完成?
有两种方法可以解决这个问题:
subFlow
对于事务 2 内联流响应器。 vaultTrack
响应已提交的事务 1 并启动 subFlow
对于交易 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
}
}
每种方法的优缺点是什么?
我对选项 1 的担忧是单个流中的两个事务不是原子的。两个事务中的一个可能失败,另一个成功,这将使数据处于不一致的状态。例如:
subFlow
在上面的响应者中,交易 2 可能会成功,但交易 1 可能会因双花问题而无法通过公证。在那种情况下,第二条链会被不正确地更新。使用
vaultTrack
会更安全,因为事务 1 会成功,但无法保证事务 2 最终会完成。
最佳答案
首先,你说:
As the data is tracked in two separate states with different participants this would need to be done in two transactions.
这不一定是真的。具有不同参与者的两个独立状态可以是同一事务的一部分。但是,让我们假设您有理由在此处将它们分开(例如隐私)。
从 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
}
}
附言实现多事务原子性的一种可能方法是使用保留,如下所示:
然而,我想到的一种攻击是
FinalityFlow
的调用者。因为 Tx1 不会在 Tx1 上分发公证人的签名,允许他们在不放弃 Tx1 的情况下要求 Tx2。如果公证人将其所有签名发布到某个公告板上而不是依赖于 FinalityFlow
的调用者,这将得到解决。分发它们。
关于corda - 在同一个 Corda 流程中创建多个交易有什么风险?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54212354/