From 6ba301b6b825697b1157693b2541a3371975cc9e Mon Sep 17 00:00:00 2001 From: jamescarlyle Date: Fri, 19 Aug 2016 17:45:25 +0100 Subject: [PATCH] Updated based on feedback to check that the encumbered state does not refer to itself as the encumbrance. --- .../core/contracts/TransactionTypes.kt | 12 +++++++- .../contracts/TransactionEncumbranceTests.kt | 29 +++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/core/src/main/kotlin/com/r3corda/core/contracts/TransactionTypes.kt b/core/src/main/kotlin/com/r3corda/core/contracts/TransactionTypes.kt index 994f1e2de6..c7ead96939 100644 --- a/core/src/main/kotlin/com/r3corda/core/contracts/TransactionTypes.kt +++ b/core/src/main/kotlin/com/r3corda/core/contracts/TransactionTypes.kt @@ -81,11 +81,21 @@ sealed class TransactionType { // Validate that all encumbrances exist within the set of input states. tx.inputs.filter { it.state.data.encumbrance != null }.forEach { encumberedInput -> - if (tx.inputs.none { it.ref.txhash == encumberedInput.ref.txhash && it.ref.index == encumberedInput.state.data.encumbrance }) { + if (tx.inputs.none { it.ref.txhash == encumberedInput.ref.txhash && + it.ref.index == encumberedInput.state.data.encumbrance }) { throw TransactionVerificationException.TransactionMissingEncumbranceException(tx) } } + // Check that an encumbered state does not refer to itself as the encumbrance, and that the number of outputs + // can contain the encumbrance. + tx.outputs.forEachIndexed { i, it -> + if (it.data.encumbrance != null) { + if (it.data.encumbrance == i || it.data.encumbrance!! >= tx.outputs.size) { + throw TransactionVerificationException.TransactionMissingEncumbranceException(tx) + } + } + } } override fun getRequiredSigners(tx: LedgerTransaction) = tx.commands.flatMap { it.signers }.toSet() diff --git a/core/src/test/kotlin/com/r3corda/core/contracts/TransactionEncumbranceTests.kt b/core/src/test/kotlin/com/r3corda/core/contracts/TransactionEncumbranceTests.kt index 87b6d1187b..b6f1a52c9f 100644 --- a/core/src/test/kotlin/com/r3corda/core/contracts/TransactionEncumbranceTests.kt +++ b/core/src/test/kotlin/com/r3corda/core/contracts/TransactionEncumbranceTests.kt @@ -67,6 +67,35 @@ class TransactionEncumbranceTests { this.verifies() } } + // An encumbered state must not be encumbered by itself. + assertFailsWith(TransactionVerificationException.TransactionMissingEncumbranceException::class) { + transaction { + input { unencumberedState } + input { unencumberedState } + output { unencumberedState } + // The encumbered state refers to an encumbrance in position 1, so what follows is wrong. + output { encumberedState } + command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } + this.verifies() + } + } + // An encumbered state must not reference an index greater than the size of the output states. + assertFailsWith(TransactionVerificationException.TransactionMissingEncumbranceException::class) { + transaction { + input { unencumberedState } + input { unencumberedState } + output { unencumberedState } + // The encumbered state refers to an encumbrance in position 1, so what follows is wrong. + output { encumberedState } + command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } + this.verifies() + } + } + + } + + @Test + fun testEncumbranceEffects() { // A transaction containing an input state that is encumbered must fail if the encumbrance is not in the correct position. assertFailsWith(TransactionVerificationException.TransactionMissingEncumbranceException::class) { ledger {