现金合同验证

Cash contract verification

我在现金合同验证失败的收集签名流程中遇到问题 - 提供错误消息

Contract verification failed: Failed requirement: for reference [01] at issuer C=US,L=New York,O=PartyB the amounts balance: 300000 - 0 != 0, contract: net.corda.finance.contracts.asset.Cash@7d43e51b

这似乎是因为输入的现金数量不等于输出的现金数量 + 退出分类帐的数量。

"for reference ${issuer.reference} at issuer ${issuer.party} the amounts balance: ${inputAmount.quantity} - ${amountExitingLedger.quantity} != ${outputAmount.quantity}" using
                            (inputAmount == outputAmount + amountExitingLedger)

然而,为了在交易中生成现金状态,我只是使用 Cash.generateSpend() 函数,所以我不确定这个错误可能是由什么引起的。使用的现金是在我们的模拟开始时自行发行的,并且可能在调用导致此问题的流程之前在节点之间移动。

我看不到正在输入的现金状态的确切值,但我可以看到有 2 个状态。现金输出就是花费的金额(3102 美元)加上其他两个州返回党花费 3102 美元,其中一个价值 97991898 美元和 97995000 美元。该派对最初在模拟开始时发行了 98000000 美元 - 因此第三个输出状态为 97995000 美元似乎很奇怪。由于 $97991898 + $3102 = $97995000,这两个输入状态的总和似乎很可能为 $97995000 并且该方已经在另一个流中花费了 $5000 - 使得第三次现金输出 $97995000 似乎不知从何而来。

这个问题可能是由 Cash.generateSpend() 中出现问题引起的吗?我没有添加任何其他现金输入或输出状态(我附上了下面的流程)。我还注意到,只有当我让产生 5000 美元支出的流程发生时才会出现此问题(即甲方向 B 支付 5000 美元,这笔款项已最终确定并记录在分类帐中,然后尝试在此处以单独的流程向 B 支付另一笔款项)。

//STEP 4: Build the transaction
val notary = serviceHub.networkMapCache.notaryIdentities.first()
val builder = TransactionBuilder(notary)
val builder2 = TermDeposit().generateRedeem(builder, TermDeposit)
//Add our required cash
val (tx, cashKeys) = Cash.generateSpend(serviceHub, builder2, Amount((TermDeposit.state.data.depositAmount.quantity * (100+TermDeposit.state.data.interestPercent)/100).toLong(), USD), flow.counterparty)
println("Redeem added cash ${Amount((TermDeposit.state.data.depositAmount.quantity * (100+TermDeposit.state.data.interestPercent)/100).toLong(), USD)}")

//STEP 5: Get the client to sign the transaction
println("Inputs ${tx.inputStates()}")
println("Outputs ${tx.outputStates()}")
val partSignedTxn = serviceHub.signInitialTransaction(tx, cashKeys)
println("Before collect sigs")
val otherPartySig = subFlow(CollectSignaturesFlow(partSignedTxn, listOf(flow), CollectSignaturesFlow.tracker()))
println("after collect sigs")

//STEP 6: Merge all signatures and commit this to the ledger
val twiceSignedTx = partSignedTxn.plus(otherPartySig.sigs) 
println("Redeem before finality flow")
return subFlow(FinalityFlow(twiceSignedTx))

我知道这个问题很开放,但如果能指出我可能出错的地方,我将不胜感激。

对于 运行 遇到此 problem/similar 现金验证问题的任何人,我能够通过创建一个节点来充当中央现金发行人而不是在开始时自行发行现金来解决此问题模拟的时候,我使用了CashIssueAndPayment流程,给每个节点发送一定数量的现金。

我仍然不确定这个问题是由我的流程中的某些东西引起的,还是由单一方是现金状态的发行者和接收者这一事实引起的——如果有人对此有意见,我会很高兴听到!

这是Cash.verify()的相关部分:

val groups = tx.groupStates { it: Cash.State -> it.amount.token }

for ((inputs, outputs, key) in groups) {
    val issuer = key.issuer
    val currency = key.product

    val inputAmount = inputs.sumCashOrNull() ?: throw IllegalArgumentException("there is at least one cash input for this group")
    val outputAmount = outputs.sumCashOrZero(Issued(issuer, currency))

    val exitKeys = inputs.flatMap { it.exitKeys }.toSet()
    val exitCommand = tx.commands.select<Commands.Exit>(parties = null, signers = exitKeys).filter { it.value.amount.token == key }.singleOrNull()
    val amountExitingLedger = exitCommand?.value?.amount ?: Amount(0, Issued(issuer, currency))

    requireThat {
        "for reference ${issuer.reference} at issuer ${issuer.party} the amounts balance: " +
            "${inputAmount.quantity} - ${amountExitingLedger.quantity} != ${outputAmount.quantity}" using
            (inputAmount == outputAmount + amountExitingLedger)
    }
}

groupStates returns 列表的列表,其中每个列表包含对应于给定 Issuer<Currency>.

的输入和输出

与不同 Issuer<Currency> 相关的现金状态不可替代。换句话说,交易必须为每个 Issuer<Currency> 输出与接收(忽略退出)一样多的现金。

这里最有可能的问题是您输入了一些现金并用不同的 Issuer<Currency> 输出了它。如果您调试您的流程并在验证之前检查交易的内容,您应该能够确定是否属于这种情况。