Change BuildMerkleTreeStore to accept transactions.

This commit modifies the BuildMerkleTreeStore function to accept a slice
of btcutil.Tx transactions as opposed to a full block.  This allows more
flexibility when calculating merkle roots since a full block may not be
created yet (particularly when generating blocks that need to be solved in
mining).

Previously, the BuildMerkleTreeStore function accepted a btcutil.Block
because originally the block itself cached the transaction hashes and it
was necessary to have access to the block to make use of the cached
transactions.  However, the code has since been improved such that it
caches transaction hashes directly in each btcutil.Tx.  This means the
code can remain as efficient as before while allowing the individual
transacitons to be passed.
This commit is contained in:
Dave Collins 2014-03-01 21:16:06 -06:00
parent 82edb203e5
commit ec641751a8
3 changed files with 10 additions and 10 deletions

View file

@ -40,11 +40,11 @@ func hashMerkleBranches(left *btcwire.ShaHash, right *btcwire.ShaHash) *btcwire.
return newSha return newSha
} }
// BuildMerkleTreeStore creates a merkle tree from block, stores it using a // BuildMerkleTreeStore creates a merkle tree from a slice of transactions,
// linear array, and returns a slice of the backing array. A linear array was // stores it using a linear array, and returns a slice of the backing array. A
// chosen as opposed to an actual tree structure since it uses about half as // linear array was chosen as opposed to an actual tree structure since it uses
// much memory. The following describes a merkle tree and how it is stored in // about half as much memory. The following describes a merkle tree and how it
// a linear array. // is stored in a linear array.
// //
// A merkle tree is a tree in which every non-leaf node is the hash of its // A merkle tree is a tree in which every non-leaf node is the hash of its
// children nodes. A diagram depicting how this works for bitcoin transactions // children nodes. A diagram depicting how this works for bitcoin transactions
@ -68,15 +68,15 @@ func hashMerkleBranches(left *btcwire.ShaHash, right *btcwire.ShaHash) *btcwire.
// are calculated by concatenating the left node with itself before hashing. // are calculated by concatenating the left node with itself before hashing.
// Since this function uses nodes that are pointers to the hashes, empty nodes // Since this function uses nodes that are pointers to the hashes, empty nodes
// will be nil. // will be nil.
func BuildMerkleTreeStore(block *btcutil.Block) []*btcwire.ShaHash { func BuildMerkleTreeStore(transactions []*btcutil.Tx) []*btcwire.ShaHash {
// Calculate how many entries are required to hold the binary merkle // Calculate how many entries are required to hold the binary merkle
// tree as a linear array and create an array of that size. // tree as a linear array and create an array of that size.
nextPoT := nextPowerOfTwo(len(block.Transactions())) nextPoT := nextPowerOfTwo(len(transactions))
arraySize := nextPoT*2 - 1 arraySize := nextPoT*2 - 1
merkles := make([]*btcwire.ShaHash, arraySize) merkles := make([]*btcwire.ShaHash, arraySize)
// Create the base transaction shas and populate the array with them. // Create the base transaction shas and populate the array with them.
for i, tx := range block.Transactions() { for i, tx := range transactions {
merkles[i] = tx.Sha() merkles[i] = tx.Sha()
} }

View file

@ -13,7 +13,7 @@ import (
// TestMerkle tests the BuildMerkleTreeStore API. // TestMerkle tests the BuildMerkleTreeStore API.
func TestMerkle(t *testing.T) { func TestMerkle(t *testing.T) {
block := btcutil.NewBlock(&Block100000) block := btcutil.NewBlock(&Block100000)
merkles := btcchain.BuildMerkleTreeStore(block) merkles := btcchain.BuildMerkleTreeStore(block.Transactions())
calculatedMerkleRoot := merkles[len(merkles)-1] calculatedMerkleRoot := merkles[len(merkles)-1]
wantMerkle := &Block100000.Header.MerkleRoot wantMerkle := &Block100000.Header.MerkleRoot
if !wantMerkle.IsEqual(calculatedMerkleRoot) { if !wantMerkle.IsEqual(calculatedMerkleRoot) {

View file

@ -453,7 +453,7 @@ func CheckBlockSanity(block *btcutil.Block, powLimit *big.Int) error {
// checks. Bitcoind builds the tree here and checks the merkle root // checks. Bitcoind builds the tree here and checks the merkle root
// after the following checks, but there is no reason not to check the // after the following checks, but there is no reason not to check the
// merkle root matches here. // merkle root matches here.
merkles := BuildMerkleTreeStore(block) merkles := BuildMerkleTreeStore(block.Transactions())
calculatedMerkleRoot := merkles[len(merkles)-1] calculatedMerkleRoot := merkles[len(merkles)-1]
if !header.MerkleRoot.IsEqual(calculatedMerkleRoot) { if !header.MerkleRoot.IsEqual(calculatedMerkleRoot) {
str := fmt.Sprintf("block merkle root is invalid - block "+ str := fmt.Sprintf("block merkle root is invalid - block "+