From ec641751a8be3b3f2e72e271de1092f0427508e5 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sat, 1 Mar 2014 21:16:06 -0600 Subject: [PATCH] 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. --- merkle.go | 16 ++++++++-------- merkle_test.go | 2 +- validate.go | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/merkle.go b/merkle.go index fdee30e13..f74ef2a3a 100644 --- a/merkle.go +++ b/merkle.go @@ -40,11 +40,11 @@ func hashMerkleBranches(left *btcwire.ShaHash, right *btcwire.ShaHash) *btcwire. return newSha } -// BuildMerkleTreeStore creates a merkle tree from block, stores it using a -// linear array, and returns a slice of the backing array. A linear array was -// chosen as opposed to an actual tree structure since it uses about half as -// much memory. The following describes a merkle tree and how it is stored in -// a linear array. +// BuildMerkleTreeStore creates a merkle tree from a slice of transactions, +// stores it using a linear array, and returns a slice of the backing array. A +// linear array was chosen as opposed to an actual tree structure since it uses +// about half as much memory. The following describes a merkle tree and how it +// is stored in a linear array. // // 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 @@ -68,15 +68,15 @@ func hashMerkleBranches(left *btcwire.ShaHash, right *btcwire.ShaHash) *btcwire. // are calculated by concatenating the left node with itself before hashing. // Since this function uses nodes that are pointers to the hashes, empty nodes // 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 // 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 merkles := make([]*btcwire.ShaHash, arraySize) // 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() } diff --git a/merkle_test.go b/merkle_test.go index 6fbae40a2..01a9af77f 100644 --- a/merkle_test.go +++ b/merkle_test.go @@ -13,7 +13,7 @@ import ( // TestMerkle tests the BuildMerkleTreeStore API. func TestMerkle(t *testing.T) { block := btcutil.NewBlock(&Block100000) - merkles := btcchain.BuildMerkleTreeStore(block) + merkles := btcchain.BuildMerkleTreeStore(block.Transactions()) calculatedMerkleRoot := merkles[len(merkles)-1] wantMerkle := &Block100000.Header.MerkleRoot if !wantMerkle.IsEqual(calculatedMerkleRoot) { diff --git a/validate.go b/validate.go index 3c4019cca..20bdf8c2a 100644 --- a/validate.go +++ b/validate.go @@ -453,7 +453,7 @@ func CheckBlockSanity(block *btcutil.Block, powLimit *big.Int) error { // checks. Bitcoind builds the tree here and checks the merkle root // after the following checks, but there is no reason not to check the // merkle root matches here. - merkles := BuildMerkleTreeStore(block) + merkles := BuildMerkleTreeStore(block.Transactions()) calculatedMerkleRoot := merkles[len(merkles)-1] if !header.MerkleRoot.IsEqual(calculatedMerkleRoot) { str := fmt.Sprintf("block merkle root is invalid - block "+