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
}
// 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()
}

View file

@ -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) {

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
// 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 "+