mirror of
https://github.com/corda/corda.git
synced 2025-02-20 01:16:42 +00:00
Minor: naming and doc tweaks in Merkle tree code.
This commit is contained in:
parent
b8942a2cc9
commit
8b1864e07c
@ -2,11 +2,9 @@ package net.corda.core.transactions
|
||||
|
||||
import net.corda.core.contracts.*
|
||||
import net.corda.core.crypto.*
|
||||
import net.corda.core.crypto.SecureHash.Companion.zeroHash
|
||||
import net.corda.core.serialization.createKryo
|
||||
import net.corda.core.serialization.extendKryoHash
|
||||
import net.corda.core.serialization.serialize
|
||||
import java.util.*
|
||||
|
||||
fun <T : Any> serializedHash(x: T): SecureHash {
|
||||
val kryo = extendKryoHash(createKryo()) // Dealing with HashMaps inside states.
|
||||
@ -14,9 +12,13 @@ fun <T : Any> serializedHash(x: T): SecureHash {
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface implemented by WireTransaction and FilteredLeaves.
|
||||
* Property traversableList assures that we always calculate hashes in the same order, lets us define which
|
||||
* fields of WireTransaction will be included in id calculation or partial merkle tree building.
|
||||
* Implemented by [WireTransaction] and [FilteredLeaves]. A TraversableTransaction allows you to iterate
|
||||
* over the flattened components of the underlying transaction structure, taking into account that some
|
||||
* may be missing in the case of this representing a "torn" transaction. Please see the user guide section
|
||||
* "Transaction tear-offs" to learn more about this feature.
|
||||
*
|
||||
* The [availableComponents] property is used for calculation of the transaction's [MerkleTree], which is in
|
||||
* turn used to derive the ID hash.
|
||||
*/
|
||||
interface TraversableTransaction {
|
||||
val inputs: List<StateRef>
|
||||
@ -29,29 +31,41 @@ interface TraversableTransaction {
|
||||
val timestamp: Timestamp?
|
||||
|
||||
/**
|
||||
* Traversing transaction fields with a list function over transaction contents. Used for leaves hashes calculation
|
||||
* and user provided filtering and checking of filtered transaction.
|
||||
* Returns a flattened list of all the components that are present in the transaction, in the following order:
|
||||
*
|
||||
* - Each input that is present
|
||||
* - Each attachment that is present
|
||||
* - Each output that is present
|
||||
* - Each command that is present
|
||||
* - The notary [Party], if present
|
||||
* - Each required signer ([mustSign]) that is present
|
||||
* - The type of the transaction, if present
|
||||
* - The timestamp of the transaction, if present
|
||||
*/
|
||||
// We may want to specify our own behaviour on certain tx fields.
|
||||
// Like if we include them at all, what to do with null values, if we treat list as one or not etc. for building
|
||||
// torn-off transaction and id calculation.
|
||||
val traversableList: List<Any>
|
||||
val availableComponents: List<Any>
|
||||
get() {
|
||||
val traverseList = mutableListOf(inputs, attachments, outputs, commands).flatten().toMutableList()
|
||||
if (notary != null) traverseList.add(notary!!)
|
||||
traverseList.addAll(mustSign)
|
||||
if (type != null) traverseList.add(type!!)
|
||||
if (timestamp != null) traverseList.add(timestamp!!)
|
||||
return traverseList
|
||||
// We may want to specify our own behaviour on certain tx fields.
|
||||
// Like if we include them at all, what to do with null values, if we treat list as one or not etc. for building
|
||||
// torn-off transaction and id calculation.
|
||||
val result = mutableListOf(inputs, attachments, outputs, commands).flatten().toMutableList()
|
||||
notary?.let { result += it }
|
||||
result.addAll(mustSign)
|
||||
type?.let { result += it }
|
||||
timestamp?.let { result += it }
|
||||
return result
|
||||
}
|
||||
|
||||
// Calculation of all leaves hashes that are needed for calculation of transaction id and partial Merkle branches.
|
||||
fun calculateLeavesHashes(): List<SecureHash> = traversableList.map { serializedHash(it) }
|
||||
/**
|
||||
* Calculate the hashes of the sub-components of the transaction, that are used to build its Merkle tree.
|
||||
* The root of the tree is the transaction identifier. The tree structure is helpful for privacy, please
|
||||
* see the user-guide section "Transaction tear-offs" to learn more about this topic.
|
||||
*/
|
||||
val availableComponentHashes: List<SecureHash> get() = availableComponents.map { serializedHash(it) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Class that holds filtered leaves for a partial Merkle transaction. We assume mixed leaf types, notice that every
|
||||
* field from WireTransaction can be used in PartialMerkleTree calculation.
|
||||
* field from [WireTransaction] can be used in [PartialMerkleTree] calculation.
|
||||
*/
|
||||
class FilteredLeaves(
|
||||
override val inputs: List<StateRef>,
|
||||
@ -73,7 +87,7 @@ class FilteredLeaves(
|
||||
* @returns false if no elements were matched on a structure or checkingFun returned false.
|
||||
*/
|
||||
fun checkWithFun(checkingFun: (Any) -> Boolean): Boolean {
|
||||
val checkList = traversableList.map { checkingFun(it) }
|
||||
val checkList = availableComponents.map { checkingFun(it) }
|
||||
return (!checkList.isEmpty()) && checkList.all { true }
|
||||
}
|
||||
}
|
||||
@ -99,8 +113,8 @@ class FilteredTransaction private constructor(
|
||||
filtering: (Any) -> Boolean
|
||||
): FilteredTransaction {
|
||||
val filteredLeaves = wtx.filterWithFun(filtering)
|
||||
val merkleTree = wtx.getMerkleTree()
|
||||
val pmt = PartialMerkleTree.build(merkleTree, filteredLeaves.calculateLeavesHashes())
|
||||
val merkleTree = wtx.merkleTree
|
||||
val pmt = PartialMerkleTree.build(merkleTree, filteredLeaves.availableComponentHashes)
|
||||
return FilteredTransaction(merkleTree.hash, filteredLeaves, pmt)
|
||||
}
|
||||
}
|
||||
@ -110,17 +124,9 @@ class FilteredTransaction private constructor(
|
||||
*/
|
||||
@Throws(MerkleTreeException::class)
|
||||
fun verify(): Boolean {
|
||||
val hashes: List<SecureHash> = filteredLeaves.calculateLeavesHashes()
|
||||
val hashes: List<SecureHash> = filteredLeaves.availableComponentHashes
|
||||
if (hashes.isEmpty())
|
||||
throw MerkleTreeException("Transaction without included leaves.")
|
||||
return partialMerkleTree.verify(rootHash, hashes)
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs verification of Partial Merkle Branch against [rootHash]. Checks filteredLeaves with provided checkingFun.
|
||||
*/
|
||||
@Throws(MerkleTreeException::class)
|
||||
fun verifyWithFunction(checkingFun: (Any) -> Boolean): Boolean {
|
||||
return verify() && filteredLeaves.checkWithFun { checkingFun(it) }
|
||||
}
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ class WireTransaction(
|
||||
@Volatile @Transient private var cachedBytes: SerializedBytes<WireTransaction>? = null
|
||||
val serialized: SerializedBytes<WireTransaction> get() = cachedBytes ?: serialize().apply { cachedBytes = this }
|
||||
|
||||
override val id: SecureHash by lazy { getMerkleTree().hash }
|
||||
override val id: SecureHash by lazy { merkleTree.hash }
|
||||
|
||||
companion object {
|
||||
fun deserialize(data: SerializedBytes<WireTransaction>, kryo: Kryo = THREAD_LOCAL_KRYO.get()): WireTransaction {
|
||||
@ -94,9 +94,7 @@ class WireTransaction(
|
||||
/**
|
||||
* Builds whole Merkle tree for a transaction.
|
||||
*/
|
||||
fun getMerkleTree(): MerkleTree {
|
||||
return MerkleTree.getMerkleTree(calculateLeavesHashes())
|
||||
}
|
||||
val merkleTree: MerkleTree by lazy { MerkleTree.getMerkleTree(availableComponentHashes) }
|
||||
|
||||
/**
|
||||
* Construction of partial transaction from WireTransaction based on filtering.
|
||||
|
Loading…
x
Reference in New Issue
Block a user