mirror of
https://github.com/corda/corda.git
synced 2025-01-01 02:36:44 +00:00
Include Merkle tree root hash in FilteredTransaction
Remove no longer needed test. Make FilteredTransaction constructor private
This commit is contained in:
parent
680bf8e462
commit
04e41b5ed4
@ -80,10 +80,12 @@ class FilteredLeaves(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Class representing merkleized filtered transaction.
|
* Class representing merkleized filtered transaction.
|
||||||
|
* @param rootHash Merkle tree root hash.
|
||||||
* @param filteredLeaves Leaves included in a filtered transaction.
|
* @param filteredLeaves Leaves included in a filtered transaction.
|
||||||
* @param partialMerkleTree Merkle branch needed to verify filteredLeaves.
|
* @param partialMerkleTree Merkle branch needed to verify filteredLeaves.
|
||||||
*/
|
*/
|
||||||
class FilteredTransaction(
|
class FilteredTransaction private constructor(
|
||||||
|
val rootHash: SecureHash,
|
||||||
val filteredLeaves: FilteredLeaves,
|
val filteredLeaves: FilteredLeaves,
|
||||||
val partialMerkleTree: PartialMerkleTree
|
val partialMerkleTree: PartialMerkleTree
|
||||||
) {
|
) {
|
||||||
@ -99,26 +101,26 @@ class FilteredTransaction(
|
|||||||
val filteredLeaves = wtx.filterWithFun(filtering)
|
val filteredLeaves = wtx.filterWithFun(filtering)
|
||||||
val merkleTree = wtx.getMerkleTree()
|
val merkleTree = wtx.getMerkleTree()
|
||||||
val pmt = PartialMerkleTree.build(merkleTree, filteredLeaves.calculateLeavesHashes())
|
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)
|
@Throws(MerkleTreeException::class)
|
||||||
fun verify(merkleRootHash: SecureHash): Boolean {
|
fun verify(): Boolean {
|
||||||
val hashes: List<SecureHash> = filteredLeaves.calculateLeavesHashes()
|
val hashes: List<SecureHash> = filteredLeaves.calculateLeavesHashes()
|
||||||
if (hashes.isEmpty())
|
if (hashes.isEmpty())
|
||||||
throw MerkleTreeException("Transaction without included leaves.")
|
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)
|
@Throws(MerkleTreeException::class)
|
||||||
fun verifyWithFunction(merkleRootHash: SecureHash, checkingFun: (Any) -> Boolean): Boolean {
|
fun verifyWithFunction(checkingFun: (Any) -> Boolean): Boolean {
|
||||||
return verify(merkleRootHash) && filteredLeaves.checkWithFun { checkingFun(it) }
|
return verify() && filteredLeaves.checkWithFun { checkingFun(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,7 +113,7 @@ class PartialMerkleTreeTest {
|
|||||||
assertTrue(mt.filteredLeaves.timestamp != null)
|
assertTrue(mt.filteredLeaves.timestamp != null)
|
||||||
assertEquals(null, mt.filteredLeaves.type)
|
assertEquals(null, mt.filteredLeaves.type)
|
||||||
assertEquals(null, mt.filteredLeaves.notary)
|
assertEquals(null, mt.filteredLeaves.notary)
|
||||||
assert(mt.verify(testTx.id))
|
assert(mt.verify())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -131,7 +131,7 @@ class PartialMerkleTreeTest {
|
|||||||
assertTrue(mt.filteredLeaves.inputs.isEmpty())
|
assertTrue(mt.filteredLeaves.inputs.isEmpty())
|
||||||
assertTrue(mt.filteredLeaves.outputs.isEmpty())
|
assertTrue(mt.filteredLeaves.outputs.isEmpty())
|
||||||
assertTrue(mt.filteredLeaves.timestamp == null)
|
assertTrue(mt.filteredLeaves.timestamp == null)
|
||||||
assertFailsWith<MerkleTreeException> { mt.verify(testTx.id) }
|
assertFailsWith<MerkleTreeException> { mt.verify() }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Partial Merkle Tree building tests
|
// Partial Merkle Tree building tests
|
||||||
|
@ -79,7 +79,7 @@ object NodeInterestRates {
|
|||||||
@Suspendable
|
@Suspendable
|
||||||
override fun call() {
|
override fun call() {
|
||||||
val request = receive<RatesFixFlow.SignRequest>(otherParty).unwrap { it }
|
val request = receive<RatesFixFlow.SignRequest>(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.
|
// 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.
|
// It will be fixed by adding partial signatures later.
|
||||||
// DOCSTART 1
|
// DOCSTART 1
|
||||||
fun sign(ftx: FilteredTransaction, merkleRoot: SecureHash): DigitalSignature.LegallyIdentifiable {
|
fun sign(ftx: FilteredTransaction): DigitalSignature.LegallyIdentifiable {
|
||||||
if (!ftx.verify(merkleRoot)) {
|
if (!ftx.verify()) {
|
||||||
throw MerkleTreeException("Rate Fix Oracle: Couldn't verify partial Merkle tree.")
|
throw MerkleTreeException("Rate Fix Oracle: Couldn't verify partial Merkle tree.")
|
||||||
}
|
}
|
||||||
// Performing validation of obtained FilteredLeaves.
|
// 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
|
// 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
|
// 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.
|
// an invalid transaction the signature is worthless.
|
||||||
return signingKey.signWithECDSA(merkleRoot.bytes, identity)
|
return signingKey.signWithECDSA(ftx.rootHash.bytes, identity)
|
||||||
}
|
}
|
||||||
// DOCEND 1
|
// DOCEND 1
|
||||||
}
|
}
|
||||||
|
@ -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")
|
class FixOutOfRange(@Suppress("unused") val byAmount: BigDecimal) : Exception("Fix out of range by $byAmount")
|
||||||
|
|
||||||
data class QueryRequest(val queries: List<FixOf>, val deadline: Instant)
|
data class QueryRequest(val queries: List<FixOf>, val deadline: Instant)
|
||||||
data class SignRequest(val rootHash: SecureHash, val ftx: FilteredTransaction)
|
data class SignRequest(val ftx: FilteredTransaction)
|
||||||
|
|
||||||
// DOCSTART 2
|
// DOCSTART 2
|
||||||
@Suspendable
|
@Suspendable
|
||||||
@ -109,9 +109,7 @@ open class RatesFixFlow(protected val tx: TransactionBuilder,
|
|||||||
val partialMerkleTx: FilteredTransaction) : FlowLogic<DigitalSignature.LegallyIdentifiable>() {
|
val partialMerkleTx: FilteredTransaction) : FlowLogic<DigitalSignature.LegallyIdentifiable>() {
|
||||||
@Suspendable
|
@Suspendable
|
||||||
override fun call(): DigitalSignature.LegallyIdentifiable {
|
override fun call(): DigitalSignature.LegallyIdentifiable {
|
||||||
val wtx = tx.toWireTransaction()
|
val resp = sendAndReceive<DigitalSignature.LegallyIdentifiable>(oracle, SignRequest(partialMerkleTx))
|
||||||
val rootHash = wtx.id
|
|
||||||
val resp = sendAndReceive<DigitalSignature.LegallyIdentifiable>(oracle, SignRequest(rootHash, partialMerkleTx))
|
|
||||||
return resp.unwrap { sig ->
|
return resp.unwrap { sig ->
|
||||||
check(sig.signer == oracle)
|
check(sig.signer == oracle)
|
||||||
tx.checkSignature(sig)
|
tx.checkSignature(sig)
|
||||||
|
@ -137,12 +137,12 @@ class NodeInterestRatesTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
val ftx1 = wtx1.buildFilteredTransaction(::filterAllOutputs)
|
val ftx1 = wtx1.buildFilteredTransaction(::filterAllOutputs)
|
||||||
assertFailsWith<IllegalArgumentException> { oracle.sign(ftx1, wtx1.id) }
|
assertFailsWith<IllegalArgumentException> { oracle.sign(ftx1) }
|
||||||
tx.addCommand(Cash.Commands.Move(), ALICE_PUBKEY)
|
tx.addCommand(Cash.Commands.Move(), ALICE_PUBKEY)
|
||||||
val wtx2 = tx.toWireTransaction()
|
val wtx2 = tx.toWireTransaction()
|
||||||
val ftx2 = wtx2.buildFilteredTransaction { x -> filterCmds(x) }
|
val ftx2 = wtx2.buildFilteredTransaction { x -> filterCmds(x) }
|
||||||
assertFalse(wtx1.id == wtx2.id)
|
assertFalse(wtx1.id == wtx2.id)
|
||||||
assertFailsWith<IllegalArgumentException> { oracle.sign(ftx2, wtx2.id) }
|
assertFailsWith<IllegalArgumentException> { oracle.sign(ftx2) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,7 +155,7 @@ class NodeInterestRatesTest {
|
|||||||
// Sign successfully.
|
// Sign successfully.
|
||||||
val wtx = tx.toWireTransaction()
|
val wtx = tx.toWireTransaction()
|
||||||
val ftx = wtx.buildFilteredTransaction { x -> fixCmdFilter(x) }
|
val ftx = wtx.buildFilteredTransaction { x -> fixCmdFilter(x) }
|
||||||
val signature = oracle.sign(ftx, wtx.id)
|
val signature = oracle.sign(ftx)
|
||||||
tx.checkAndAddSignature(signature)
|
tx.checkAndAddSignature(signature)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -169,7 +169,7 @@ class NodeInterestRatesTest {
|
|||||||
tx.addCommand(badFix, oracle.identity.owningKey)
|
tx.addCommand(badFix, oracle.identity.owningKey)
|
||||||
val wtx = tx.toWireTransaction()
|
val wtx = tx.toWireTransaction()
|
||||||
val ftx = wtx.buildFilteredTransaction { x -> fixCmdFilter(x) }
|
val ftx = wtx.buildFilteredTransaction { x -> fixCmdFilter(x) }
|
||||||
val e1 = assertFailsWith<NodeInterestRates.UnknownFix> { oracle.sign(ftx, wtx.id) }
|
val e1 = assertFailsWith<NodeInterestRates.UnknownFix> { oracle.sign(ftx) }
|
||||||
assertEquals(fixOf, e1.fix)
|
assertEquals(fixOf, e1.fix)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -189,7 +189,7 @@ class NodeInterestRatesTest {
|
|||||||
tx.addCommand(fix, oracle.identity.owningKey)
|
tx.addCommand(fix, oracle.identity.owningKey)
|
||||||
val wtx = tx.toWireTransaction()
|
val wtx = tx.toWireTransaction()
|
||||||
val ftx = wtx.buildFilteredTransaction(::filtering)
|
val ftx = wtx.buildFilteredTransaction(::filtering)
|
||||||
assertFailsWith<IllegalArgumentException> { oracle.sign(ftx, wtx.id) }
|
assertFailsWith<IllegalArgumentException> { oracle.sign(ftx) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,20 +198,7 @@ class NodeInterestRatesTest {
|
|||||||
val tx = makeTX()
|
val tx = makeTX()
|
||||||
val wtx = tx.toWireTransaction()
|
val wtx = tx.toWireTransaction()
|
||||||
val ftx = wtx.buildFilteredTransaction({ false })
|
val ftx = wtx.buildFilteredTransaction({ false })
|
||||||
assertFailsWith<MerkleTreeException> { oracle.sign(ftx, wtx.id) }
|
assertFailsWith<MerkleTreeException> { oracle.sign(ftx) }
|
||||||
}
|
|
||||||
|
|
||||||
@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<MerkleTreeException> { oracle.sign(ftx2, wtx1.id) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
Loading…
Reference in New Issue
Block a user