我们目前正在将分类帐同步服务集成到我们的Cordapp中:https://github.com/corda/corda-solutions/tree/master/bn-apps/ledger-sync
在我们自己的测试中,我们发现在某些情况下,崩溃后账本无法成功同步/修复。
我们的测试执行以下操作:
A
和B
彼此进行事务,创建状态S
。B
崩溃并恢复到不知道S
的状态。A
创建一个新事务,该事务使用状态S
B
使用分类帐同步服务来恢复所有状态。在后台,发生以下情况:当节点A
创建使用状态S
的Tx时,节点B
还将收到创建状态{{1}的旧Tx }作为依赖项。从那时起,Tx记录在节点S
的数据库中,可以通过调用B
来检索。
但是,查询库中的serviceHub.validatedTransactions.getTransaction(txId)
或CONSUMED
状态不会返回旧状态ALL
。运行分类帐同步将报告该节点不同步,表示创建状态S
的事务丢失。
致电修复将无法成功修复,连续运行S
将继续报告丢失的事务。
我不确定该用例是否真正受支持(在分类帐不同步时创建Tx),但是我认为,如果不是受支持的用例,则很难确定节点是否与每个用例进行事务处理其他当其中一个节点不同步时。
我希望问题已经解决,否则我也可以为此做准备并提供测试。
更新: 根据要求,我在此处创建了Corda Solutions回购的分支,并添加了一个显示错误的测试:https://github.com/marioschlipf/corda-solutions/commit/fe1ab5917c971fcf9732bf8af7d0f2c1800b5e37
答案 0 :(得分:1)
我重新创建了该方案,其中有四个节点运行从主节点构建的 Ledger Sync Service (最新提交839dfb8772c3b08447183a84e336a527a0f3975b
)。我以以下方式修改了BogusFlow
以允许使用输入状态:
/**
* A trivial flow that is merely used to illustrate synchronisation by persisting meaningless transactions in
* participant's vaults
*/
@InitiatingFlow
@StartableByRPC
class BogusFlow(
private val them: Party,
private val precursor: UniqueIdentifier? = null
) : FlowLogic<SignedTransaction>() {
@Suspendable
override fun call(): SignedTransaction {
val notary = serviceHub.networkMapCache.notaryIdentities.first()
val cmd = Command(BogusContract.Commands.Bogus(), listOf(them.owningKey))
val builder = TransactionBuilder(notary)
precursor?.let {
val result = serviceHub.vaultService.queryBy(BogusState::class.java, LinearStateQueryCriteria(linearId = listOf(it)))
val inputState = result.states.single()
builder.addInputState(inputState)
}
builder.addOutputState(BogusState(ourIdentity, them), BOGUS_CONTRACT_ID)
.addCommand(cmd).apply {
verify(serviceHub)
}
val partiallySigned = serviceHub.signInitialTransaction(builder)
val session = initiateFlow(them)
val fullySigned = subFlow(CollectSignaturesFlow(partiallySigned, setOf(session)))
return subFlow(FinalityFlow(fullySigned))
}
}
包含该流的CorDapp被部署到三个节点(爱丽丝A
,鲍勃B
,查理C
)。使用了非验证公证人(N
)。
请考虑以下步骤来模拟故障和还原。
A
,B
,C
和N
A
身份调用net.corda.businessnetworks.ledgersync.BogusFlow
,以O=Bob Ltd., L=London, C=GB
为目标A
并破坏数据库,即rm persistence.mv.db
B
一样,为contractStateType net.corda.businessnetworks.ledgersync.BogusState
运行vaultQuery以验证B
是否了解 2 之后的未消耗状态。输出应包含linearId
。记下此ID。B
一样,以在{em> 4 中获得的C
作为前导,从linearId
开始流程。即flow start net.corda.businessnetworks.ledgersync.BogusFlow them: "O=Charlie SARL, L=Paris, C=FR", precursor: "2429c289-0ccb-4adb-9714-32ee3d0d7f12"
。请注意,在生产用例中,鉴于A
尚未签署,您的合同代码可能会首先禁止执行此交易。B
的身份运行vaultQuery contractStateType: net.corda.businessnetworks.ledgersync.BogusState
,并验证参与者B
和C
(即"participants" : [ "O=Bob Ltd., L=London, C=GB", "O=Charlie SARL, L=Paris, C=FR" ]
)是否处于未消费状态。A
的身份备份该节点,创建一个新的H2数据库。A
的身份开始EvaluateLedgerConsistencyFlow
(即connection.proxy.startFlow(::EvaluateLedgerConsistencyFlow, listOf(alice, bob, charlie))
)。这应该返回{O=Bob Ltd., L=London, C=GB=false, O=Charlie SARL, L=Paris, C=FR=true}
,指示A
与B
不同步。A
的身份运行RequestLedgersSyncFlow
(即connection.proxy.startFlow(::RequestLedgersSyncFlow, listOf(alice, bob, charlie))
)。这将返回丢失交易的摘要(例如{O=Bob Ltd., L=London, C=GB=LedgerSyncFindings(missingAtRequester=[BAA58E9E9E2025181F00459FCE8B0D035705A38D1068A0F4C4BAB53F3F56FB40], missingAtRequestee=[]), O=Charlie SARL, L=Paris, C=FR=LedgerSyncFindings(missingAtRequester=[], missingAtRequestee=[])}
)。A
的身份运行TransactionRecoveryFlow
,并传递9的结果。例如。 connection.proxy.startFlow(::TransactionRecoveryFlow, report)
,其中report
是上一步的结果。A
一样,要验证重新运行EvaluateLedgerConsistencyFlow
,它将返回结果{O=Bob Ltd., L=London, C=GB=true, O=Charlie SARL, L=Paris, C=FR=true}
,表明差异已解决。A
的身份运行保管库查询(即VaultQueryCriteria(status = ALL), PageSpecification(), Sort(emptyList()), BogusState::class.java
)以检索内容并验证状态是否已重新创建。这涵盖了您所描述的情况吗?