mirror of
https://github.com/btcsuite/btcd.git
synced 2024-11-19 01:40:07 +01:00
blockchain: Add CalcMerkleRoot
CalcMerkleRoot uses the rolling merkle root algorithm to calculate the merkle root commitment inside the Bitcoin block header. It allocates significantly less memory than the BuildMerkleTreeStore function that's currently in use (99.9% in an average block with 2000 txs).
This commit is contained in:
parent
2d23f94002
commit
025fa65c93
@ -9,9 +9,9 @@ import (
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"github.com/btcsuite/btcd/btcutil"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcd/btcutil"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -85,7 +85,7 @@ func HashMerkleBranches(left, right *chainhash.Hash) chainhash.Hash {
|
||||
//
|
||||
// The above stored as a linear array is as follows:
|
||||
//
|
||||
// [h1 h2 h3 h4 h12 h34 root]
|
||||
// [h1 h2 h3 h4 h12 h34 root]
|
||||
//
|
||||
// As the above shows, the merkle root is always the last element in the array.
|
||||
//
|
||||
@ -153,6 +153,36 @@ func BuildMerkleTreeStore(transactions []*btcutil.Tx, witness bool) []*chainhash
|
||||
return merkles
|
||||
}
|
||||
|
||||
// CalcMerkleRoot computes the merkle root over a set of hashed leaves. The
|
||||
// interior nodes are computed opportunistically as the leaves are added to the
|
||||
// abstract tree to reduce the total number of allocations. Throughout the
|
||||
// computation, this computation only requires storing O(log n) interior
|
||||
// nodes.
|
||||
//
|
||||
// This method differs from BuildMerkleTreeStore in that the interior nodes are
|
||||
// discarded instead of being returned along with the root. CalcMerkleRoot is
|
||||
// slightly faster than BuildMerkleTreeStore and requires significantly less
|
||||
// memory and fewer allocations.
|
||||
//
|
||||
// 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
|
||||
// where h(x) is a double sha256 follows:
|
||||
//
|
||||
// root = h1234 = h(h12 + h34)
|
||||
// / \
|
||||
// h12 = h(h1 + h2) h34 = h(h3 + h4)
|
||||
// / \ / \
|
||||
// h1 = h(tx1) h2 = h(tx2) h3 = h(tx3) h4 = h(tx4)
|
||||
//
|
||||
// The additional bool parameter indicates if we are generating the merkle tree
|
||||
// using witness transaction id's rather than regular transaction id's. This
|
||||
// also presents an additional case wherein the wtxid of the coinbase transaction
|
||||
// is the zeroHash.
|
||||
func CalcMerkleRoot(transactions []*btcutil.Tx, witness bool) chainhash.Hash {
|
||||
s := newRollingMerkleTreeStore(uint64(len(transactions)))
|
||||
return s.calcMerkleRoot(transactions, witness)
|
||||
}
|
||||
|
||||
// ExtractWitnessCommitment attempts to locate, and return the witness
|
||||
// commitment for a block. The witness commitment is of the form:
|
||||
// SHA256(witness root || witness nonce). The function additionally returns a
|
||||
|
@ -11,17 +11,22 @@ import (
|
||||
"github.com/btcsuite/btcd/btcutil"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// TestMerkle tests the BuildMerkleTreeStore API.
|
||||
func TestMerkle(t *testing.T) {
|
||||
block := btcutil.NewBlock(&Block100000)
|
||||
merkles := BuildMerkleTreeStore(block.Transactions(), false)
|
||||
calculatedMerkleRoot := merkles[len(merkles)-1]
|
||||
calcMerkleRoot := CalcMerkleRoot(block.Transactions(), false)
|
||||
merkleStoreTree := BuildMerkleTreeStore(block.Transactions(), false)
|
||||
merkleStoreRoot := merkleStoreTree[len(merkleStoreTree)-1]
|
||||
|
||||
require.Equal(t, *merkleStoreRoot, calcMerkleRoot)
|
||||
|
||||
wantMerkle := &Block100000.Header.MerkleRoot
|
||||
if !wantMerkle.IsEqual(calculatedMerkleRoot) {
|
||||
if !wantMerkle.IsEqual(&calcMerkleRoot) {
|
||||
t.Errorf("BuildMerkleTreeStore: merkle root mismatch - "+
|
||||
"got %v, want %v", calculatedMerkleRoot, wantMerkle)
|
||||
"got %v, want %v", calcMerkleRoot, wantMerkle)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user