Проверка кассового договора
Я сталкиваюсь с проблемой во время потока сбора подписей, когда проверка кассового контракта не проходит - выдается сообщение об ошибке
Проверка контракта не удалась: Не выполнено требование: для ссылки [01] у эмитента C= США,L= Нью-Йорк,O= Сторона B остаток суммы: 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 долл. США. Партия изначально получила 98000000 долларов США в начале симуляции - поэтому наличие третьего состояния вывода в 97995000 долларов кажется очень странным. Представляется вероятным, что эти два входных состояния составляют 97995000 долларов США, начиная с 97991898 долларов США + 3102 доллара США = 97995000 долларов США, и что эта партия уже потратила 5000 долларов США в другом потоке, что делает этот третий денежный выпуск в размере 97995000 долларов США, казалось бы, ниоткуда.
Может ли эта проблема быть вызвана ошибкой в Cash.generateSpend()? Я не добавляю никакие другие входные или выходные состояния наличности (я приложил поток ниже). Я также отметил, что эта проблема возникает только в том случае, если я позволю потоку потратить 5000 долл. США (т. Е. Сторона А выплачивает 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))
Я знаю, что этот вопрос очень открытый, но любые указания на области, в которых я могу ошибаться, будут с благодарностью.
2 ответа
Вот соответствующая часть 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>
, Если вы отлаживаете свой поток и проверяете содержание транзакции, прежде чем она будет проверена, вы сможете определить, так ли это.
Для тех, кто сталкивался с этой проблемой / подобными проблемами с проверкой наличности, я смог исправить это, создав узел, выступающий в роли центрального эмитента наличных денег, а затем вместо самостоятельной выдачи наличных денег в начале моделирования я использовал поток CashIssueAndPayment и отправка определенной суммы денег каждому узлу.
Я все еще не уверен, была ли эта проблема вызвана чем-то в моих потоках или тем фактом, что одна сторона была эмитентом и получателем денежных состояний - если кто-то внесет свой вклад в это, было бы здорово услышать!