btcd/blockchain/bip30_test.go
2026-05-14 18:05:33 -07:00

149 lines
4.7 KiB
Go

package blockchain
import (
"testing"
"github.com/btcsuite/btcd/chaincfg/v2"
"github.com/btcsuite/btcd/chainhash/v2"
"github.com/stretchr/testify/require"
)
// mustHashFromStr is a helper to parse hashes inside tests. It fails the
// test immediately when the string is not a valid hash.
func mustHashFromStr(t *testing.T, s string) chainhash.Hash {
t.Helper()
h, err := chainhash.NewHashFromStr(s)
require.NoError(t, err)
return *h
}
// TestBip0030CheckNeededExceptions makes sure the two historical blocks that
// overwrote earlier coinbases do not trigger the BIP30 check. This mirrors the
// exceptions Bitcoin Core ships as part of the original BIP30 fix.
func TestBip0030CheckNeededExceptions(t *testing.T) {
params := chaincfg.MainNetParams
cases := []struct {
height int32
hash string
}{{
height: 91842,
hash: "00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec",
}, {
height: 91880,
hash: "00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721",
}}
for _, tc := range cases {
tc := tc
t.Run(tc.hash, func(t *testing.T) {
node := &blockNode{
height: tc.height,
hash: mustHashFromStr(t, tc.hash),
}
require.False(t, bip0030CheckNeeded(node, &params))
})
}
}
// TestBip0030CheckNeededBeforeBIP34 ensures we still run the BIP30 check prior
// to the recorded BIP34 activation height.
func TestBip0030CheckNeededBeforeBIP34(t *testing.T) {
params := chaincfg.MainNetParams
node := &blockNode{
height: params.BIP0034Height - 1,
hash: mustHashFromStr(t, "0000000000000000000000000000000000000000000000000000000000000001"),
}
require.True(t, bip0030CheckNeeded(node, &params))
}
// TestBip0030CheckNeededAtActivationHeight validates that the activation block
// itself still triggers the check.
func TestBip0030CheckNeededAtActivationHeight(t *testing.T) {
params := chaincfg.MainNetParams
node := &blockNode{
height: params.BIP0034Height,
hash: mustHashFromStr(t, "000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8"),
parent: &blockNode{height: params.BIP0034Height - 1},
}
require.True(t, bip0030CheckNeeded(node, &params))
}
// TestBip0030CheckNeededAfterBIP34 covers the happy-path where we are on a
// chain that contains the recorded BIP34 activation block. In that case the
// expensive duplicate-coinbase check can be skipped.
func TestBip0030CheckNeededAfterBIP34(t *testing.T) {
params := chaincfg.MainNetParams
ancestor := &blockNode{
height: params.BIP0034Height,
hash: mustHashFromStr(t, "000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8"),
}
parent := &blockNode{
height: ancestor.height + 1,
hash: mustHashFromStr(t, "0000000000000000000000000000000000000000000000000000000000000002"),
parent: ancestor,
}
node := &blockNode{
height: parent.height + 1,
hash: mustHashFromStr(t, "0000000000000000000000000000000000000000000000000000000000000003"),
parent: parent,
}
require.False(t, bip0030CheckNeeded(node, &params))
}
// TestBip0030CheckNeededMismatchedActivation verifies that if the block at the
// recorded BIP34 activation height does not match, we continue to run the BIP30
// check (this matches Bitcoin Core's behavior and guards against alternative
// chains that have not activated BIP34 yet).
func TestBip0030CheckNeededMismatchedActivation(t *testing.T) {
params := chaincfg.MainNetParams
ancestor := &blockNode{
height: params.BIP0034Height,
hash: mustHashFromStr(t, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
}
parent := &blockNode{
height: ancestor.height + 1,
hash: mustHashFromStr(t, "0000000000000000000000000000000000000000000000000000000000000004"),
parent: ancestor,
}
node := &blockNode{
height: parent.height + 1,
hash: mustHashFromStr(t, "0000000000000000000000000000000000000000000000000000000000000005"),
parent: parent,
}
require.True(t, bip0030CheckNeeded(node, &params))
}
// TestBip0030CheckNeededReenabled ensures that once the chain reaches the
// re-enable height, the duplicate check is performed again even when BIP34 is
// active on the current branch.
func TestBip0030CheckNeededReenabled(t *testing.T) {
params := chaincfg.MainNetParams
ancestor := &blockNode{
height: params.BIP0034Height,
hash: mustHashFromStr(t, "000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8"),
}
parent := &blockNode{
height: ancestor.height + 1,
hash: mustHashFromStr(t, "0000000000000000000000000000000000000000000000000000000000000100"),
parent: ancestor,
}
node := &blockNode{
height: bip34ReenableBIP30Height,
hash: mustHashFromStr(t, "0000000000000000000000000000000000000000000000000000000000000200"),
parent: parent,
}
require.True(t, bip0030CheckNeeded(node, &params))
}