dcrd/internal/mining/mining_test.go
Dave Collins 12d7c2d44f
mining: Convert to use new stdaddr package.
This converts the internal mining package to use the stdaddr package
instead of dcrutil.Address as well as to support script versions.

All callers that use the mining package in the repository are updated
accordingly to maintain code that continues to build and work properly
as well as pass all tests.  In order to achieve this, it introduces
temporary address conversion code that will be removed in future
commits.

This is part of a series of commits to convert all packages in the
repository to make use of the new stdaddr package.
2021-04-09 13:39:15 -05:00

196 lines
6.4 KiB
Go

// Copyright (c) 2020-2021 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package mining
import (
"errors"
"testing"
"github.com/decred/dcrd/blockchain/v4"
"github.com/decred/dcrd/chaincfg/chainhash"
"github.com/decred/dcrd/chaincfg/v3"
"github.com/decred/dcrd/dcrutil/v4"
"github.com/decred/dcrd/txscript/v4"
"github.com/decred/dcrd/txscript/v4/stdaddr"
"github.com/decred/dcrd/wire"
)
// TestNewBlockTemplateBasicErrorScenarios tests various basic error scenarios
// that can occur during new block template generation.
func TestNewBlockTemplateBasicErrorScenarios(t *testing.T) {
t.Parallel()
// Create a new mining harness instance.
harness, _, err := newMiningHarness(chaincfg.MainNetParams())
if err != nil {
t.Fatalf("error creating mining harness: %v", err)
}
// Create a test address for use in template generation.
address, err := stdaddr.DecodeAddress("Dsi8CRt85xYyempXs7ZPL1rBxvDdAGZmgsg",
harness.chainParams)
if err != nil {
t.Fatalf("error decoding address: %v", err)
}
// Test error retrieving standard verify flags.
standardVerifyFlags := harness.policy.StandardVerifyFlags
var errFlags = errors.New("error retrieving standard verify flags")
harness.policy.StandardVerifyFlags = func() (txscript.ScriptFlags, error) {
return 0, errFlags
}
_, err = harness.generator.NewBlockTemplate(address)
if !errors.Is(err, errFlags) {
t.Fatalf("unexpected error retrieving standard verify flags -- got %v, "+
"want %v", err, errFlags)
}
harness.policy.StandardVerifyFlags = standardVerifyFlags
// Test error retrieving treasury agenda.
var errTreasuryAgenda = errors.New("error retrieving treasury agenda")
harness.chain.isTreasuryAgendaActiveErr = errTreasuryAgenda
_, err = harness.generator.NewBlockTemplate(address)
if !errors.Is(err, errTreasuryAgenda) {
t.Fatalf("unexpected error retrieving treasury agenda -- got %v, want %v",
err, errTreasuryAgenda)
}
harness.chain.isTreasuryAgendaActiveErr = nil
}
// TestNewBlockTemplate tests the generation of a new block template containing
// regular and vote transactions.
func TestNewBlockTemplate(t *testing.T) {
t.Parallel()
// Create a new mining harness instance.
harness, spendableOuts, err := newMiningHarness(chaincfg.MainNetParams())
if err != nil {
t.Fatalf("error creating mining harness: %v", err)
}
// Create a test address for use in template generation.
address, err := stdaddr.DecodeAddress("Dsi8CRt85xYyempXs7ZPL1rBxvDdAGZmgsg",
harness.chainParams)
if err != nil {
t.Fatalf("error decoding address: %v", err)
}
// Define a munger to apply transaction fees.
applyTxFee := func(fee int64) func(*wire.MsgTx) {
return func(tx *wire.MsgTx) {
tx.TxOut[0].Value -= fee
}
}
// Create additional transactions from the first spendable output provided by
// the harness.
numTxs := 6
txs := make([]*dcrutil.Tx, numTxs)
baseTx, err := harness.CreateSignedTx(spendableOuts, uint32(numTxs))
if err != nil {
t.Fatalf("unable to create transaction: %v", err)
}
harness.AddFakeUTXO(baseTx, harness.chain.bestState.Height, 1,
harness.chain.isTreasuryAgendaActive)
for i := 0; i < numTxs; i++ {
tx, err := harness.CreateSignedTx([]spendableOutput{
txOutToSpendableOut(baseTx, uint32(i), wire.TxTreeRegular)}, 1,
applyTxFee(5000))
if err != nil {
t.Fatalf("unable to create transaction: %v", err)
}
txs[i] = tx
}
// Create ticket purchase transactions spending the outputs of the prior
// regular transactions.
numVotes := 5
tickets := make([]*dcrutil.Tx, numVotes)
ticketHashes := make([]chainhash.Hash, numVotes)
for i := 0; i < numVotes; i++ {
ticket, err := harness.CreateTicketPurchase(txs[i], 40000)
if err != nil {
t.Fatalf("unable to create ticket purchase transaction: %v", err)
}
tickets[i] = ticket
ticketHashes[i] = ticket.MsgTx().TxHash()
}
// Add the ticket outputs as utxos to fake their existence. Use one after
// the stake enabled height for the height of the fake utxos to ensure they
// are mature for the votes cast at stake validation height below.
harness.chain.bestState = blockchain.BestState{
Height: harness.chainParams.StakeEnabledHeight + 1,
}
for i, ticket := range tickets {
harness.AddFakeUTXO(ticket, harness.chain.bestState.Height, uint32(i+1),
harness.chain.isTreasuryAgendaActive)
}
// Create votes on a block at stake validation height using the previously
// created tickets.
hash := chainhash.Hash{0x5c, 0xa1, 0xab, 0x1e}
harness.chain.tipGeneration = []chainhash.Hash{hash}
harness.chain.bestState = blockchain.BestState{
Hash: hash,
Height: harness.chainParams.StakeValidationHeight,
NextWinningTickets: ticketHashes,
}
votes := make([]*dcrutil.Tx, numVotes)
for i, ticket := range tickets {
vote, err := harness.CreateVote(ticket)
if err != nil {
t.Fatalf("unable to create vote: %v", err)
}
votes[i] = vote
}
// Add vote transactions to the tx source.
for _, vote := range votes {
_, err = harness.AddTransactionToTxSource(vote)
if err != nil {
t.Fatalf("unable to add transaction to the tx source: %v", err)
}
}
// Add remaining regular transactions to the tx source.
for i := numVotes; i < numTxs; i++ {
_, err = harness.AddTransactionToTxSource(txs[i])
if err != nil {
t.Fatalf("unable to add transaction to the tx source: %v", err)
}
}
// Generate a new block template.
blockTemplate, err := harness.generator.NewBlockTemplate(address)
if err != nil {
t.Fatalf("unexpected err generating block template: %v", err)
}
// Validate the number of transactions in the generated block template.
gotTx := len(blockTemplate.Block.Transactions)
wantTx := numTxs - numVotes + 1 // + 1 for coinbase.
if gotTx != wantTx {
t.Fatalf("unexpected number of transactions in template -- got %v, want %v",
gotTx, wantTx)
}
// Validate the number of stake transactions in the generated block template.
gotStx := len(blockTemplate.Block.STransactions)
wantStx := numVotes + 1 // + 1 for stakebase.
if gotStx != wantStx {
t.Fatalf("unexpected number of stake transactions in template -- got %v, "+
"want %v", gotStx, wantStx)
}
// Validate that the block is sane. These checks are context free.
block := dcrutil.NewBlock(blockTemplate.Block)
err = blockchain.CheckBlockSanity(block, harness.generator.cfg.TimeSource,
harness.chainParams)
if err != nil {
t.Fatalf("unexpected error when checking block sanity: %v", err)
}
}