From 04e41b5ed4a8a1c3520718fa20e7540e12a73c2a Mon Sep 17 00:00:00 2001 From: Andrius Dagys Date: Thu, 9 Feb 2017 14:55:02 +0000 Subject: [PATCH] Include Merkle tree root hash in FilteredTransaction Remove no longer needed test. Make FilteredTransaction constructor private --- .../core/transactions/MerkleTransaction.kt | 18 +++++++------ .../core/crypto/PartialMerkleTreeTest.kt | 4 +-- .../net/corda/irs/api/NodeInterestRates.kt | 8 +++--- .../net/corda/irs/flows/RatesFixFlow.kt | 6 ++--- .../irs/testing/NodeInterestRatesTest.kt | 25 +++++-------------- 5 files changed, 24 insertions(+), 37 deletions(-) diff --git a/core/src/main/kotlin/net/corda/core/transactions/MerkleTransaction.kt b/core/src/main/kotlin/net/corda/core/transactions/MerkleTransaction.kt index 2cd6811dd3..a662a4a5e8 100644 --- a/core/src/main/kotlin/net/corda/core/transactions/MerkleTransaction.kt +++ b/core/src/main/kotlin/net/corda/core/transactions/MerkleTransaction.kt @@ -80,10 +80,12 @@ class FilteredLeaves( /** * Class representing merkleized filtered transaction. + * @param rootHash Merkle tree root hash. * @param filteredLeaves Leaves included in a filtered transaction. * @param partialMerkleTree Merkle branch needed to verify filteredLeaves. */ -class FilteredTransaction( +class FilteredTransaction private constructor( + val rootHash: SecureHash, val filteredLeaves: FilteredLeaves, val partialMerkleTree: PartialMerkleTree ) { @@ -99,26 +101,26 @@ class FilteredTransaction( val filteredLeaves = wtx.filterWithFun(filtering) val merkleTree = wtx.getMerkleTree() val pmt = PartialMerkleTree.build(merkleTree, filteredLeaves.calculateLeavesHashes()) - return FilteredTransaction(filteredLeaves, pmt) + return FilteredTransaction(merkleTree.hash, filteredLeaves, pmt) } } /** - * Runs verification of Partial Merkle Branch with merkleRootHash. + * Runs verification of Partial Merkle Branch against [rootHash]. */ @Throws(MerkleTreeException::class) - fun verify(merkleRootHash: SecureHash): Boolean { + fun verify(): Boolean { val hashes: List = filteredLeaves.calculateLeavesHashes() if (hashes.isEmpty()) throw MerkleTreeException("Transaction without included leaves.") - return partialMerkleTree.verify(merkleRootHash, hashes) + return partialMerkleTree.verify(rootHash, hashes) } /** - * Runs verification of Partial Merkle Branch with merkleRootHash. Checks filteredLeaves with provided checkingFun. + * Runs verification of Partial Merkle Branch against [rootHash]. Checks filteredLeaves with provided checkingFun. */ @Throws(MerkleTreeException::class) - fun verifyWithFunction(merkleRootHash: SecureHash, checkingFun: (Any) -> Boolean): Boolean { - return verify(merkleRootHash) && filteredLeaves.checkWithFun { checkingFun(it) } + fun verifyWithFunction(checkingFun: (Any) -> Boolean): Boolean { + return verify() && filteredLeaves.checkWithFun { checkingFun(it) } } } diff --git a/core/src/test/kotlin/net/corda/core/crypto/PartialMerkleTreeTest.kt b/core/src/test/kotlin/net/corda/core/crypto/PartialMerkleTreeTest.kt index b8b0b3bc9a..fa68ffb1d6 100644 --- a/core/src/test/kotlin/net/corda/core/crypto/PartialMerkleTreeTest.kt +++ b/core/src/test/kotlin/net/corda/core/crypto/PartialMerkleTreeTest.kt @@ -113,7 +113,7 @@ class PartialMerkleTreeTest { assertTrue(mt.filteredLeaves.timestamp != null) assertEquals(null, mt.filteredLeaves.type) assertEquals(null, mt.filteredLeaves.notary) - assert(mt.verify(testTx.id)) + assert(mt.verify()) } @Test @@ -131,7 +131,7 @@ class PartialMerkleTreeTest { assertTrue(mt.filteredLeaves.inputs.isEmpty()) assertTrue(mt.filteredLeaves.outputs.isEmpty()) assertTrue(mt.filteredLeaves.timestamp == null) - assertFailsWith { mt.verify(testTx.id) } + assertFailsWith { mt.verify() } } // Partial Merkle Tree building tests diff --git a/samples/irs-demo/src/main/kotlin/net/corda/irs/api/NodeInterestRates.kt b/samples/irs-demo/src/main/kotlin/net/corda/irs/api/NodeInterestRates.kt index aedf23af3f..cd40735fa3 100644 --- a/samples/irs-demo/src/main/kotlin/net/corda/irs/api/NodeInterestRates.kt +++ b/samples/irs-demo/src/main/kotlin/net/corda/irs/api/NodeInterestRates.kt @@ -79,7 +79,7 @@ object NodeInterestRates { @Suspendable override fun call() { val request = receive(otherParty).unwrap { it } - send(otherParty, service.oracle.sign(request.ftx, request.rootHash)) + send(otherParty, service.oracle.sign(request.ftx)) } } @@ -189,8 +189,8 @@ object NodeInterestRates { // Oracle gets signing request for only some of them with a valid partial tree? We sign over a whole transaction. // It will be fixed by adding partial signatures later. // DOCSTART 1 - fun sign(ftx: FilteredTransaction, merkleRoot: SecureHash): DigitalSignature.LegallyIdentifiable { - if (!ftx.verify(merkleRoot)) { + fun sign(ftx: FilteredTransaction): DigitalSignature.LegallyIdentifiable { + if (!ftx.verify()) { throw MerkleTreeException("Rate Fix Oracle: Couldn't verify partial Merkle tree.") } // Performing validation of obtained FilteredLeaves. @@ -219,7 +219,7 @@ object NodeInterestRates { // Note that we will happily sign an invalid transaction, as we are only being presented with a filtered // version so we can't resolve or check it ourselves. However, that doesn't matter much, as if we sign // an invalid transaction the signature is worthless. - return signingKey.signWithECDSA(merkleRoot.bytes, identity) + return signingKey.signWithECDSA(ftx.rootHash.bytes, identity) } // DOCEND 1 } diff --git a/samples/irs-demo/src/main/kotlin/net/corda/irs/flows/RatesFixFlow.kt b/samples/irs-demo/src/main/kotlin/net/corda/irs/flows/RatesFixFlow.kt index 917cc2b9f1..c35d913a6d 100644 --- a/samples/irs-demo/src/main/kotlin/net/corda/irs/flows/RatesFixFlow.kt +++ b/samples/irs-demo/src/main/kotlin/net/corda/irs/flows/RatesFixFlow.kt @@ -45,7 +45,7 @@ open class RatesFixFlow(protected val tx: TransactionBuilder, class FixOutOfRange(@Suppress("unused") val byAmount: BigDecimal) : Exception("Fix out of range by $byAmount") data class QueryRequest(val queries: List, val deadline: Instant) - data class SignRequest(val rootHash: SecureHash, val ftx: FilteredTransaction) + data class SignRequest(val ftx: FilteredTransaction) // DOCSTART 2 @Suspendable @@ -109,9 +109,7 @@ open class RatesFixFlow(protected val tx: TransactionBuilder, val partialMerkleTx: FilteredTransaction) : FlowLogic() { @Suspendable override fun call(): DigitalSignature.LegallyIdentifiable { - val wtx = tx.toWireTransaction() - val rootHash = wtx.id - val resp = sendAndReceive(oracle, SignRequest(rootHash, partialMerkleTx)) + val resp = sendAndReceive(oracle, SignRequest(partialMerkleTx)) return resp.unwrap { sig -> check(sig.signer == oracle) tx.checkSignature(sig) diff --git a/samples/irs-demo/src/test/kotlin/net/corda/irs/testing/NodeInterestRatesTest.kt b/samples/irs-demo/src/test/kotlin/net/corda/irs/testing/NodeInterestRatesTest.kt index afed9222a4..9d8608e719 100644 --- a/samples/irs-demo/src/test/kotlin/net/corda/irs/testing/NodeInterestRatesTest.kt +++ b/samples/irs-demo/src/test/kotlin/net/corda/irs/testing/NodeInterestRatesTest.kt @@ -137,12 +137,12 @@ class NodeInterestRatesTest { } } val ftx1 = wtx1.buildFilteredTransaction(::filterAllOutputs) - assertFailsWith { oracle.sign(ftx1, wtx1.id) } + assertFailsWith { oracle.sign(ftx1) } tx.addCommand(Cash.Commands.Move(), ALICE_PUBKEY) val wtx2 = tx.toWireTransaction() val ftx2 = wtx2.buildFilteredTransaction { x -> filterCmds(x) } assertFalse(wtx1.id == wtx2.id) - assertFailsWith { oracle.sign(ftx2, wtx2.id) } + assertFailsWith { oracle.sign(ftx2) } } } @@ -155,7 +155,7 @@ class NodeInterestRatesTest { // Sign successfully. val wtx = tx.toWireTransaction() val ftx = wtx.buildFilteredTransaction { x -> fixCmdFilter(x) } - val signature = oracle.sign(ftx, wtx.id) + val signature = oracle.sign(ftx) tx.checkAndAddSignature(signature) } } @@ -169,7 +169,7 @@ class NodeInterestRatesTest { tx.addCommand(badFix, oracle.identity.owningKey) val wtx = tx.toWireTransaction() val ftx = wtx.buildFilteredTransaction { x -> fixCmdFilter(x) } - val e1 = assertFailsWith { oracle.sign(ftx, wtx.id) } + val e1 = assertFailsWith { oracle.sign(ftx) } assertEquals(fixOf, e1.fix) } } @@ -189,7 +189,7 @@ class NodeInterestRatesTest { tx.addCommand(fix, oracle.identity.owningKey) val wtx = tx.toWireTransaction() val ftx = wtx.buildFilteredTransaction(::filtering) - assertFailsWith { oracle.sign(ftx, wtx.id) } + assertFailsWith { oracle.sign(ftx) } } } @@ -198,20 +198,7 @@ class NodeInterestRatesTest { val tx = makeTX() val wtx = tx.toWireTransaction() val ftx = wtx.buildFilteredTransaction({ false }) - assertFailsWith { oracle.sign(ftx, wtx.id) } - } - - @Test - fun `partial tree verification exception`() { - databaseTransaction(database) { - val tx = makeTX() - val wtx1 = tx.toWireTransaction() - tx.addCommand(Cash.Commands.Move(), ALICE_PUBKEY) - val wtx2 = tx.toWireTransaction() - val ftx2 = wtx2.buildFilteredTransaction { x -> filterCmds(x) } - assertFalse(wtx1.id == wtx2.id) - assertFailsWith { oracle.sign(ftx2, wtx1.id) } - } + assertFailsWith { oracle.sign(ftx) } } @Test