Corda的分类帐同步在某些情况下不同步保管库状态

时间:2019-01-17 08:34:25

标签: corda

我们目前正在将分类帐同步服务集成到我们的Cordapp中:https://github.com/corda/corda-solutions/tree/master/bn-apps/ledger-sync

在我们自己的测试中,我们发现在某些情况下,崩溃后账本无法成功同步/修复。

我们的测试执行以下操作:

  • 节点AB彼此进行事务,创建状态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

1 个答案:

答案 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)。

请考虑以下步骤来模拟故障和还原。

  1. 使用H2作为数据库启动ABCN
  2. A身份调用net.corda.businessnetworks.ledgersync.BogusFlow,以O=Bob Ltd., L=London, C=GB为目标
  3. 关闭节点A并破坏数据库,即rm persistence.mv.db
  4. B一样,为contractStateType net.corda.businessnetworks.ledgersync.BogusState运行vaultQuery以验证B是否了解 2 之后的未消耗状态。输出应包含linearId。记下此ID。
  5. 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尚未签署,您的合同代码可能会首先禁止执行此交易。
  6. B的身份运行vaultQuery contractStateType: net.corda.businessnetworks.ledgersync.BogusState,并验证参与者BC(即"participants" : [ "O=Bob Ltd., L=London, C=GB", "O=Charlie SARL, L=Paris, C=FR" ])是否处于未消费状态。
  7. A的身份备份该节点,创建一个新的H2数据库。
  8. 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},指示AB不同步。
  9. 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=[])})。
  10. A的身份运行TransactionRecoveryFlow,并传递9的结果。例如。 connection.proxy.startFlow(::TransactionRecoveryFlow, report),其中report是上一步的结果。
  11. A一样,要验证重新运行EvaluateLedgerConsistencyFlow,它将返回结果{O=Bob Ltd., L=London, C=GB=true, O=Charlie SARL, L=Paris, C=FR=true},表明差异已解决。
  12. 要进一步验证,请以A的身份运行保管库查询(即VaultQueryCriteria(status = ALL), PageSpecification(), Sort(emptyList()), BogusState::class.java)以检索内容并验证状态是否已重新创建。

这涵盖了您所描述的情况吗?