blockchain: update calcSequenceLocks test to activate CSV first
This commit is contained in:
parent
ca5e14da6a
commit
d767af1509
1 changed files with 87 additions and 40 deletions
|
@ -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
|
||||||
|
|
Loading…
Add table
Reference in a new issue