blockchain: update calcSequenceLocks test to activate CSV first

This commit is contained in:
Olaoluwa Osuntokun 2016-11-12 19:44:41 -08:00
parent ca5e14da6a
commit d767af1509
No known key found for this signature in database
GPG key ID: 9CC5B105D03521A2

View file

@ -5,11 +5,15 @@
package blockchain_test package blockchain_test
import ( import (
"bytes"
"testing" "testing"
"time"
"github.com/btcsuite/btcd/blockchain" "github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/rpctest"
"github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil" "github.com/btcsuite/btcutil"
) )
@ -115,15 +119,10 @@ func TestHaveBlock(t *testing.T) {
// combinations of inputs to the CalcSequenceLock function in order to ensure // combinations of inputs to the CalcSequenceLock function in order to ensure
// the returned SequenceLocks are correct for each test instance. // the returned SequenceLocks are correct for each test instance.
func TestCalcSequenceLock(t *testing.T) { func TestCalcSequenceLock(t *testing.T) {
fileName := "blk_0_to_4.dat.bz2" netParams := &chaincfg.SimNetParams
blocks, err := loadBlocks(fileName)
if err != nil {
t.Errorf("Error loading file: %v\n", err)
return
}
// Create a new database and chain instance to run tests against. // Create a new database and chain instance to run tests against.
chain, teardownFunc, err := chainSetup("haveblock", &chaincfg.MainNetParams) chain, teardownFunc, err := chainSetup("haveblock", netParams)
if err != nil { if err != nil {
t.Errorf("Failed to setup chain instance: %v", err) t.Errorf("Failed to setup chain instance: %v", err)
return return
@ -134,46 +133,91 @@ func TestCalcSequenceLock(t *testing.T) {
// maturity to 1. // maturity to 1.
chain.TstSetCoinbaseMaturity(1) chain.TstSetCoinbaseMaturity(1)
// Load all the blocks into our test chain. // Create a test mining address to use for the blocks we'll generate
for i := 1; i < len(blocks); i++ { // shortly below.
_, isOrphan, err := chain.ProcessBlock(blocks[i], blockchain.BFNone) k := bytes.Repeat([]byte{1}, 32)
_, miningPub := btcec.PrivKeyFromBytes(btcec.S256(), k)
miningAddr, err := btcutil.NewAddressPubKey(miningPub.SerializeCompressed(),
netParams)
if err != nil {
t.Fatalf("unable to generate mining addr: %v", err)
}
// We'll keep track of the previous block for back pointers in blocks
// we generated, and also the generated blocks along with the MTP from
// their PoV to aide with our relative time lock calculations.
var prevBlock *btcutil.Block
var blocksWithMTP []struct {
block *btcutil.Block
mtp time.Time
}
// We need to activate CSV in order to test the processing logic, so
// manually craft the block version that's used to signal the soft-fork
// activation.
csvBit := netParams.Deployments[chaincfg.DeploymentCSV].BitNumber
blockVersion := int32(0x20000000 | (uint32(1) << csvBit))
// Generate enough blocks to activate CSV, collecting each of the
// blocks into a slice for later use.
numBlocksToActivate := (netParams.MinerConfirmationWindow * 3)
for i := uint32(0); i < numBlocksToActivate; i++ {
block, err := rpctest.CreateBlock(prevBlock, nil, blockVersion,
time.Time{}, miningAddr, netParams)
if err != nil { if err != nil {
t.Errorf("ProcessBlock fail on block %v: %v\n", i, err) t.Fatalf("unable to generate block: %v", err)
return }
mtp := chain.BestSnapshot().MedianTime
_, isOrphan, err := chain.ProcessBlock(block, blockchain.BFNone)
if err != nil {
t.Fatalf("ProcessBlock fail on block %v: %v\n", i, err)
} }
if isOrphan { if isOrphan {
t.Errorf("ProcessBlock incorrectly returned block %v "+ t.Fatalf("ProcessBlock incorrectly returned block %v "+
"is an orphan\n", i) "is an orphan\n", i)
return
} }
blocksWithMTP = append(blocksWithMTP, struct {
block *btcutil.Block
mtp time.Time
}{
block: block,
mtp: mtp,
})
prevBlock = block
} }
// Create with all the utxos within the create created above. // Create with all the utxos within the create created above.
utxoView := blockchain.NewUtxoViewpoint() utxoView := blockchain.NewUtxoViewpoint()
for blockHeight, block := range blocks { for blockHeight, blockWithMTP := range blocksWithMTP {
for _, tx := range block.Transactions() { for _, tx := range blockWithMTP.block.Transactions() {
utxoView.AddTxOuts(tx, int32(blockHeight)) utxoView.AddTxOuts(tx, int32(blockHeight))
} }
} }
utxoView.SetBestHash(blocks[len(blocks)-1].Hash()) utxoView.SetBestHash(blocksWithMTP[len(blocksWithMTP)-1].block.Hash())
// The median past time from the point of view of the second to last // The median time calculated from the PoV of the best block in our
// block in the chain. // test chain. For unconfirmed inputs, this value will be used since th
medianTime := blocks[2].MsgBlock().Header.Timestamp.Unix() // MTP will be calculated from the PoV of the yet-to-be-mined block.
nextMedianTime := int64(1401292712)
// The median past time of the *next* block will be the timestamp of
// the 2nd block due to the way MTP is calculated in order to be
// compatible with Bitcoin Core.
nextMedianTime := blocks[2].MsgBlock().Header.Timestamp.Unix()
// We'll refer to this utxo within each input in the transactions // We'll refer to this utxo within each input in the transactions
// created below. This block that includes this UTXO has a height of 4. // created below. This utxo has an age of 4 blocks and was mined within
targetTx := blocks[4].Transactions()[0] // block 297
targetTx := blocksWithMTP[len(blocksWithMTP)-4].block.Transactions()[0]
utxo := wire.OutPoint{ utxo := wire.OutPoint{
Hash: *targetTx.Hash(), Hash: *targetTx.Hash(),
Index: 0, Index: 0,
} }
// Obtain the median time past from the PoV of the input created above.
// The MTP for the input is the MTP from the PoV of the block *prior*
// to the one that included it.
medianTime := blocksWithMTP[len(blocksWithMTP)-5].mtp.Unix()
// Add an additional transaction which will serve as our unconfirmed // Add an additional transaction which will serve as our unconfirmed
// output. // output.
var fakeScript []byte var fakeScript []byte
@ -187,6 +231,7 @@ func TestCalcSequenceLock(t *testing.T) {
Hash: unConfTx.TxHash(), Hash: unConfTx.TxHash(),
Index: 0, Index: 0,
} }
// Adding a utxo with a height of 0x7fffffff indicates that the output // Adding a utxo with a height of 0x7fffffff indicates that the output
// is currently unmined. // is currently unmined.
utxoView.AddTxOuts(btcutil.NewTx(unConfTx), 0x7fffffff) utxoView.AddTxOuts(btcutil.NewTx(unConfTx), 0x7fffffff)
@ -283,24 +328,24 @@ func TestCalcSequenceLock(t *testing.T) {
Sequence: blockchain.LockTimeToSequence(true, 2560), Sequence: blockchain.LockTimeToSequence(true, 2560),
}, { }, {
PreviousOutPoint: utxo, PreviousOutPoint: utxo,
Sequence: blockchain.LockTimeToSequence(false, 3) | Sequence: blockchain.LockTimeToSequence(false, 5) |
wire.SequenceLockTimeDisabled, wire.SequenceLockTimeDisabled,
}, { }, {
PreviousOutPoint: utxo, PreviousOutPoint: utxo,
Sequence: blockchain.LockTimeToSequence(false, 3), Sequence: blockchain.LockTimeToSequence(false, 4),
}}, }},
}), }),
view: utxoView, view: utxoView,
want: &blockchain.SequenceLock{ want: &blockchain.SequenceLock{
Seconds: medianTime + (5 << wire.SequenceLockTimeGranularity) - 1, Seconds: medianTime + (5 << wire.SequenceLockTimeGranularity) - 1,
BlockHeight: 6, BlockHeight: 299,
}, },
}, },
// Transaction has a single input spending the genesis block // Transaction has a single input spending the genesis block
// transaction. The input's sequence number is encodes a // transaction. The input's sequence number is encodes a
// relative lock-time in blocks (3 blocks). The sequence lock // relative lock-time in blocks (3 blocks). The sequence lock
// should have a value of -1 for seconds, but a block height of // should have a value of -1 for seconds, but a block height of
// 6 meaning it can be included at height 7. // 298 meaning it can be included at height 299.
{ {
tx: btcutil.NewTx(&wire.MsgTx{ tx: btcutil.NewTx(&wire.MsgTx{
Version: 2, Version: 2,
@ -312,7 +357,7 @@ func TestCalcSequenceLock(t *testing.T) {
view: utxoView, view: utxoView,
want: &blockchain.SequenceLock{ want: &blockchain.SequenceLock{
Seconds: -1, Seconds: -1,
BlockHeight: 6, BlockHeight: 298,
}, },
}, },
// A transaction with two inputs with lock times expressed in // A transaction with two inputs with lock times expressed in
@ -337,8 +382,9 @@ func TestCalcSequenceLock(t *testing.T) {
}, },
// A transaction with two inputs with lock times expressed in // A transaction with two inputs with lock times expressed in
// seconds. The selected sequence lock value for blocks should // seconds. The selected sequence lock value for blocks should
// be the height further in the future, so a height of 10 // be the height further in the future. The converted absolute
// indicating in can be included at height 7. // block height should be 302, meaning it can be included in
// block 303.
{ {
tx: btcutil.NewTx(&wire.MsgTx{ tx: btcutil.NewTx(&wire.MsgTx{
Version: 2, Version: 2,
@ -353,7 +399,7 @@ func TestCalcSequenceLock(t *testing.T) {
view: utxoView, view: utxoView,
want: &blockchain.SequenceLock{ want: &blockchain.SequenceLock{
Seconds: -1, Seconds: -1,
BlockHeight: 10, BlockHeight: 302,
}, },
}, },
// A transaction with multiple inputs. Two inputs are time // A transaction with multiple inputs. Two inputs are time
@ -380,14 +426,15 @@ func TestCalcSequenceLock(t *testing.T) {
view: utxoView, view: utxoView,
want: &blockchain.SequenceLock{ want: &blockchain.SequenceLock{
Seconds: medianTime + (13 << wire.SequenceLockTimeGranularity) - 1, Seconds: medianTime + (13 << wire.SequenceLockTimeGranularity) - 1,
BlockHeight: 12, BlockHeight: 304,
}, },
}, },
// A transaction with a single unconfirmed input. As the input // A transaction with a single unconfirmed input. As the input
// is confirmed, the height of the input should be interpreted // is confirmed, the height of the input should be interpreted
// as the height of the *next* block. So the relative block // as the height of the *next* block. The current block height
// lock should be based from a height of 5 rather than a height // is 300, so the lock time should be calculated using height
// of 4. // 301 as a base. A 2 block relative lock means the transaction
// can be included after block 302, so in 303.
{ {
tx: btcutil.NewTx(&wire.MsgTx{ tx: btcutil.NewTx(&wire.MsgTx{
Version: 2, Version: 2,
@ -399,7 +446,7 @@ func TestCalcSequenceLock(t *testing.T) {
view: utxoView, view: utxoView,
want: &blockchain.SequenceLock{ want: &blockchain.SequenceLock{
Seconds: -1, Seconds: -1,
BlockHeight: 6, BlockHeight: 302,
}, },
}, },
// A transaction with a single unconfirmed input. The input has // A transaction with a single unconfirmed input. The input has