blockchain: Consolidate tests into package.

Putting the test code in the same package makes it easier for forks
since they don't have to change the import paths as much and it also
gets rid of the need for internal_test.go to bridge.

While here, remove the reorganization test since it is much better
handled by the full block tests and is no longer needed and do some
light cleanup on a few other tests.

The full block tests had to remain in the separate test package since it
is a circular dependency otherwise.  This did require duplicating some
of the chain setup code, but given the other benefits this is
acceptable.
This commit is contained in:
Dave Collins 2017-08-19 19:21:36 -05:00
parent f4fe6c373e
commit e02fbcf5a1
No known key found for this signature in database
GPG Key ID: B8904D9D9C93D1F2
14 changed files with 366 additions and 381 deletions

View File

@ -2,12 +2,11 @@
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package blockchain_test
package blockchain
import (
"testing"
"github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcutil"
)
@ -17,7 +16,7 @@ func BenchmarkIsCoinBase(b *testing.B) {
tx, _ := btcutil.NewBlock(&Block100000).Tx(1)
b.ResetTimer()
for i := 0; i < b.N; i++ {
blockchain.IsCoinBase(tx)
IsCoinBase(tx)
}
}
@ -27,6 +26,6 @@ func BenchmarkIsCoinBaseTx(b *testing.B) {
tx := Block100000.Transactions[1]
b.ResetTimer()
for i := 0; i < b.N; i++ {
blockchain.IsCoinBaseTx(tx)
IsCoinBaseTx(tx)
}
}

View File

@ -2,13 +2,12 @@
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package blockchain_test
package blockchain
import (
"testing"
"time"
"github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
@ -49,7 +48,7 @@ func TestHaveBlock(t *testing.T) {
chain.TstSetCoinbaseMaturity(1)
for i := 1; i < len(blocks); i++ {
_, isOrphan, err := chain.ProcessBlock(blocks[i], blockchain.BFNone)
_, isOrphan, err := chain.ProcessBlock(blocks[i], BFNone)
if err != nil {
t.Errorf("ProcessBlock fail on block %v: %v\n", i, err)
return
@ -63,7 +62,7 @@ func TestHaveBlock(t *testing.T) {
// Insert an orphan block.
_, isOrphan, err := chain.ProcessBlock(btcutil.NewBlock(&Block100000),
blockchain.BFNone)
BFNone)
if err != nil {
t.Errorf("Unable to process block: %v", err)
return
@ -125,12 +124,15 @@ func TestCalcSequenceLock(t *testing.T) {
blockVersion := int32(0x20000000 | (uint32(1) << csvBit))
// Generate enough synthetic blocks to activate CSV.
chain, node := blockchain.TstNewFakeChain(netParams)
chain := newFakeChain(netParams)
node := chain.bestNode
blockTime := node.Header().Timestamp
numBlocksToActivate := (netParams.MinerConfirmationWindow * 3)
for i := uint32(0); i < numBlocksToActivate; i++ {
blockTime = blockTime.Add(time.Second)
node = chain.TstNewFakeNode(node, blockVersion, 0, blockTime)
node = newFakeNode(node, blockVersion, 0, blockTime)
chain.index.AddNode(node)
chain.bestNode = node
}
// Create a utxo view with a fake utxo for the inputs used in the
@ -142,11 +144,9 @@ func TestCalcSequenceLock(t *testing.T) {
Value: 10,
}},
})
utxoView := blockchain.NewUtxoViewpoint()
utxoView := NewUtxoViewpoint()
utxoView.AddTxOuts(targetTx, int32(numBlocksToActivate)-4)
bestHeader := node.Header()
bestHash := bestHeader.BlockHash()
utxoView.SetBestHash(&bestHash)
utxoView.SetBestHash(&node.hash)
// Create a utxo that spends the fake utxo created above for use in the
// transactions created in the tests. It has an age of 4 blocks. Note
@ -190,9 +190,9 @@ func TestCalcSequenceLock(t *testing.T) {
tests := []struct {
tx *wire.MsgTx
view *blockchain.UtxoViewpoint
view *UtxoViewpoint
mempool bool
want *blockchain.SequenceLock
want *SequenceLock
}{
// A transaction of version one should disable sequence locks
// as the new sequence number semantics only apply to
@ -202,11 +202,11 @@ func TestCalcSequenceLock(t *testing.T) {
Version: 1,
TxIn: []*wire.TxIn{{
PreviousOutPoint: utxo,
Sequence: blockchain.LockTimeToSequence(false, 3),
Sequence: LockTimeToSequence(false, 3),
}},
},
view: utxoView,
want: &blockchain.SequenceLock{
want: &SequenceLock{
Seconds: -1,
BlockHeight: -1,
},
@ -223,7 +223,7 @@ func TestCalcSequenceLock(t *testing.T) {
}},
},
view: utxoView,
want: &blockchain.SequenceLock{
want: &SequenceLock{
Seconds: -1,
BlockHeight: -1,
},
@ -239,11 +239,11 @@ func TestCalcSequenceLock(t *testing.T) {
Version: 2,
TxIn: []*wire.TxIn{{
PreviousOutPoint: utxo,
Sequence: blockchain.LockTimeToSequence(true, 2),
Sequence: LockTimeToSequence(true, 2),
}},
},
view: utxoView,
want: &blockchain.SequenceLock{
want: &SequenceLock{
Seconds: medianTime - 1,
BlockHeight: -1,
},
@ -257,11 +257,11 @@ func TestCalcSequenceLock(t *testing.T) {
Version: 2,
TxIn: []*wire.TxIn{{
PreviousOutPoint: utxo,
Sequence: blockchain.LockTimeToSequence(true, 1024),
Sequence: LockTimeToSequence(true, 1024),
}},
},
view: utxoView,
want: &blockchain.SequenceLock{
want: &SequenceLock{
Seconds: medianTime + 1023,
BlockHeight: -1,
},
@ -277,18 +277,18 @@ func TestCalcSequenceLock(t *testing.T) {
Version: 2,
TxIn: []*wire.TxIn{{
PreviousOutPoint: utxo,
Sequence: blockchain.LockTimeToSequence(true, 2560),
Sequence: LockTimeToSequence(true, 2560),
}, {
PreviousOutPoint: utxo,
Sequence: blockchain.LockTimeToSequence(false, 4),
Sequence: LockTimeToSequence(false, 4),
}, {
PreviousOutPoint: utxo,
Sequence: blockchain.LockTimeToSequence(false, 5) |
Sequence: LockTimeToSequence(false, 5) |
wire.SequenceLockTimeDisabled,
}},
},
view: utxoView,
want: &blockchain.SequenceLock{
want: &SequenceLock{
Seconds: medianTime + (5 << wire.SequenceLockTimeGranularity) - 1,
BlockHeight: prevUtxoHeight + 3,
},
@ -302,11 +302,11 @@ func TestCalcSequenceLock(t *testing.T) {
Version: 2,
TxIn: []*wire.TxIn{{
PreviousOutPoint: utxo,
Sequence: blockchain.LockTimeToSequence(false, 3),
Sequence: LockTimeToSequence(false, 3),
}},
},
view: utxoView,
want: &blockchain.SequenceLock{
want: &SequenceLock{
Seconds: -1,
BlockHeight: prevUtxoHeight + 2,
},
@ -319,14 +319,14 @@ func TestCalcSequenceLock(t *testing.T) {
Version: 2,
TxIn: []*wire.TxIn{{
PreviousOutPoint: utxo,
Sequence: blockchain.LockTimeToSequence(true, 5120),
Sequence: LockTimeToSequence(true, 5120),
}, {
PreviousOutPoint: utxo,
Sequence: blockchain.LockTimeToSequence(true, 2560),
Sequence: LockTimeToSequence(true, 2560),
}},
},
view: utxoView,
want: &blockchain.SequenceLock{
want: &SequenceLock{
Seconds: medianTime + (10 << wire.SequenceLockTimeGranularity) - 1,
BlockHeight: -1,
},
@ -340,14 +340,14 @@ func TestCalcSequenceLock(t *testing.T) {
Version: 2,
TxIn: []*wire.TxIn{{
PreviousOutPoint: utxo,
Sequence: blockchain.LockTimeToSequence(false, 1),
Sequence: LockTimeToSequence(false, 1),
}, {
PreviousOutPoint: utxo,
Sequence: blockchain.LockTimeToSequence(false, 11),
Sequence: LockTimeToSequence(false, 11),
}},
},
view: utxoView,
want: &blockchain.SequenceLock{
want: &SequenceLock{
Seconds: -1,
BlockHeight: prevUtxoHeight + 10,
},
@ -360,20 +360,20 @@ func TestCalcSequenceLock(t *testing.T) {
Version: 2,
TxIn: []*wire.TxIn{{
PreviousOutPoint: utxo,
Sequence: blockchain.LockTimeToSequence(true, 2560),
Sequence: LockTimeToSequence(true, 2560),
}, {
PreviousOutPoint: utxo,
Sequence: blockchain.LockTimeToSequence(true, 6656),
Sequence: LockTimeToSequence(true, 6656),
}, {
PreviousOutPoint: utxo,
Sequence: blockchain.LockTimeToSequence(false, 3),
Sequence: LockTimeToSequence(false, 3),
}, {
PreviousOutPoint: utxo,
Sequence: blockchain.LockTimeToSequence(false, 9),
Sequence: LockTimeToSequence(false, 9),
}},
},
view: utxoView,
want: &blockchain.SequenceLock{
want: &SequenceLock{
Seconds: medianTime + (13 << wire.SequenceLockTimeGranularity) - 1,
BlockHeight: prevUtxoHeight + 8,
},
@ -389,12 +389,12 @@ func TestCalcSequenceLock(t *testing.T) {
Version: 2,
TxIn: []*wire.TxIn{{
PreviousOutPoint: unConfUtxo,
Sequence: blockchain.LockTimeToSequence(false, 2),
Sequence: LockTimeToSequence(false, 2),
}},
},
view: utxoView,
mempool: true,
want: &blockchain.SequenceLock{
want: &SequenceLock{
Seconds: -1,
BlockHeight: nextBlockHeight + 1,
},
@ -407,12 +407,12 @@ func TestCalcSequenceLock(t *testing.T) {
Version: 2,
TxIn: []*wire.TxIn{{
PreviousOutPoint: unConfUtxo,
Sequence: blockchain.LockTimeToSequence(true, 1024),
Sequence: LockTimeToSequence(true, 1024),
}},
},
view: utxoView,
mempool: true,
want: &blockchain.SequenceLock{
want: &SequenceLock{
Seconds: nextMedianTime + 1023,
BlockHeight: -1,
},

View File

@ -1,8 +1,8 @@
// Copyright (c) 2013-2016 The btcsuite developers
// Copyright (c) 2013-2017 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package blockchain_test
package blockchain
import (
"compress/bzip2"
@ -12,14 +12,15 @@ import (
"os"
"path/filepath"
"strings"
"time"
"github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/database"
_ "github.com/btcsuite/btcd/database/ffldb"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
)
const (
@ -56,10 +57,68 @@ func isSupportedDbType(dbType string) bool {
return false
}
// loadBlocks reads files containing bitcoin block data (gzipped but otherwise
// in the format bitcoind writes) from disk and returns them as an array of
// btcutil.Block. This is largely borrowed from the test code in btcdb.
func loadBlocks(filename string) (blocks []*btcutil.Block, err error) {
filename = filepath.Join("testdata/", filename)
var network = wire.MainNet
var dr io.Reader
var fi io.ReadCloser
fi, err = os.Open(filename)
if err != nil {
return
}
if strings.HasSuffix(filename, ".bz2") {
dr = bzip2.NewReader(fi)
} else {
dr = fi
}
defer fi.Close()
var block *btcutil.Block
err = nil
for height := int64(1); err == nil; height++ {
var rintbuf uint32
err = binary.Read(dr, binary.LittleEndian, &rintbuf)
if err == io.EOF {
// hit end of file at expected offset: no warning
height--
err = nil
break
}
if err != nil {
break
}
if rintbuf != uint32(network) {
break
}
err = binary.Read(dr, binary.LittleEndian, &rintbuf)
blocklen := rintbuf
rbytes := make([]byte, blocklen)
// read block
dr.Read(rbytes)
block, err = btcutil.NewBlockFromBytes(rbytes)
if err != nil {
return
}
blocks = append(blocks, block)
}
return
}
// chainSetup is used to create a new db and chain instance with the genesis
// block already inserted. In addition to the new chain instance, it returns
// a teardown function the caller should invoke when done testing to clean up.
func chainSetup(dbName string, params *chaincfg.Params) (*blockchain.BlockChain, func(), error) {
func chainSetup(dbName string, params *chaincfg.Params) (*BlockChain, func(), error) {
if !isSupportedDbType(testDbType) {
return nil, nil, fmt.Errorf("unsupported db type %v", testDbType)
}
@ -113,11 +172,11 @@ func chainSetup(dbName string, params *chaincfg.Params) (*blockchain.BlockChain,
paramsCopy := *params
// Create the main chain instance.
chain, err := blockchain.New(&blockchain.Config{
chain, err := New(&Config{
DB: db,
ChainParams: &paramsCopy,
Checkpoints: nil,
TimeSource: blockchain.NewMedianTime(),
TimeSource: NewMedianTime(),
SigCache: txscript.NewSigCache(1000),
})
if err != nil {
@ -129,7 +188,7 @@ func chainSetup(dbName string, params *chaincfg.Params) (*blockchain.BlockChain,
}
// loadUtxoView returns a utxo view loaded from a file.
func loadUtxoView(filename string) (*blockchain.UtxoViewpoint, error) {
func loadUtxoView(filename string) (*UtxoViewpoint, error) {
// The utxostore file format is:
// <tx hash><serialized utxo len><serialized utxo>
//
@ -151,7 +210,7 @@ func loadUtxoView(filename string) (*blockchain.UtxoViewpoint, error) {
}
defer fi.Close()
view := blockchain.NewUtxoViewpoint()
view := NewUtxoViewpoint()
for {
// Hash of the utxo entry.
var hash chainhash.Hash
@ -179,7 +238,7 @@ func loadUtxoView(filename string) (*blockchain.UtxoViewpoint, error) {
}
// Deserialize it and add it to the view.
utxoEntry, err := blockchain.TstDeserializeUtxoEntry(serialized)
utxoEntry, err := deserializeUtxoEntry(serialized)
if err != nil {
return nil, err
}
@ -188,3 +247,53 @@ func loadUtxoView(filename string) (*blockchain.UtxoViewpoint, error) {
return view, nil
}
// TstSetCoinbaseMaturity makes the ability to set the coinbase maturity
// available when running tests.
func (b *BlockChain) TstSetCoinbaseMaturity(maturity uint16) {
b.chainParams.CoinbaseMaturity = maturity
}
// newFakeChain returns a chain that is usable for syntetic tests. It is
// important to note that this chain has no database associated with it, so
// it is not usable with all functions and the tests must take care when making
// use of it.
func newFakeChain(params *chaincfg.Params) *BlockChain {
// Create a genesis block node and block index index populated with it
// for use when creating the fake chain below.
node := newBlockNode(&params.GenesisBlock.Header, 0)
node.inMainChain = true
index := newBlockIndex(nil, params)
index.AddNode(node)
targetTimespan := int64(params.TargetTimespan / time.Second)
targetTimePerBlock := int64(params.TargetTimePerBlock / time.Second)
adjustmentFactor := params.RetargetAdjustmentFactor
return &BlockChain{
chainParams: params,
timeSource: NewMedianTime(),
minRetargetTimespan: targetTimespan / adjustmentFactor,
maxRetargetTimespan: targetTimespan * adjustmentFactor,
blocksPerRetarget: int32(targetTimespan / targetTimePerBlock),
index: index,
warningCaches: newThresholdCaches(vbNumBits),
deploymentCaches: newThresholdCaches(chaincfg.DefinedDeployments),
bestNode: node,
}
}
// newFakeNode creates a block node connected to the passed parent with the
// provided fields populated and fake values for the other fields.
func newFakeNode(parent *blockNode, blockVersion int32, bits uint32, timestamp time.Time) *blockNode {
// Make up a header and create a block node from it.
header := &wire.BlockHeader{
Version: blockVersion,
PrevBlock: parent.hash,
Bits: bits,
Timestamp: timestamp,
}
node := newBlockNode(header, parent.height+1)
node.parent = parent
node.workSum.Add(parent.workSum, node.workSum)
return node
}

View File

@ -1,16 +1,16 @@
// Copyright (c) 2014 The btcsuite developers
// Copyright (c) 2014-2017 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package blockchain_test
package blockchain
import (
"math/big"
"testing"
"github.com/btcsuite/btcd/blockchain"
)
// TestBigToCompact ensures BigToCompact converts big integers to the expected
// compact representation.
func TestBigToCompact(t *testing.T) {
tests := []struct {
in int64
@ -22,7 +22,7 @@ func TestBigToCompact(t *testing.T) {
for x, test := range tests {
n := big.NewInt(test.in)
r := blockchain.BigToCompact(n)
r := BigToCompact(n)
if r != test.out {
t.Errorf("TestBigToCompact test #%d failed: got %d want %d\n",
x, r, test.out)
@ -31,6 +31,8 @@ func TestBigToCompact(t *testing.T) {
}
}
// TestCompactToBig ensures CompactToBig converts numbers using the compact
// representation to the expected big intergers.
func TestCompactToBig(t *testing.T) {
tests := []struct {
in uint32
@ -40,7 +42,7 @@ func TestCompactToBig(t *testing.T) {
}
for x, test := range tests {
n := blockchain.CompactToBig(test.in)
n := CompactToBig(test.in)
want := big.NewInt(test.out)
if n.Cmp(want) != 0 {
t.Errorf("TestCompactToBig test #%d failed: got %d want %d\n",
@ -50,6 +52,8 @@ func TestCompactToBig(t *testing.T) {
}
}
// TestCalcWork ensures CalcWork calculates the expected work value from values
// in compact representation.
func TestCalcWork(t *testing.T) {
tests := []struct {
in uint32
@ -61,7 +65,7 @@ func TestCalcWork(t *testing.T) {
for x, test := range tests {
bits := uint32(test.in)
r := blockchain.CalcWork(bits)
r := CalcWork(bits)
if r.Int64() != test.out {
t.Errorf("TestCalcWork test #%d failed: got %v want %d\n",
x, r.Int64(), test.out)

View File

@ -1,59 +1,57 @@
// Copyright (c) 2014 The btcsuite developers
// Copyright (c) 2014-2017 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package blockchain_test
package blockchain
import (
"testing"
"github.com/btcsuite/btcd/blockchain"
)
// TestErrorCodeStringer tests the stringized output for the ErrorCode type.
func TestErrorCodeStringer(t *testing.T) {
tests := []struct {
in blockchain.ErrorCode
in ErrorCode
want string
}{
{blockchain.ErrDuplicateBlock, "ErrDuplicateBlock"},
{blockchain.ErrBlockTooBig, "ErrBlockTooBig"},
{blockchain.ErrBlockVersionTooOld, "ErrBlockVersionTooOld"},
{blockchain.ErrInvalidTime, "ErrInvalidTime"},
{blockchain.ErrTimeTooOld, "ErrTimeTooOld"},
{blockchain.ErrTimeTooNew, "ErrTimeTooNew"},
{blockchain.ErrDifficultyTooLow, "ErrDifficultyTooLow"},
{blockchain.ErrUnexpectedDifficulty, "ErrUnexpectedDifficulty"},
{blockchain.ErrHighHash, "ErrHighHash"},
{blockchain.ErrBadMerkleRoot, "ErrBadMerkleRoot"},
{blockchain.ErrBadCheckpoint, "ErrBadCheckpoint"},
{blockchain.ErrForkTooOld, "ErrForkTooOld"},
{blockchain.ErrCheckpointTimeTooOld, "ErrCheckpointTimeTooOld"},
{blockchain.ErrNoTransactions, "ErrNoTransactions"},
{blockchain.ErrTooManyTransactions, "ErrTooManyTransactions"},
{blockchain.ErrNoTxInputs, "ErrNoTxInputs"},
{blockchain.ErrNoTxOutputs, "ErrNoTxOutputs"},
{blockchain.ErrTxTooBig, "ErrTxTooBig"},
{blockchain.ErrBadTxOutValue, "ErrBadTxOutValue"},
{blockchain.ErrDuplicateTxInputs, "ErrDuplicateTxInputs"},
{blockchain.ErrBadTxInput, "ErrBadTxInput"},
{blockchain.ErrBadCheckpoint, "ErrBadCheckpoint"},
{blockchain.ErrMissingTxOut, "ErrMissingTxOut"},
{blockchain.ErrUnfinalizedTx, "ErrUnfinalizedTx"},
{blockchain.ErrDuplicateTx, "ErrDuplicateTx"},
{blockchain.ErrOverwriteTx, "ErrOverwriteTx"},
{blockchain.ErrImmatureSpend, "ErrImmatureSpend"},
{blockchain.ErrSpendTooHigh, "ErrSpendTooHigh"},
{blockchain.ErrBadFees, "ErrBadFees"},
{blockchain.ErrTooManySigOps, "ErrTooManySigOps"},
{blockchain.ErrFirstTxNotCoinbase, "ErrFirstTxNotCoinbase"},
{blockchain.ErrMultipleCoinbases, "ErrMultipleCoinbases"},
{blockchain.ErrBadCoinbaseScriptLen, "ErrBadCoinbaseScriptLen"},
{blockchain.ErrBadCoinbaseValue, "ErrBadCoinbaseValue"},
{blockchain.ErrMissingCoinbaseHeight, "ErrMissingCoinbaseHeight"},
{blockchain.ErrBadCoinbaseHeight, "ErrBadCoinbaseHeight"},
{blockchain.ErrScriptMalformed, "ErrScriptMalformed"},
{blockchain.ErrScriptValidation, "ErrScriptValidation"},
{ErrDuplicateBlock, "ErrDuplicateBlock"},
{ErrBlockTooBig, "ErrBlockTooBig"},
{ErrBlockVersionTooOld, "ErrBlockVersionTooOld"},
{ErrInvalidTime, "ErrInvalidTime"},
{ErrTimeTooOld, "ErrTimeTooOld"},
{ErrTimeTooNew, "ErrTimeTooNew"},
{ErrDifficultyTooLow, "ErrDifficultyTooLow"},
{ErrUnexpectedDifficulty, "ErrUnexpectedDifficulty"},
{ErrHighHash, "ErrHighHash"},
{ErrBadMerkleRoot, "ErrBadMerkleRoot"},
{ErrBadCheckpoint, "ErrBadCheckpoint"},
{ErrForkTooOld, "ErrForkTooOld"},
{ErrCheckpointTimeTooOld, "ErrCheckpointTimeTooOld"},
{ErrNoTransactions, "ErrNoTransactions"},
{ErrTooManyTransactions, "ErrTooManyTransactions"},
{ErrNoTxInputs, "ErrNoTxInputs"},
{ErrNoTxOutputs, "ErrNoTxOutputs"},
{ErrTxTooBig, "ErrTxTooBig"},
{ErrBadTxOutValue, "ErrBadTxOutValue"},
{ErrDuplicateTxInputs, "ErrDuplicateTxInputs"},
{ErrBadTxInput, "ErrBadTxInput"},
{ErrBadCheckpoint, "ErrBadCheckpoint"},
{ErrMissingTxOut, "ErrMissingTxOut"},
{ErrUnfinalizedTx, "ErrUnfinalizedTx"},
{ErrDuplicateTx, "ErrDuplicateTx"},
{ErrOverwriteTx, "ErrOverwriteTx"},
{ErrImmatureSpend, "ErrImmatureSpend"},
{ErrSpendTooHigh, "ErrSpendTooHigh"},
{ErrBadFees, "ErrBadFees"},
{ErrTooManySigOps, "ErrTooManySigOps"},
{ErrFirstTxNotCoinbase, "ErrFirstTxNotCoinbase"},
{ErrMultipleCoinbases, "ErrMultipleCoinbases"},
{ErrBadCoinbaseScriptLen, "ErrBadCoinbaseScriptLen"},
{ErrBadCoinbaseValue, "ErrBadCoinbaseValue"},
{ErrMissingCoinbaseHeight, "ErrMissingCoinbaseHeight"},
{ErrBadCoinbaseHeight, "ErrBadCoinbaseHeight"},
{ErrScriptMalformed, "ErrScriptMalformed"},
{ErrScriptValidation, "ErrScriptValidation"},
{0xffff, "Unknown ErrorCode (65535)"},
}
@ -71,15 +69,15 @@ func TestErrorCodeStringer(t *testing.T) {
// TestRuleError tests the error output for the RuleError type.
func TestRuleError(t *testing.T) {
tests := []struct {
in blockchain.RuleError
in RuleError
want string
}{
{
blockchain.RuleError{Description: "duplicate block"},
RuleError{Description: "duplicate block"},
"duplicate block",
},
{
blockchain.RuleError{Description: "human-readable error"},
RuleError{Description: "human-readable error"},
"human-readable error",
},
}
@ -100,19 +98,19 @@ func TestDeploymentError(t *testing.T) {
t.Parallel()
tests := []struct {
in blockchain.DeploymentError
in DeploymentError
want string
}{
{
blockchain.DeploymentError(0),
DeploymentError(0),
"deployment ID 0 does not exist",
},
{
blockchain.DeploymentError(10),
DeploymentError(10),
"deployment ID 10 does not exist",
},
{
blockchain.DeploymentError(123),
DeploymentError(123),
"deployment ID 123 does not exist",
},
}

View File

@ -1,5 +1,5 @@
// Copyright (c) 2016 The Decred developers
// Copyright (c) 2016 The btcsuite developers
// Copyright (c) 2016-2017 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
@ -7,16 +7,128 @@ package blockchain_test
import (
"bytes"
"fmt"
"os"
"path/filepath"
"testing"
"github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/blockchain/fullblocktests"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/database"
_ "github.com/btcsuite/btcd/database/ffldb"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
)
const (
// testDbType is the database backend type to use for the tests.
testDbType = "ffldb"
// testDbRoot is the root directory used to create all test databases.
testDbRoot = "testdbs"
// blockDataNet is the expected network in the test block data.
blockDataNet = wire.MainNet
)
// filesExists returns whether or not the named file or directory exists.
func fileExists(name string) bool {
if _, err := os.Stat(name); err != nil {
if os.IsNotExist(err) {
return false
}
}
return true
}
// isSupportedDbType returns whether or not the passed database type is
// currently supported.
func isSupportedDbType(dbType string) bool {
supportedDrivers := database.SupportedDrivers()
for _, driver := range supportedDrivers {
if dbType == driver {
return true
}
}
return false
}
// chainSetup is used to create a new db and chain instance with the genesis
// block already inserted. In addition to the new chain instance, it returns
// a teardown function the caller should invoke when done testing to clean up.
func chainSetup(dbName string, params *chaincfg.Params) (*blockchain.BlockChain, func(), error) {
if !isSupportedDbType(testDbType) {
return nil, nil, fmt.Errorf("unsupported db type %v", testDbType)
}
// Handle memory database specially since it doesn't need the disk
// specific handling.
var db database.DB
var teardown func()
if testDbType == "memdb" {
ndb, err := database.Create(testDbType)
if err != nil {
return nil, nil, fmt.Errorf("error creating db: %v", err)
}
db = ndb
// Setup a teardown function for cleaning up. This function is
// returned to the caller to be invoked when it is done testing.
teardown = func() {
db.Close()
}
} else {
// Create the root directory for test databases.
if !fileExists(testDbRoot) {
if err := os.MkdirAll(testDbRoot, 0700); err != nil {
err := fmt.Errorf("unable to create test db "+
"root: %v", err)
return nil, nil, err
}
}
// Create a new database to store the accepted blocks into.
dbPath := filepath.Join(testDbRoot, dbName)
_ = os.RemoveAll(dbPath)
ndb, err := database.Create(testDbType, dbPath, blockDataNet)
if err != nil {
return nil, nil, fmt.Errorf("error creating db: %v", err)
}
db = ndb
// Setup a teardown function for cleaning up. This function is
// returned to the caller to be invoked when it is done testing.
teardown = func() {
db.Close()
os.RemoveAll(dbPath)
os.RemoveAll(testDbRoot)
}
}
// Copy the chain params to ensure any modifications the tests do to
// the chain parameters do not affect the global instance.
paramsCopy := *params
// Create the main chain instance.
chain, err := blockchain.New(&blockchain.Config{
DB: db,
ChainParams: &paramsCopy,
Checkpoints: nil,
TimeSource: blockchain.NewMedianTime(),
SigCache: txscript.NewSigCache(1000),
})
if err != nil {
teardown()
err := fmt.Errorf("failed to create chain instance: %v", err)
return nil, nil, err
}
return chain, teardown, nil
}
// TestFullBlocks ensures all tests generated by the fullblocktests package
// have the expected result when processed via ProcessBlock.
func TestFullBlocks(t *testing.T) {

View File

@ -1,99 +0,0 @@
// Copyright (c) 2013-2017 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
/*
This test file is part of the blockchain package rather than than the
blockchain_test package so it can bridge access to the internals to properly
test cases which are either not possible or can't reliably be tested via the
public interface. The functions are only exported while the tests are being
run.
*/
package blockchain
import (
"sort"
"time"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/wire"
)
// TstSetCoinbaseMaturity makes the ability to set the coinbase maturity
// available to the test package.
func (b *BlockChain) TstSetCoinbaseMaturity(maturity uint16) {
b.chainParams.CoinbaseMaturity = maturity
}
// TstTimeSorter makes the internal timeSorter type available to the test
// package.
func TstTimeSorter(times []int64) sort.Interface {
return timeSorter(times)
}
// TstCheckSerializedHeight makes the internal checkSerializedHeight function
// available to the test package.
var TstCheckSerializedHeight = checkSerializedHeight
// TstSetMaxMedianTimeEntries makes the ability to set the maximum number of
// median time entries available to the test package.
func TstSetMaxMedianTimeEntries(val int) {
maxMedianTimeEntries = val
}
// TstCheckBlockScripts makes the internal checkBlockScripts function available
// to the test package.
var TstCheckBlockScripts = checkBlockScripts
// TstDeserializeUtxoEntry makes the internal deserializeUtxoEntry function
// available to the test package.
var TstDeserializeUtxoEntry = deserializeUtxoEntry
// TstNewFakeChain returns a chain that is usable for syntetic tests. It is
// important to note that this chain has no database associated with it, so
// it is not usable with all functions and the tests must take care when making
// use of it.
func TstNewFakeChain(params *chaincfg.Params) (*BlockChain, *blockNode) {
// Create a genesis block node and block index index populated with it
// for use when creating the fake chain below.
node := newBlockNode(&params.GenesisBlock.Header, 0)
node.inMainChain = true
index := newBlockIndex(nil, params)
index.AddNode(node)
targetTimespan := int64(params.TargetTimespan / time.Second)
targetTimePerBlock := int64(params.TargetTimePerBlock / time.Second)
adjustmentFactor := params.RetargetAdjustmentFactor
return &BlockChain{
chainParams: params,
timeSource: NewMedianTime(),
minRetargetTimespan: targetTimespan / adjustmentFactor,
maxRetargetTimespan: targetTimespan * adjustmentFactor,
blocksPerRetarget: int32(targetTimespan / targetTimePerBlock),
index: index,
warningCaches: newThresholdCaches(vbNumBits),
deploymentCaches: newThresholdCaches(chaincfg.DefinedDeployments),
bestNode: node,
}, node
}
// TstNewFakeNode creates a block node connected to the passed parent with the
// provided fields populated and fake values for the other fields and adds it
// to the blockchain's index as well as makes it the best node.
func (b *BlockChain) TstNewFakeNode(parent *blockNode, blockVersion int32, bits uint32, timestamp time.Time) *blockNode {
// Make up a header and create a block node from it.
header := &wire.BlockHeader{
Version: blockVersion,
PrevBlock: parent.hash,
Bits: bits,
Timestamp: timestamp,
}
node := newBlockNode(header, parent.height+1)
node.parent = parent
node.workSum.Add(parent.workSum, node.workSum)
b.index.AddNode(node)
b.bestNode = node
return node
}

View File

@ -1,15 +1,13 @@
// Copyright (c) 2013-2014 The btcsuite developers
// Copyright (c) 2013-2017 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package blockchain_test
package blockchain
import (
"strconv"
"testing"
"time"
"github.com/btcsuite/btcd/blockchain"
)
// TestMedianTime tests the medianTime implementation.
@ -55,11 +53,11 @@ func TestMedianTime(t *testing.T) {
}
// Modify the max number of allowed median time entries for these tests.
blockchain.TstSetMaxMedianTimeEntries(10)
defer blockchain.TstSetMaxMedianTimeEntries(200)
maxMedianTimeEntries = 10
defer func() { maxMedianTimeEntries = 200 }()
for i, test := range tests {
filter := blockchain.NewMedianTime()
filter := NewMedianTime()
for j, offset := range test.in {
id := strconv.Itoa(j)
now := time.Unix(time.Now().Unix(), 0)

View File

@ -1,20 +1,19 @@
// Copyright (c) 2013-2014 The btcsuite developers
// Copyright (c) 2013-2017 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package blockchain_test
package blockchain
import (
"testing"
"github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcutil"
)
// TestMerkle tests the BuildMerkleTreeStore API.
func TestMerkle(t *testing.T) {
block := btcutil.NewBlock(&Block100000)
merkles := blockchain.BuildMerkleTreeStore(block.Transactions(), false)
merkles := BuildMerkleTreeStore(block.Transactions(), false)
calculatedMerkleRoot := merkles[len(merkles)-1]
wantMerkle := &Block100000.Header.MerkleRoot
if !wantMerkle.IsEqual(calculatedMerkleRoot) {

View File

@ -2,12 +2,11 @@
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package blockchain_test
package blockchain
import (
"testing"
"github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/chaincfg"
)
@ -27,8 +26,8 @@ func TestNotifications(t *testing.T) {
defer teardownFunc()
notificationCount := 0
callback := func(notification *blockchain.Notification) {
if notification.Type == blockchain.NTBlockAccepted {
callback := func(notification *Notification) {
if notification.Type == NTBlockAccepted {
notificationCount++
}
}
@ -40,7 +39,7 @@ func TestNotifications(t *testing.T) {
chain.Subscribe(callback)
}
_, _, err = chain.ProcessBlock(blocks[1], blockchain.BFNone)
_, _, err = chain.ProcessBlock(blocks[1], BFNone)
if err != nil {
t.Fatalf("ProcessBlock fail on block 1: %v\n", err)
}

View File

@ -1,129 +0,0 @@
// Copyright (c) 2013-2014 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package blockchain_test
import (
"compress/bzip2"
"encoding/binary"
"io"
"os"
"path/filepath"
"strings"
"testing"
"github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
)
// TestReorganization loads a set of test blocks which force a chain
// reorganization to test the block chain handling code.
// The test blocks were originally from a post on the bitcoin talk forums:
// https://bitcointalk.org/index.php?topic=46370.msg577556#msg577556
func TestReorganization(t *testing.T) {
// Intentionally load the side chain blocks out of order to ensure
// orphans are handled properly along with chain reorganization.
testFiles := []string{
"blk_0_to_4.dat.bz2",
"blk_4A.dat.bz2",
"blk_5A.dat.bz2",
"blk_3A.dat.bz2",
}
var blocks []*btcutil.Block
for _, file := range testFiles {
blockTmp, err := loadBlocks(file)
if err != nil {
t.Errorf("Error loading file: %v\n", err)
}
blocks = append(blocks, blockTmp...)
}
t.Logf("Number of blocks: %v\n", len(blocks))
// Create a new database and chain instance to run tests against.
chain, teardownFunc, err := chainSetup("reorg", &chaincfg.MainNetParams)
if err != nil {
t.Errorf("Failed to setup chain instance: %v", err)
return
}
defer teardownFunc()
// Since we're not dealing with the real block chain set the coinbase
// maturity to 1.
chain.TstSetCoinbaseMaturity(1)
expectedOrphans := map[int]struct{}{5: {}, 6: {}}
for i := 1; i < len(blocks); i++ {
_, isOrphan, err := chain.ProcessBlock(blocks[i], blockchain.BFNone)
if err != nil {
t.Errorf("ProcessBlock fail on block %v: %v\n", i, err)
return
}
if _, ok := expectedOrphans[i]; !ok && isOrphan {
t.Errorf("ProcessBlock incorrectly returned block %v "+
"is an orphan\n", i)
}
}
}
// loadBlocks reads files containing bitcoin block data (gzipped but otherwise
// in the format bitcoind writes) from disk and returns them as an array of
// btcutil.Block. This is largely borrowed from the test code in btcdb.
func loadBlocks(filename string) (blocks []*btcutil.Block, err error) {
filename = filepath.Join("testdata/", filename)
var network = wire.MainNet
var dr io.Reader
var fi io.ReadCloser
fi, err = os.Open(filename)
if err != nil {
return
}
if strings.HasSuffix(filename, ".bz2") {
dr = bzip2.NewReader(fi)
} else {
dr = fi
}
defer fi.Close()
var block *btcutil.Block
err = nil
for height := int64(1); err == nil; height++ {
var rintbuf uint32
err = binary.Read(dr, binary.LittleEndian, &rintbuf)
if err == io.EOF {
// hit end of file at expected offset: no warning
height--
err = nil
break
}
if err != nil {
break
}
if rintbuf != uint32(network) {
break
}
err = binary.Read(dr, binary.LittleEndian, &rintbuf)
blocklen := rintbuf
rbytes := make([]byte, blocklen)
// read block
dr.Read(rbytes)
block, err = btcutil.NewBlockFromBytes(rbytes)
if err != nil {
return
}
blocks = append(blocks, block)
}
return
}

View File

@ -1,15 +1,14 @@
// Copyright (c) 2013-2016 The btcsuite developers
// Copyright (c) 2013-2017 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package blockchain_test
package blockchain
import (
"fmt"
"runtime"
"testing"
"github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/txscript"
)
@ -42,8 +41,7 @@ func TestCheckBlockScripts(t *testing.T) {
}
scriptFlags := txscript.ScriptBip16
err = blockchain.TstCheckBlockScripts(blocks[0], view, scriptFlags,
nil, nil)
err = checkBlockScripts(blocks[0], view, scriptFlags, nil, nil)
if err != nil {
t.Errorf("Transaction script validation failed: %v\n", err)
return

View File

@ -2,14 +2,12 @@
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package blockchain_test
package blockchain
import (
"reflect"
"sort"
"testing"
"github.com/btcsuite/btcd/blockchain"
)
// TestTimeSorter tests the timeSorter implementation.
@ -39,7 +37,7 @@ func TestTimeSorter(t *testing.T) {
for i, test := range tests {
result := make([]int64, len(test.in))
copy(result, test.in)
sort.Sort(blockchain.TstTimeSorter(result))
sort.Sort(timeSorter(result))
if !reflect.DeepEqual(result, test.want) {
t.Errorf("timeSorter #%d got %v want %v", i, result,
test.want)

View File

@ -1,8 +1,8 @@
// Copyright (c) 2013-2016 The btcsuite developers
// Copyright (c) 2013-2017 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package blockchain_test
package blockchain
import (
"math"
@ -10,7 +10,6 @@ import (
"testing"
"time"
"github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
@ -20,15 +19,15 @@ import (
// TestSequenceLocksActive tests the SequenceLockActive function to ensure it
// works as expected in all possible combinations/scenarios.
func TestSequenceLocksActive(t *testing.T) {
seqLock := func(h int32, s int64) *blockchain.SequenceLock {
return &blockchain.SequenceLock{
seqLock := func(h int32, s int64) *SequenceLock {
return &SequenceLock{
Seconds: s,
BlockHeight: h,
}
}
tests := []struct {
seqLock *blockchain.SequenceLock
seqLock *SequenceLock
blockHeight int32
mtp time.Time
@ -55,7 +54,7 @@ func TestSequenceLocksActive(t *testing.T) {
t.Logf("Running %d sequence locks tests", len(tests))
for i, test := range tests {
got := blockchain.SequenceLockActive(test.seqLock,
got := SequenceLockActive(test.seqLock,
test.blockHeight, test.mtp)
if got != test.want {
t.Fatalf("SequenceLockActive #%d got %v want %v", i,
@ -89,8 +88,8 @@ func TestCheckConnectBlock(t *testing.T) {
func TestCheckBlockSanity(t *testing.T) {
powLimit := chaincfg.MainNetParams.PowLimit
block := btcutil.NewBlock(&Block100000)
timeSource := blockchain.NewMedianTime()
err := blockchain.CheckBlockSanity(block, powLimit, timeSource)
timeSource := NewMedianTime()
err := CheckBlockSanity(block, powLimit, timeSource)
if err != nil {
t.Errorf("CheckBlockSanity: %v", err)
}
@ -99,7 +98,7 @@ func TestCheckBlockSanity(t *testing.T) {
// second fails.
timestamp := block.MsgBlock().Header.Timestamp
block.MsgBlock().Header.Timestamp = timestamp.Add(time.Nanosecond)
err = blockchain.CheckBlockSanity(block, powLimit, timeSource)
err = CheckBlockSanity(block, powLimit, timeSource)
if err == nil {
t.Errorf("CheckBlockSanity: error is nil when it shouldn't be")
}
@ -115,11 +114,11 @@ func TestCheckSerializedHeight(t *testing.T) {
coinbaseTx.AddTxIn(wire.NewTxIn(coinbaseOutpoint, nil, nil))
// Expected rule errors.
missingHeightError := blockchain.RuleError{
ErrorCode: blockchain.ErrMissingCoinbaseHeight,
missingHeightError := RuleError{
ErrorCode: ErrMissingCoinbaseHeight,
}
badHeightError := blockchain.RuleError{
ErrorCode: blockchain.ErrBadCoinbaseHeight,
badHeightError := RuleError{
ErrorCode: ErrBadCoinbaseHeight,
}
tests := []struct {
@ -151,15 +150,15 @@ func TestCheckSerializedHeight(t *testing.T) {
msgTx.TxIn[0].SignatureScript = test.sigScript
tx := btcutil.NewTx(msgTx)
err := blockchain.TstCheckSerializedHeight(tx, test.wantHeight)
err := checkSerializedHeight(tx, test.wantHeight)
if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
t.Errorf("checkSerializedHeight #%d wrong error type "+
"got: %v <%T>, want: %T", i, err, err, test.err)
continue
}
if rerr, ok := err.(blockchain.RuleError); ok {
trerr := test.err.(blockchain.RuleError)
if rerr, ok := err.(RuleError); ok {
trerr := test.err.(RuleError)
if rerr.ErrorCode != trerr.ErrorCode {
t.Errorf("checkSerializedHeight #%d wrong "+
"error code got: %v, want: %v", i,