Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

blockchain, fullblocktests, workmath, testhelper: add InvalidateBlock() method to BlockChain #2155

Merged
merged 10 commits into from
May 22, 2024
Merged
Prev Previous commit
Next Next commit
blockchain: add block generating functions in test code
The block generating functions here allow for a test to create mock
blocks.  This is useful for testing invalidateblock and reconsiderblock
methods on blockchain that will be added in later commits.
  • Loading branch information
kcalvinalvin committed Apr 22, 2024
commit ea39fe090dddf45e3a91aaecd0dd6323ed5e5dc2
94 changes: 94 additions & 0 deletions blockchain/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"strings"
"time"

"github.com/btcsuite/btcd/blockchain/internal/testhelper"
"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
Expand Down Expand Up @@ -396,3 +397,96 @@ func newFakeNode(parent *blockNode, blockVersion int32, bits uint32, timestamp t
}
return newBlockNode(header, parent)
}

// addBlock adds a block to the blockchain that succeeds the previous block.
// The blocks spends all the provided spendable outputs. The new block and
// the new spendable outputs created in the block are returned.
func addBlock(chain *BlockChain, prev *btcutil.Block, spends []*testhelper.SpendableOut) (
*btcutil.Block, []*testhelper.SpendableOut, error) {

block, outs, err := newBlock(chain, prev, spends)
if err != nil {
return nil, nil, err
}

_, _, err = chain.ProcessBlock(block, BFNone)
if err != nil {
return nil, nil, err
}

return block, outs, nil
}

// calcMerkleRoot creates a merkle tree from the slice of transactions and
// returns the root of the tree.
func calcMerkleRoot(txns []*wire.MsgTx) chainhash.Hash {
if len(txns) == 0 {
return chainhash.Hash{}
}

utilTxns := make([]*btcutil.Tx, 0, len(txns))
for _, tx := range txns {
utilTxns = append(utilTxns, btcutil.NewTx(tx))
}
return CalcMerkleRoot(utilTxns, false)
}

// newBlock creates a block to the blockchain that succeeds the previous block.
// The blocks spends all the provided spendable outputs. The new block and the
// newly spendable outputs created in the block are returned.
func newBlock(chain *BlockChain, prev *btcutil.Block,
spends []*testhelper.SpendableOut) (*btcutil.Block, []*testhelper.SpendableOut, error) {

blockHeight := prev.Height() + 1
txns := make([]*wire.MsgTx, 0, 1+len(spends))

// Create and add coinbase tx.
cb := testhelper.CreateCoinbaseTx(blockHeight, CalcBlockSubsidy(blockHeight, chain.chainParams))
txns = append(txns, cb)

// Spend all txs to be spent.
for _, spend := range spends {
cb.TxOut[0].Value += int64(testhelper.LowFee)

spendTx := testhelper.CreateSpendTx(spend, testhelper.LowFee)
txns = append(txns, spendTx)
}

// Use a timestamp that is one second after the previous block unless
// this is the first block in which case the current time is used.
var ts time.Time
if blockHeight == 1 {
ts = time.Unix(time.Now().Unix(), 0)
} else {
ts = prev.MsgBlock().Header.Timestamp.Add(time.Second)
}

// Create the block. The nonce will be solved in the below code in
// SolveBlock.
block := btcutil.NewBlock(&wire.MsgBlock{
Header: wire.BlockHeader{
Version: 1,
PrevBlock: *prev.Hash(),
MerkleRoot: calcMerkleRoot(txns),
Bits: chain.chainParams.PowLimitBits,
Timestamp: ts,
Nonce: 0, // To be solved.
},
Transactions: txns,
})
block.SetHeight(blockHeight)

// Solve the block.
if !testhelper.SolveBlock(&block.MsgBlock().Header) {
return nil, nil, fmt.Errorf("Unable to solve block at height %d", blockHeight)
}

// Create spendable outs to return.
outs := make([]*testhelper.SpendableOut, len(txns))
for i, tx := range txns {
out := testhelper.MakeSpendableOutForTx(tx, 0)
outs[i] = &out
}

return block, outs, nil
}