dcrd/internal/mining/mining_test.go
Donald Adu-Poku 48e43ca109 multi: Start dcrutil v4 module dev cycle.
This updates the dcrutil module version to v4
and updates import and deps sites.
2020-12-16 16:30:24 -06:00

195 lines
6.3 KiB
Go

// Copyright (c) 2020 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/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 := dcrutil.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 := dcrutil.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)
}
}