mirror of
https://github.com/corda/corda.git
synced 2025-02-21 09:51:57 +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.contracts.*
|
||||||
import net.corda.core.crypto.*
|
import net.corda.core.crypto.*
|
||||||
import net.corda.core.crypto.SecureHash.Companion.zeroHash
|
|
||||||
import net.corda.core.serialization.createKryo
|
import net.corda.core.serialization.createKryo
|
||||||
import net.corda.core.serialization.extendKryoHash
|
import net.corda.core.serialization.extendKryoHash
|
||||||
import net.corda.core.serialization.serialize
|
import net.corda.core.serialization.serialize
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
fun <T : Any> serializedHash(x: T): SecureHash {
|
fun <T : Any> serializedHash(x: T): SecureHash {
|
||||||
val kryo = extendKryoHash(createKryo()) // Dealing with HashMaps inside states.
|
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.
|
* Implemented by [WireTransaction] and [FilteredLeaves]. A TraversableTransaction allows you to iterate
|
||||||
* Property traversableList assures that we always calculate hashes in the same order, lets us define which
|
* over the flattened components of the underlying transaction structure, taking into account that some
|
||||||
* fields of WireTransaction will be included in id calculation or partial merkle tree building.
|
* 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 {
|
interface TraversableTransaction {
|
||||||
val inputs: List<StateRef>
|
val inputs: List<StateRef>
|
||||||
@ -29,29 +31,41 @@ interface TraversableTransaction {
|
|||||||
val timestamp: Timestamp?
|
val timestamp: Timestamp?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Traversing transaction fields with a list function over transaction contents. Used for leaves hashes calculation
|
* Returns a flattened list of all the components that are present in the transaction, in the following order:
|
||||||
* and user provided filtering and checking of filtered transaction.
|
*
|
||||||
|
* - 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.
|
val availableComponents: List<Any>
|
||||||
// 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>
|
|
||||||
get() {
|
get() {
|
||||||
val traverseList = mutableListOf(inputs, attachments, outputs, commands).flatten().toMutableList()
|
// We may want to specify our own behaviour on certain tx fields.
|
||||||
if (notary != null) traverseList.add(notary!!)
|
// Like if we include them at all, what to do with null values, if we treat list as one or not etc. for building
|
||||||
traverseList.addAll(mustSign)
|
// torn-off transaction and id calculation.
|
||||||
if (type != null) traverseList.add(type!!)
|
val result = mutableListOf(inputs, attachments, outputs, commands).flatten().toMutableList()
|
||||||
if (timestamp != null) traverseList.add(timestamp!!)
|
notary?.let { result += it }
|
||||||
return traverseList
|
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
|
* 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(
|
class FilteredLeaves(
|
||||||
override val inputs: List<StateRef>,
|
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.
|
* @returns false if no elements were matched on a structure or checkingFun returned false.
|
||||||
*/
|
*/
|
||||||
fun checkWithFun(checkingFun: (Any) -> Boolean): Boolean {
|
fun checkWithFun(checkingFun: (Any) -> Boolean): Boolean {
|
||||||
val checkList = traversableList.map { checkingFun(it) }
|
val checkList = availableComponents.map { checkingFun(it) }
|
||||||
return (!checkList.isEmpty()) && checkList.all { true }
|
return (!checkList.isEmpty()) && checkList.all { true }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -99,8 +113,8 @@ class FilteredTransaction private constructor(
|
|||||||
filtering: (Any) -> Boolean
|
filtering: (Any) -> Boolean
|
||||||
): FilteredTransaction {
|
): FilteredTransaction {
|
||||||
val filteredLeaves = wtx.filterWithFun(filtering)
|
val filteredLeaves = wtx.filterWithFun(filtering)
|
||||||
val merkleTree = wtx.getMerkleTree()
|
val merkleTree = wtx.merkleTree
|
||||||
val pmt = PartialMerkleTree.build(merkleTree, filteredLeaves.calculateLeavesHashes())
|
val pmt = PartialMerkleTree.build(merkleTree, filteredLeaves.availableComponentHashes)
|
||||||
return FilteredTransaction(merkleTree.hash, filteredLeaves, pmt)
|
return FilteredTransaction(merkleTree.hash, filteredLeaves, pmt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -110,17 +124,9 @@ class FilteredTransaction private constructor(
|
|||||||
*/
|
*/
|
||||||
@Throws(MerkleTreeException::class)
|
@Throws(MerkleTreeException::class)
|
||||||
fun verify(): Boolean {
|
fun verify(): Boolean {
|
||||||
val hashes: List<SecureHash> = filteredLeaves.calculateLeavesHashes()
|
val hashes: List<SecureHash> = filteredLeaves.availableComponentHashes
|
||||||
if (hashes.isEmpty())
|
if (hashes.isEmpty())
|
||||||
throw MerkleTreeException("Transaction without included leaves.")
|
throw MerkleTreeException("Transaction without included leaves.")
|
||||||
return partialMerkleTree.verify(rootHash, hashes)
|
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
|
@Volatile @Transient private var cachedBytes: SerializedBytes<WireTransaction>? = null
|
||||||
val serialized: SerializedBytes<WireTransaction> get() = cachedBytes ?: serialize().apply { cachedBytes = this }
|
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 {
|
companion object {
|
||||||
fun deserialize(data: SerializedBytes<WireTransaction>, kryo: Kryo = THREAD_LOCAL_KRYO.get()): WireTransaction {
|
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.
|
* Builds whole Merkle tree for a transaction.
|
||||||
*/
|
*/
|
||||||
fun getMerkleTree(): MerkleTree {
|
val merkleTree: MerkleTree by lazy { MerkleTree.getMerkleTree(availableComponentHashes) }
|
||||||
return MerkleTree.getMerkleTree(calculateLeavesHashes())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construction of partial transaction from WireTransaction based on filtering.
|
* Construction of partial transaction from WireTransaction based on filtering.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user