Corda 的 Ledger Sync 在某些情况下不同步保管库状态

标签 corda

我们目前正致力于在我们的 Cordapp 中集成 Ledger Sync Service:https://github.com/corda/corda-solutions/tree/master/bn-apps/ledger-sync

在我们自己的测试中,我们体验到在某些情况下,账本在崩溃后没有成功同步/修复。

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

  • 节点 AB相互交易,创建状态 S .
  • 节点 B崩溃并恢复到它不知道的状态 S .
  • 节点 A创建一个使用状态 S 的新事务
  • 节点 B使用账本同步服务恢复所有状态。

  • 在后台,会发生以下情况:当节点 A创建使用状态 S 的 Tx , 节点 B还将收到创建状态 S 的旧 Tx作为依赖。从那时起,Tx 记录在节点 B 的数据库中。并且可以通过调用 serviceHub.validatedTransactions.getTransaction(txId) 来检索.

    但是,在保管库中查询 CONSUMEDALL states 不会返回旧状态 S .运行账本同步会报告节点不同步,说创建状态的事务S不见了。

    调用修复将无法成功修复,连续运行RequestLedgersSyncFlow将继续报告丢失的交易。

    我不确定这个用例是否真的受支持(在分类帐不同步时创建 Txs),但我认为如果它不是受支持的用例,则很难确保节点之间没有相互交易的节点不同步。

    我希望问题清楚,否则我也可以为此准备并提供测试。

    更新:
    根据要求,我在这里创建了 Corda Solutions 存储库的一个分支,并添加了一个显示错误的测试:https://github.com/marioschlipf/corda-solutions/commit/fe1ab5917c971fcf9732bf8af7d0f2c1800b5e37

    最佳答案

    我已经重新创建了四​​个节点运行从 master 构建的 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 部署到三个节点(Alice A,Bob B,Charlie C)。使用了非验证公证人 (N)。

    考虑以下步骤来模拟故障和恢复。
  • 开始A , B , CN使用 H2 作为数据库
  • 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 , 用 C 开始一个流程, 利用 linearId在 4 中获得作为前体。 IE。 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并验证参与者是否处于未消费状态 BC (即 "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}表示AB 不同步.
  • 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 )以检索内容并验证已重新创建状态。

  • 这是否涵盖了您所描述的场景?

    关于Corda 的 Ledger Sync 在某些情况下不同步保管库状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54231839/

    相关文章:

    corda - 如何在 Corda 流程中创建随机数生成?

    postgresql - 我们如何将 Corda 连接到 Azure PostgreSQL?

    corda - 用于向交易对手隐藏 State 字段的 Merkle 树?

    networking - 如何为corda网络创建自签名证书?

    corda - 法律散文用法 Corda

    java - Jarsigner 签署 Corda 工作流程 jar 时出现重复条目​​错误

    Corda:契约(Contract)附件如何在交易中传输?

    corda - 网络根信任库和 keystore 之间有什么关系?

    java - 如何在运行时之前验证 RPC 调用的可变参数?

    database - Corda - 账本、保险库和存储服务之间的区别