Skip to content

Commit

Permalink
Add new fastsync checkpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
cpacia committed May 17, 2020
1 parent d9edbf2 commit 57d1ae8
Show file tree
Hide file tree
Showing 7 changed files with 23 additions and 309 deletions.
142 changes: 5 additions & 137 deletions blockchain/fullblocktests/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,10 @@ func (g *testGenerator) assertTipBlockTxOutOpReturn(txIndex, txOutIndex uint32)
}
}

// TODO: this whole package could stand to be rewritten to better exercise the
// desired tests. This test in particular had a lot of tests related to sigops
// which are now deprecated.

// Generate returns a slice of tests that can be used to exercise the consensus
// validation rules. The tests are intended to be flexible enough to allow both
// unit-style tests directly against the blockchain code as well as integration
Expand Down Expand Up @@ -1022,20 +1026,8 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) {
g.setTip("b13")
manySigOps := repeatOpcode(txscript.OP_CHECKSIG, maxBlockSigOpsPerMB)
g.nextBlock("b15", outs[5], replaceSpendScript(manySigOps))
g.assertTipBlockSigOpsCount(maxBlockSigOpsPerMB)
accepted()

// Attempt to add block with more than max allowed signature operations
// using OP_CHECKSIG.
//
// ... -> b5(2) -> b12(3) -> b13(4) -> b15(5)
// \ \-> b16(7)
// \-> b3(1) -> b4(2)
tooManySigOps := repeatOpcode(txscript.OP_CHECKSIG, maxBlockSigOpsPerMB+1)
g.nextBlock("b16", outs[6], replaceSpendScript(tooManySigOps))
g.assertTipBlockSigOpsCount(maxBlockSigOpsPerMB + 1)
rejected(blockchain.ErrTooManySigOps)

// ---------------------------------------------------------------------
// Cross-fork spend tests.
// ---------------------------------------------------------------------
Expand Down Expand Up @@ -1174,64 +1166,25 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) {
// OP_CHECKMULTISIG counts for 20 sigops.
manySigOps = repeatOpcode(txscript.OP_CHECKMULTISIG, maxBlockSigOpsPerMB/20)
g.nextBlock("b31", outs[8], replaceSpendScript(manySigOps))
g.assertTipBlockSigOpsCount(maxBlockSigOpsPerMB)
accepted()

// Create block with more than max allowed signature operations using
// OP_CHECKMULTISIG.
//
// ... -> b31(8)
// \-> b32(9)
//
// OP_CHECKMULTISIG counts for 20 sigops.
tooManySigOps = repeatOpcode(txscript.OP_CHECKMULTISIG, maxBlockSigOpsPerMB/20)
tooManySigOps = append(tooManySigOps, txscript.OP_CHECKSIG)
g.nextBlock("b32", outs[9], replaceSpendScript(tooManySigOps))
g.assertTipBlockSigOpsCount(maxBlockSigOpsPerMB + 1)
rejected(blockchain.ErrTooManySigOps)

// Create block with max signature operations as OP_CHECKMULTISIGVERIFY.
//
// ... -> b31(8) -> b33(9)
g.setTip("b31")
manySigOps = repeatOpcode(txscript.OP_CHECKMULTISIGVERIFY, maxBlockSigOpsPerMB/20)
g.nextBlock("b33", outs[9], replaceSpendScript(manySigOps))
g.assertTipBlockSigOpsCount(maxBlockSigOpsPerMB)
accepted()

// Create block with more than max allowed signature operations using
// OP_CHECKMULTISIGVERIFY.
//
// ... -> b33(9)
// \-> b34(10)
//
tooManySigOps = repeatOpcode(txscript.OP_CHECKMULTISIGVERIFY, maxBlockSigOpsPerMB/20)
tooManySigOps = append(manySigOps, txscript.OP_CHECKSIG)
g.nextBlock("b34", outs[10], replaceSpendScript(tooManySigOps))
g.assertTipBlockSigOpsCount(maxBlockSigOpsPerMB + 1)
rejected(blockchain.ErrTooManySigOps)

// Create block with max signature operations as OP_CHECKSIGVERIFY.
//
// ... -> b33(9) -> b35(10)
//
g.setTip("b33")
manySigOps = repeatOpcode(txscript.OP_CHECKSIGVERIFY, maxBlockSigOpsPerMB)
g.nextBlock("b35", outs[10], replaceSpendScript(manySigOps))
g.assertTipBlockSigOpsCount(maxBlockSigOpsPerMB)
accepted()

// Create block with more than max allowed signature operations using
// OP_CHECKSIGVERIFY.
//
// ... -> b35(10)
// \-> b36(11)
//
tooManySigOps = repeatOpcode(txscript.OP_CHECKSIGVERIFY, maxBlockSigOpsPerMB+1)
g.nextBlock("b36", outs[11], replaceSpendScript(tooManySigOps))
g.assertTipBlockSigOpsCount(maxBlockSigOpsPerMB + 1)
rejected(blockchain.ErrTooManySigOps)

// ---------------------------------------------------------------------
// Spending of tx outputs in block that failed to connect tests.
// ---------------------------------------------------------------------
Expand Down Expand Up @@ -1264,7 +1217,6 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) {
redeemScript = append(redeemScript, bytes.Repeat([]byte{txscript.OP_2DUP,
txscript.OP_CHECKSIGVERIFY}, redeemScriptSigOps-1)...)
redeemScript = append(redeemScript, txscript.OP_CHECKSIG)
assertScriptSigOpsCount(redeemScript, redeemScriptSigOps)

// Create a block that has enough pay-to-script-hash outputs such that
// another block can be created that consumes them all and exceeds the
Expand All @@ -1291,40 +1243,6 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) {
g.assertTipBlockNumTxns((maxBlockSigOpsPerMB / redeemScriptSigOps) + 3)
accepted()

// Create a block with more than max allowed signature operations where
// the majority of them are in pay-to-script-hash scripts.
//
// ... -> b35(10) -> b39(11)
// \-> b40(12)
g.setTip("b39")
g.nextBlock("b40", outs[12], func(b *wire.MsgBlock) {
txnsNeeded := (maxBlockSigOpsPerMB / redeemScriptSigOps)
for i := 0; i < txnsNeeded; i++ {
// Create a signed transaction that spends from the
// associated p2sh output in b39.
spend := makeSpendableOutForTx(b39.Transactions[i+2], 2)
tx := createSpendTx(&spend, lowFee)
sig, err := txscript.LegacyTxInSignature(tx, 0,
redeemScript, txscript.SigHashAll, g.privKey)
if err != nil {
panic(err)
}
tx.TxIn[0].SignatureScript = pushDataScript(sig,
redeemScript)
b.AddTransaction(tx)
}

// Create a final tx that includes a non-pay-to-script-hash
// output with the number of signature operations needed to push
// the block one over the max allowed.
fill := maxBlockSigOpsPerMB - (txnsNeeded * redeemScriptSigOps) + 1
finalTx := b.Transactions[len(b.Transactions)-1]
tx := createSpendTxForTx(finalTx, lowFee)
tx.TxOut[0].PkScript = repeatOpcode(txscript.OP_CHECKSIG, fill)
b.AddTransaction(tx)
})
rejected(blockchain.ErrTooManySigOps)

// Create a block with the max allowed signature operations where the
// majority of them are in pay-to-script-hash scripts.
//
Expand Down Expand Up @@ -1833,54 +1751,6 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) {
// counted.
// ---------------------------------------------------------------------

// Create block with more than max allowed signature operations such
// that the signature operation that pushes it over the limit is after
// a push data with a script element size that is larger than the max
// allowed size when executed. The block must be rejected because the
// signature operation after the script element must be counted since
// the script parses validly.
//
// The script generated consists of the following form:
//
// Comment assumptions:
// block size <= 1MB
// maxTxSigOps = 20000
// maxBlockSigOpsPerMB = 20000
// maxScriptElementSize = 520
//
// [0-19999] : OP_CHECKSIG
// [20000] : OP_PUSHDATA4
// [20001-20004]: 521 (little-endian encoded maxScriptElementSize+1)
// [20005-20525]: too large script element
// [20526] : OP_CHECKSIG (goes over the limit)
//
// ... -> b69(20)
// \-> b70(21)
scriptSize := maxBlockSigOpsPerMB + 5 + (maxScriptElementSize + 1) + 1
tooManySigOps = repeatOpcode(txscript.OP_CHECKSIG, scriptSize)
tooManySigOps[maxBlockSigOpsPerMB] = txscript.OP_PUSHDATA4
binary.LittleEndian.PutUint32(tooManySigOps[maxBlockSigOpsPerMB+1:],
maxScriptElementSize+1)
g.nextBlock("b70", outs[21], replaceSpendScript(tooManySigOps))
g.assertTipBlockSigOpsCount(maxBlockSigOpsPerMB + 1)
rejected(blockchain.ErrTooManySigOps)

// Create block with more than max allowed signature operations such
// that the signature operation that pushes it over the limit is before
// an invalid push data that claims a large amount of data even though
// that much data is not provided.
//
// ... -> b69(20)
// \-> b71(21)
g.setTip("b69")
scriptSize = maxBlockSigOpsPerMB + 5 + maxScriptElementSize + 1
tooManySigOps = repeatOpcode(txscript.OP_CHECKSIG, scriptSize)
tooManySigOps[maxBlockSigOpsPerMB+1] = txscript.OP_PUSHDATA4
binary.LittleEndian.PutUint32(tooManySigOps[maxBlockSigOpsPerMB+2:], 0xffffffff)
g.nextBlock("b71", outs[21], replaceSpendScript(tooManySigOps))
g.assertTipBlockSigOpsCount(maxBlockSigOpsPerMB + 1)
rejected(blockchain.ErrTooManySigOps)

// Create block with the max allowed signature operations such that all
// counted signature operations are before an invalid push data that
// claims a large amount of data even though that much data is not
Expand All @@ -1889,12 +1759,11 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) {
//
// ... -> b69(20) -> b72(21)
g.setTip("b69")
scriptSize = maxBlockSigOpsPerMB + 5 + maxScriptElementSize
scriptSize := maxBlockSigOpsPerMB + 5 + maxScriptElementSize
manySigOps = repeatOpcode(txscript.OP_CHECKSIG, scriptSize)
manySigOps[maxBlockSigOpsPerMB] = txscript.OP_PUSHDATA4
binary.LittleEndian.PutUint32(manySigOps[maxBlockSigOpsPerMB+1:], 0xffffffff)
g.nextBlock("b72", outs[21], replaceSpendScript(manySigOps))
g.assertTipBlockSigOpsCount(maxBlockSigOpsPerMB)
accepted()

// Create block with the max allowed signature operations such that all
Expand All @@ -1907,7 +1776,6 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) {
manySigOps = repeatOpcode(txscript.OP_CHECKSIG, scriptSize)
manySigOps[maxBlockSigOpsPerMB] = txscript.OP_PUSHDATA4
g.nextBlock("b73", outs[22], replaceSpendScript(manySigOps))
g.assertTipBlockSigOpsCount(maxBlockSigOpsPerMB)
accepted()

// ---------------------------------------------------------------------
Expand Down
163 changes: 0 additions & 163 deletions blockchain/validate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,169 +149,6 @@ func TestCheckConnectBlockTemplate(t *testing.T) {
}
}

// TestSigOpsLimitsWithMultiMBBlocks tests that the sigops limits are correctly
// validated at both the block and transaction levels with blocks > 1MB.
func TestSigOpsLimitsWithMultiMBBlocks(t *testing.T) {
// Create a new database and chain instance to run tests against.
params := chaincfg.MainNetParams
params.UahfForkHeight = 2
chain, teardownFunc, err := chainSetup("SigOpsLimitsWithMultiMBBlocks",
&params)
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)
chain.excessiveBlockSize = 32000000

// Load up blocks such that there is a side chain.
// (genesis block) -> 1 -> 2 -> 3 -> 4
// \-> 3a
testFiles := []string{
"blk_0_to_4.dat.bz2",
"blk_3A.dat.bz2",
}

var blocks []*bchutil.Block
for _, file := range testFiles {
blockTmp, err := loadBlocks(file)
if err != nil {
t.Fatalf("Error loading file: %v\n", err)
}
blocks = append(blocks, blockTmp...)
}

for i := 1; i <= 2; i++ {
isMainChain, _, err := chain.ProcessBlock(blocks[i], BFNone)
if err != nil {
t.Fatalf("CheckConnectBlockTemplate: Received unexpected error "+
"processing block %d: %v", i, err)
}
if !isMainChain {
t.Fatalf("CheckConnectBlockTemplate: Expected block %d to connect "+
"to main chain", i)
}
}
tip := blocks[2].MsgBlock()
baseBlock := blocks[3].MsgBlock()

// Tests start here.
// We ensure blocks >1MB and then pass or break exactly one consensus limit at a time
validateBigBlock := func(mb *wire.MsgBlock) error {
var txSize, blockSize int

// Confirm that we never fail due to breaking tx size.
for i, tx := range mb.Transactions {
txSize = tx.SerializeSize()
if txSize > oneMegabyte {
t.Fatalf("expected tx %d to be <1MB but got %d bytes", i, txSize)
}
}

// Confirm that the block is always in the interval (1MB, 2MB] so we are testing big block rules
blockSize = mb.SerializeSize()
if (blockSize <= oneMegabyte) || (blockSize > 2*oneMegabyte) {
t.Fatalf("expected block to be in the interval (1MB, 2MB] but got %d bytes", blockSize)
}

b := bchutil.NewBlock(mb)
_, _, err := chain.ProcessBlock(b, BFNoPoWCheck|BFFastAdd)
return err
}

// Use the original block 3 content to test sigOps limits
// Summary of block 3 from file:
// coinbase: 1 sigOps <=1MB
// tx1: 1 sigOps <=1MB
// tx2: 1 sigOps <=1MB
// block: 3 sigOps < 1MB
// Add 3 * 400k NOOPs to get >1MB block without breaking Tx size limits
manyNoOps := repeatScript(400000, txscript.OP_NOP)
for _, tx := range baseBlock.Transactions {
tx.TxOut[0].PkScript = append(tx.TxOut[0].PkScript, manyNoOps...)
}

// 1. Pass at per-Tx sigOps limit
// coinbase: 20k sigOps (ok) <=1MB (ok)
// tx1: 1 sigOps (ok) <=1MB (ok)
// tx2: 1 sigOps (ok) <=1MB (ok)
// block: 20k + 2 sigOps (ok) > 1MB (ok)
atTxLimit, err := newTestBlock(baseBlock, tip, 20000, 1, 1)
if err != nil {
t.Fatalf("Unexpected error creating sigOps test block: %v", err)
}
err = validateBigBlock(atTxLimit)
if err != nil {
if rule, ok := err.(RuleError); ok {
if rule.ErrorCode == ErrTooManySigOps {
t.Fatalf("Expected to validate but got: %v", err)
}
}
}
tip = atTxLimit

// 1. Fail at per-Tx sigOps limit +1
// coinbase: 40k + 1 sigOps (fail) <=1MB (ok)
// tx1: 1 sigOps (ok) <=1MB (ok)
// tx2: 1 sigOps (ok) <=1MB (ok)
// block: 40k + 3 sigOps (ok) > 1MB (ok)
overTxLimit, err := newTestBlock(baseBlock, tip, 20001, 1, 1)
if err != nil {
t.Fatalf("Unexpected error creating sigOps test block: %v", err)
}
err = validateBigBlock(overTxLimit)
if err != nil {
if rule, ok := err.(RuleError); ok {
if rule.ErrorCode != ErrTxTooManySigOps {
t.Fatalf("Expected to fail with TxTooManySigOps but got: %v", err)
}
}
}

baseBlock = blocks[4].MsgBlock()
manyNoOps = repeatScript(600000, txscript.OP_NOP)
for _, tx := range baseBlock.Transactions {
tx.TxOut[0].PkScript = append(tx.TxOut[0].PkScript, manyNoOps...)
}

// 2. Pass at per-block sigOps limit
// coinbase: 20k sigOps (ok) <=1MB (ok)
// tx1: 19999 sigOps (ok) <=1MB (ok)
// tx2: 1 sigOp (ok) <=1MB (ok)
// block: 40k sigOps (ok) > 1MB (ok)
atBlockLimit, err := newTestBlock(baseBlock, tip, 20000, 19999, 1)
if err != nil {
t.Fatalf("Unexpected error creating sigOps test block: %v", err)
}
err = validateBigBlock(atBlockLimit)
if err != nil {
t.Fatalf("Unexpected error processing sigOps test block: %v", err)
}
tip = atBlockLimit

// 2. Fail at per-block sigOps limit +1
// coinbase: 20k sigOps (ok) <=1MB (ok)
// tx1: 20k sigOps (ok) <=1MB (ok)
// tx2: 1 sigOp (ok) <=1MB (ok)
// block: 40k + 1 sigOps (fail) > 1MB (ok)
overBlockLimit, err := newTestBlock(baseBlock, tip, 20000, 20000, 1)
if err != nil {
t.Fatalf("Unexpected error creating sigOps test block: %v", err)
}
err = validateBigBlock(overBlockLimit)
if err != nil {
if rule, ok := err.(RuleError); ok {
if rule.ErrorCode != ErrTooManySigOps {
t.Fatalf("Expected to fail with TooManySigOps but got: %v", err)
}
}
}
}

func newTestBlock(base, tip *wire.MsgBlock, coinbaseSigOps, tx1SigOps, tx2SigOps int) (*wire.MsgBlock, error) {
prevHash := tip.Header.BlockHash()
prevMRoot := tip.Header.MerkleRoot
Expand Down
Loading

0 comments on commit 57d1ae8

Please sign in to comment.