现金合同验证

时间:2017-11-30 02:14:28

标签: verification contract corda

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

  

合同验证失败:要求失败:对于发行人C = US的参考[01],L =纽约,O = PartyB,余额为:300000 - 0!= 0,合同: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美元。该派对最初在模拟开始时发行了9800万美元 - 所以这个第三个输出状态为97995000美元似乎很奇怪。似乎这两个输入状态总计为97995000美元,因为97991898美元+ 3102美元= 97995000美元,并且该方已经在另一个流程中花费了5000美元 - 这使得第三次现金输出97995000美元似乎无处可见。

这个问题可能是由Cash.generateSpend()出错吗?我没有添加任何其他输入或输出状态的现金(我已附上以下流程)。我还注意到这个问题只有在我让流量达到$ 5000花费的情况下才会发生(即甲方支付B $ 5000,最终确定并记录在分类账中,然后尝试在另一个流程中再向B付款)。 / p>

//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))

我知道这个问题是非常开放的,但是对于我可能出错的地方的任何指示都将非常感激。

2 个答案:

答案 0 :(得分:2)

对于遇到此问题的任何人/类似的现金验证问题,我能够通过创建一个节点作为中央现金发行人来解决这个问题,然后在模拟开始时代替自发现金,我使用CashIssueAndPayment流动,并向每个节点发送一定数量的现金。

我仍然不确定这个问题是由我的流程中的某些事情造成的,还是单方是现金状态的发行人和收件人这一事实 - 如果有人对此提出意见,我会很高兴听到!

答案 1 :(得分:1)

以下是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返回列表列表,其中每个列表包含与给定Issuer<Currency>对应的输入和输出。

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

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