Moves filterFun and indexOffsets into MerkleTransaction.

This commit is contained in:
Joel Dudley 2017-08-31 17:11:44 +01:00 committed by GitHub
parent 8d29c78073
commit 574c476709
2 changed files with 64 additions and 64 deletions

View File

@ -159,11 +159,74 @@ class FilteredTransaction private constructor(
fun buildMerkleTransaction(wtx: WireTransaction,
filtering: Predicate<Any>
): FilteredTransaction {
val filteredLeaves = wtx.filterWithFun(filtering)
val filteredLeaves = filterWithFun(wtx, filtering)
val merkleTree = wtx.merkleTree
val pmt = PartialMerkleTree.build(merkleTree, filteredLeaves.availableComponentHashes)
return FilteredTransaction(merkleTree.hash, filteredLeaves, pmt)
}
/**
* Construction of partial transaction from WireTransaction based on filtering.
* Note that list of nonces to be sent is updated on the fly, based on the index of the filtered tx component.
* @param filtering filtering over the whole WireTransaction
* @returns FilteredLeaves used in PartialMerkleTree calculation and verification.
*/
private fun filterWithFun(wtx: WireTransaction, filtering: Predicate<Any>): FilteredLeaves {
val nonces: MutableList<SecureHash> = mutableListOf()
val offsets = indexOffsets(wtx)
fun notNullFalseAndNoncesUpdate(elem: Any?, index: Int): Any? {
return if (elem == null || !filtering.test(elem)) {
null
} else {
nonces.add(computeNonce(wtx.privacySalt, index))
elem
}
}
fun <T : Any> filterAndNoncesUpdate(t: T, index: Int): Boolean {
return if (filtering.test(t)) {
nonces.add(computeNonce(wtx.privacySalt, index))
true
} else {
false
}
}
// TODO: We should have a warning (require) if all leaves (excluding salt) are visible after filtering.
// Consider the above after refactoring FilteredTransaction to implement TraversableTransaction,
// so that a WireTransaction can be used when required to send a full tx (e.g. RatesFixFlow in Oracles).
return FilteredLeaves(
wtx.inputs.filterIndexed { index, it -> filterAndNoncesUpdate(it, index) },
wtx.attachments.filterIndexed { index, it -> filterAndNoncesUpdate(it, index + offsets[0]) },
wtx.outputs.filterIndexed { index, it -> filterAndNoncesUpdate(it, index + offsets[1]) },
wtx.commands.filterIndexed { index, it -> filterAndNoncesUpdate(it, index + offsets[2]) },
notNullFalseAndNoncesUpdate(wtx.notary, offsets[3]) as Party?,
notNullFalseAndNoncesUpdate(wtx.timeWindow, offsets[4]) as TimeWindow?,
nonces
)
}
// We use index offsets, to get the actual leaf-index per transaction component required for nonce computation.
private fun indexOffsets(wtx: WireTransaction): List<Int> {
// There is no need to add an index offset for inputs, because they are the first components in the
// transaction format and it is always zero. Thus, offsets[0] corresponds to attachments,
// offsets[1] to outputs, offsets[2] to commands and so on.
val offsets = mutableListOf(wtx.inputs.size, wtx.inputs.size + wtx.attachments.size)
offsets.add(offsets.last() + wtx.outputs.size)
offsets.add(offsets.last() + wtx.commands.size)
if (wtx.notary != null) {
offsets.add(offsets.last() + 1)
} else {
offsets.add(offsets.last())
}
if (wtx.timeWindow != null) {
offsets.add(offsets.last() + 1)
} else {
offsets.add(offsets.last())
}
// No need to add offset for privacySalt as it doesn't require a nonce.
return offsets
}
}
/**

View File

@ -106,69 +106,6 @@ data class WireTransaction(
*/
val merkleTree: MerkleTree by lazy { MerkleTree.getMerkleTree(availableComponentHashes) }
/**
* Construction of partial transaction from WireTransaction based on filtering.
* Note that list of nonces to be sent is updated on the fly, based on the index of the filtered tx component.
* @param filtering filtering over the whole WireTransaction
* @returns FilteredLeaves used in PartialMerkleTree calculation and verification.
*/
fun filterWithFun(filtering: Predicate<Any>): FilteredLeaves {
val nonces: MutableList<SecureHash> = mutableListOf()
val offsets = indexOffsets()
fun notNullFalseAndNoncesUpdate(elem: Any?, index: Int): Any? {
return if (elem == null || !filtering.test(elem)) {
null
} else {
nonces.add(computeNonce(privacySalt, index))
elem
}
}
fun <T : Any> filterAndNoncesUpdate(t: T, index: Int): Boolean {
return if (filtering.test(t)) {
nonces.add(computeNonce(privacySalt, index))
true
} else {
false
}
}
// TODO: We should have a warning (require) if all leaves (excluding salt) are visible after filtering.
// Consider the above after refactoring FilteredTransaction to implement TraversableTransaction,
// so that a WireTransaction can be used when required to send a full tx (e.g. RatesFixFlow in Oracles).
return FilteredLeaves(
inputs.filterIndexed { index, it -> filterAndNoncesUpdate(it, index) },
attachments.filterIndexed { index, it -> filterAndNoncesUpdate(it, index + offsets[0]) },
outputs.filterIndexed { index, it -> filterAndNoncesUpdate(it, index + offsets[1]) },
commands.filterIndexed { index, it -> filterAndNoncesUpdate(it, index + offsets[2]) },
notNullFalseAndNoncesUpdate(notary, offsets[3]) as Party?,
notNullFalseAndNoncesUpdate(timeWindow, offsets[4]) as TimeWindow?,
nonces
)
}
// We use index offsets, to get the actual leaf-index per transaction component required for nonce computation.
private fun indexOffsets(): List<Int> {
// There is no need to add an index offset for inputs, because they are the first components in the
// transaction format and it is always zero. Thus, offsets[0] corresponds to attachments,
// offsets[1] to outputs, offsets[2] to commands and so on.
val offsets = mutableListOf(inputs.size, inputs.size + attachments.size)
offsets.add(offsets.last() + outputs.size)
offsets.add(offsets.last() + commands.size)
if (notary != null) {
offsets.add(offsets.last() + 1)
} else {
offsets.add(offsets.last())
}
if (timeWindow != null) {
offsets.add(offsets.last() + 1)
} else {
offsets.add(offsets.last())
}
// No need to add offset for privacySalt as it doesn't require a nonce.
return offsets
}
/**
* Checks that the given signature matches one of the commands and that it is a correct signature over the tx.
*