aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xtest/functional/feature_block.py477
1 files changed, 234 insertions, 243 deletions
diff --git a/test/functional/feature_block.py b/test/functional/feature_block.py
index ad6b9eb218..181c7f3369 100755
--- a/test/functional/feature_block.py
+++ b/test/functional/feature_block.py
@@ -8,11 +8,9 @@ import struct
import time
from test_framework.blocktools import create_block, create_coinbase, create_transaction, get_legacy_sigopcount_block
-from test_framework.comptool import RejectResult, TestInstance, TestManager
from test_framework.key import CECKey
from test_framework.messages import (
CBlock,
- CBlockHeader,
COIN,
COutPoint,
CTransaction,
@@ -22,7 +20,7 @@ from test_framework.messages import (
uint256_from_compact,
uint256_from_str,
)
-from test_framework.mininode import network_thread_start
+from test_framework.mininode import P2PDataStore, network_thread_start, network_thread_join
from test_framework.script import (
CScript,
MAX_SCRIPT_ELEMENT_SIZE,
@@ -44,14 +42,8 @@ from test_framework.script import (
SignatureHash,
hash160,
)
-from test_framework.test_framework import ComparisonTestFramework
-from test_framework.util import *
-from test_framework.comptool import TestManager, TestInstance, RejectResult
-from test_framework.blocktools import *
-import time
-from test_framework.key import CECKey
-from test_framework.script import *
-import struct
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_equal
MAX_BLOCK_SIGOPS = 20000
@@ -63,9 +55,6 @@ class PreviousSpendableOutput():
# Use this class for tests that require behavior other than normal "mininode" behavior.
# For now, it is used to serialize a bloated varint (b64).
class CBrokenBlock(CBlock):
- def __init__(self, header=None):
- super(CBrokenBlock, self).__init__(header)
-
def initialize(self, base_block):
self.vtx = copy.deepcopy(base_block.vtx)
self.hashMerkleRoot = self.calc_merkle_root()
@@ -82,46 +71,43 @@ class CBrokenBlock(CBlock):
return r
def normal_serialize(self):
- r = b""
- r += super(CBrokenBlock, self).serialize()
- return r
+ return super().serialize()
-class FullBlockTest(ComparisonTestFramework):
- # Can either run this test as 1 node with expected answers, or two and compare them.
- # Change the "outcome" variable from each TestInstance object to only do the comparison.
+class FullBlockTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
self.setup_clean_chain = True
+ self.extra_args = [[]]
+
+ def run_test(self):
+ node = self.nodes[0] # convenience reference to the node
+
+ # reconnect_p2p() expects the network thread to be running
+ network_thread_start()
+
+ self.reconnect_p2p()
+
self.block_heights = {}
self.coinbase_key = CECKey()
self.coinbase_key.set_secretbytes(b"horsebattery")
self.coinbase_pubkey = self.coinbase_key.get_pubkey()
self.tip = None
self.blocks = {}
-
- def run_test(self):
- self.test = TestManager(self, self.options.tmpdir)
- self.test.add_all_connections(self.nodes)
- network_thread_start()
- self.test.run()
-
- def get_tests(self):
self.genesis_hash = int(self.nodes[0].getbestblockhash(), 16)
self.block_heights[self.genesis_hash] = 0
self.spendable_outputs = []
# Create a new block
- self.next_block(0)
+ b0 = self.next_block(0)
self.save_spendable_output()
- yield self.accepted()
+ self.sync_blocks([b0])
- # Now we need that block to mature so we can spend the coinbase.
- test = TestInstance(sync_every_block=False)
+ # Allow the block to mature
+ blocks = []
for i in range(99):
- self.next_block(5000 + i)
- test.blocks_and_transactions.append([self.tip, True])
+ blocks.append(self.next_block(5000 + i))
self.save_spendable_output()
- yield test
+ self.sync_blocks(blocks)
# collect spendable outputs now to avoid cluttering the code later on
out = []
@@ -131,15 +117,15 @@ class FullBlockTest(ComparisonTestFramework):
# Start by building a couple of blocks on top (which output is spent is
# in parentheses):
# genesis -> b1 (0) -> b2 (1)
- self.next_block(1, spend=out[0])
+ b1 = self.next_block(1, spend=out[0])
self.save_spendable_output()
- yield self.accepted()
- self.next_block(2, spend=out[1])
- yield self.accepted()
+ b2 = self.next_block(2, spend=out[1])
self.save_spendable_output()
- # so fork like this:
+ self.sync_blocks([b1, b2])
+
+ # Fork like this:
#
# genesis -> b1 (0) -> b2 (1)
# \-> b3 (1)
@@ -149,27 +135,27 @@ class FullBlockTest(ComparisonTestFramework):
self.move_tip(1)
b3 = self.next_block(3, spend=out[1])
txout_b3 = PreviousSpendableOutput(b3.vtx[1], 0)
- yield self.rejected()
+ self.sync_blocks([b3], False)
# Now we add another block to make the alternative chain longer.
#
# genesis -> b1 (0) -> b2 (1)
# \-> b3 (1) -> b4 (2)
self.log.info("Reorg to a longer chain")
- self.next_block(4, spend=out[2])
- yield self.accepted()
+ b4 = self.next_block(4, spend=out[2])
+ self.sync_blocks([b4])
# ... and back to the first chain.
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
# \-> b3 (1) -> b4 (2)
self.move_tip(2)
- self.next_block(5, spend=out[2])
+ b5 = self.next_block(5, spend=out[2])
self.save_spendable_output()
- yield self.rejected()
+ self.sync_blocks([b5], False)
self.log.info("Reorg back to the original chain")
- self.next_block(6, spend=out[3])
- yield self.accepted()
+ b6 = self.next_block(6, spend=out[3])
+ self.sync_blocks([b6], True)
# Try to create a fork that double-spends
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
@@ -177,11 +163,11 @@ class FullBlockTest(ComparisonTestFramework):
# \-> b3 (1) -> b4 (2)
self.log.info("Reject a chain with a double spend, even if it is longer")
self.move_tip(5)
- self.next_block(7, spend=out[2])
- yield self.rejected()
+ b7 = self.next_block(7, spend=out[2])
+ self.sync_blocks([b7], False)
- self.next_block(8, spend=out[4])
- yield self.rejected()
+ b8 = self.next_block(8, spend=out[4])
+ self.sync_blocks([b8], False, reconnect=True)
# Try to create a block that has too much fee
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
@@ -189,8 +175,8 @@ class FullBlockTest(ComparisonTestFramework):
# \-> b3 (1) -> b4 (2)
self.log.info("Reject a block where the miner creates too much coinbase reward")
self.move_tip(6)
- self.next_block(9, spend=out[4], additional_coinbase_value=1)
- yield self.rejected(RejectResult(16, b'bad-cb-amount'))
+ b9 = self.next_block(9, spend=out[4], additional_coinbase_value=1)
+ self.sync_blocks([b9], False, 16, b'bad-cb-amount', reconnect=True)
# Create a fork that ends in a block with too much fee (the one that causes the reorg)
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
@@ -198,33 +184,27 @@ class FullBlockTest(ComparisonTestFramework):
# \-> b3 (1) -> b4 (2)
self.log.info("Reject a chain where the miner creates too much coinbase reward, even if the chain is longer")
self.move_tip(5)
- self.next_block(10, spend=out[3])
- yield self.rejected()
+ b10 = self.next_block(10, spend=out[3])
+ self.sync_blocks([b10], False)
- self.next_block(11, spend=out[4], additional_coinbase_value=1)
- yield self.rejected(RejectResult(16, b'bad-cb-amount'))
+ b11 = self.next_block(11, spend=out[4], additional_coinbase_value=1)
+ self.sync_blocks([b11], False, 16, b'bad-cb-amount', reconnect=True)
# Try again, but with a valid fork first
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
# \-> b12 (3) -> b13 (4) -> b14 (5)
- # (b12 added last)
# \-> b3 (1) -> b4 (2)
self.log.info("Reject a chain where the miner creates too much coinbase reward, even if the chain is longer (on a forked chain)")
self.move_tip(5)
b12 = self.next_block(12, spend=out[3])
self.save_spendable_output()
b13 = self.next_block(13, spend=out[4])
- # Deliver the block header for b12, and the block b13.
- # b13 should be accepted but the tip won't advance until b12 is delivered.
- yield TestInstance([[CBlockHeader(b12), None], [b13, False]])
-
self.save_spendable_output()
- # b14 is invalid, but the node won't know that until it tries to connect
- # Tip still can't advance because b12 is missing
- self.next_block(14, spend=out[5], additional_coinbase_value=1)
- yield self.rejected()
+ b14 = self.next_block(14, spend=out[5], additional_coinbase_value=1)
+ self.sync_blocks([b12, b13, b14], False, 16, b'bad-cb-amount', reconnect=True)
- yield TestInstance([[b12, True, b13.sha256]]) # New tip should be b13.
+ # New tip should be b13.
+ assert_equal(node.getbestblockhash(), b13.hash)
# Add a block with MAX_BLOCK_SIGOPS and one with one more sigop
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
@@ -233,14 +213,14 @@ class FullBlockTest(ComparisonTestFramework):
self.log.info("Accept a block with lots of checksigs")
lots_of_checksigs = CScript([OP_CHECKSIG] * (MAX_BLOCK_SIGOPS - 1))
self.move_tip(13)
- self.next_block(15, spend=out[5], script=lots_of_checksigs)
- yield self.accepted()
+ b15 = self.next_block(15, spend=out[5], script=lots_of_checksigs)
self.save_spendable_output()
+ self.sync_blocks([b15], True)
self.log.info("Reject a block with too many checksigs")
too_many_checksigs = CScript([OP_CHECKSIG] * (MAX_BLOCK_SIGOPS))
- self.next_block(16, spend=out[6], script=too_many_checksigs)
- yield self.rejected(RejectResult(16, b'bad-blk-sigops'))
+ b16 = self.next_block(16, spend=out[6], script=too_many_checksigs)
+ self.sync_blocks([b16], False, 16, b'bad-blk-sigops', reconnect=True)
# Attempt to spend a transaction created on a different fork
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
@@ -248,8 +228,8 @@ class FullBlockTest(ComparisonTestFramework):
# \-> b3 (1) -> b4 (2)
self.log.info("Reject a block with a spend from a re-org'ed out tx")
self.move_tip(15)
- self.next_block(17, spend=txout_b3)
- yield self.rejected(RejectResult(16, b'bad-txns-inputs-missingorspent'))
+ b17 = self.next_block(17, spend=txout_b3)
+ self.sync_blocks([b17], False, 16, b'bad-txns-inputs-missingorspent', reconnect=True)
# Attempt to spend a transaction created on a different fork (on a fork this time)
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
@@ -258,11 +238,11 @@ class FullBlockTest(ComparisonTestFramework):
# \-> b3 (1) -> b4 (2)
self.log.info("Reject a block with a spend from a re-org'ed out tx (on a forked chain)")
self.move_tip(13)
- self.next_block(18, spend=txout_b3)
- yield self.rejected()
+ b18 = self.next_block(18, spend=txout_b3)
+ self.sync_blocks([b18], False)
- self.next_block(19, spend=out[6])
- yield self.rejected()
+ b19 = self.next_block(19, spend=out[6])
+ self.sync_blocks([b19], False, 16, b'bad-txns-inputs-missingorspent', reconnect=True)
# Attempt to spend a coinbase at depth too low
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
@@ -270,8 +250,8 @@ class FullBlockTest(ComparisonTestFramework):
# \-> b3 (1) -> b4 (2)
self.log.info("Reject a block spending an immature coinbase.")
self.move_tip(15)
- self.next_block(20, spend=out[7])
- yield self.rejected(RejectResult(16, b'bad-txns-premature-spend-of-coinbase'))
+ b20 = self.next_block(20, spend=out[7])
+ self.sync_blocks([b20], False, 16, b'bad-txns-premature-spend-of-coinbase')
# Attempt to spend a coinbase at depth too low (on a fork this time)
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
@@ -280,11 +260,11 @@ class FullBlockTest(ComparisonTestFramework):
# \-> b3 (1) -> b4 (2)
self.log.info("Reject a block spending an immature coinbase (on a forked chain)")
self.move_tip(13)
- self.next_block(21, spend=out[6])
- yield self.rejected()
+ b21 = self.next_block(21, spend=out[6])
+ self.sync_blocks([b21], False)
- self.next_block(22, spend=out[5])
- yield self.rejected()
+ b22 = self.next_block(22, spend=out[5])
+ self.sync_blocks([b22], False, 16, b'bad-txns-premature-spend-of-coinbase')
# Create a block on either side of MAX_BLOCK_BASE_SIZE and make sure its accepted/rejected
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
@@ -302,7 +282,7 @@ class FullBlockTest(ComparisonTestFramework):
b23 = self.update_block(23, [tx])
# Make sure the math above worked out to produce a max-sized block
assert_equal(len(b23.serialize()), MAX_BLOCK_BASE_SIZE)
- yield self.accepted()
+ self.sync_blocks([b23], True)
self.save_spendable_output()
self.log.info("Reject a block of size MAX_BLOCK_BASE_SIZE + 1")
@@ -313,10 +293,10 @@ class FullBlockTest(ComparisonTestFramework):
tx.vout = [CTxOut(0, script_output)]
b24 = self.update_block(24, [tx])
assert_equal(len(b24.serialize()), MAX_BLOCK_BASE_SIZE + 1)
- yield self.rejected(RejectResult(16, b'bad-blk-length'))
+ self.sync_blocks([b24], False, 16, b'bad-blk-length', reconnect=True)
- self.next_block(25, spend=out[7])
- yield self.rejected()
+ b25 = self.next_block(25, spend=out[7])
+ self.sync_blocks([b25], False)
# Create blocks with a coinbase input script size out of range
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
@@ -331,11 +311,11 @@ class FullBlockTest(ComparisonTestFramework):
# update_block causes the merkle root to get updated, even with no new
# transactions, and updates the required state.
b26 = self.update_block(26, [])
- yield self.rejected(RejectResult(16, b'bad-cb-length'))
+ self.sync_blocks([b26], False, 16, b'bad-cb-length', reconnect=True)
# Extend the b26 chain to make sure bitcoind isn't accepting b26
- self.next_block(27, spend=out[7])
- yield self.rejected(False)
+ b27 = self.next_block(27, spend=out[7])
+ self.sync_blocks([b27], False)
# Now try a too-large-coinbase script
self.move_tip(15)
@@ -343,11 +323,11 @@ class FullBlockTest(ComparisonTestFramework):
b28.vtx[0].vin[0].scriptSig = b'\x00' * 101
b28.vtx[0].rehash()
b28 = self.update_block(28, [])
- yield self.rejected(RejectResult(16, b'bad-cb-length'))
+ self.sync_blocks([b28], False, 16, b'bad-cb-length', reconnect=True)
# Extend the b28 chain to make sure bitcoind isn't accepting b28
- self.next_block(29, spend=out[7])
- yield self.rejected(False)
+ b29 = self.next_block(29, spend=out[7])
+ self.sync_blocks([b29], False)
# b30 has a max-sized coinbase scriptSig.
self.move_tip(23)
@@ -355,7 +335,7 @@ class FullBlockTest(ComparisonTestFramework):
b30.vtx[0].vin[0].scriptSig = b'\x00' * 100
b30.vtx[0].rehash()
b30 = self.update_block(30, [])
- yield self.accepted()
+ self.sync_blocks([b30], True)
self.save_spendable_output()
# b31 - b35 - check sigops of OP_CHECKMULTISIG / OP_CHECKMULTISIGVERIFY / OP_CHECKSIGVERIFY
@@ -371,7 +351,7 @@ class FullBlockTest(ComparisonTestFramework):
lots_of_multisigs = CScript([OP_CHECKMULTISIG] * ((MAX_BLOCK_SIGOPS - 1) // 20) + [OP_CHECKSIG] * 19)
b31 = self.next_block(31, spend=out[8], script=lots_of_multisigs)
assert_equal(get_legacy_sigopcount_block(b31), MAX_BLOCK_SIGOPS)
- yield self.accepted()
+ self.sync_blocks([b31], True)
self.save_spendable_output()
# this goes over the limit because the coinbase has one sigop
@@ -379,33 +359,33 @@ class FullBlockTest(ComparisonTestFramework):
too_many_multisigs = CScript([OP_CHECKMULTISIG] * (MAX_BLOCK_SIGOPS // 20))
b32 = self.next_block(32, spend=out[9], script=too_many_multisigs)
assert_equal(get_legacy_sigopcount_block(b32), MAX_BLOCK_SIGOPS + 1)
- yield self.rejected(RejectResult(16, b'bad-blk-sigops'))
+ self.sync_blocks([b32], False, 16, b'bad-blk-sigops', reconnect=True)
# CHECKMULTISIGVERIFY
self.log.info("Accept a block with the max number of OP_CHECKMULTISIGVERIFY sigops")
self.move_tip(31)
lots_of_multisigs = CScript([OP_CHECKMULTISIGVERIFY] * ((MAX_BLOCK_SIGOPS - 1) // 20) + [OP_CHECKSIG] * 19)
- self.next_block(33, spend=out[9], script=lots_of_multisigs)
- yield self.accepted()
+ b33 = self.next_block(33, spend=out[9], script=lots_of_multisigs)
+ self.sync_blocks([b33], True)
self.save_spendable_output()
self.log.info("Reject a block with too many OP_CHECKMULTISIGVERIFY sigops")
too_many_multisigs = CScript([OP_CHECKMULTISIGVERIFY] * (MAX_BLOCK_SIGOPS // 20))
- self.next_block(34, spend=out[10], script=too_many_multisigs)
- yield self.rejected(RejectResult(16, b'bad-blk-sigops'))
+ b34 = self.next_block(34, spend=out[10], script=too_many_multisigs)
+ self.sync_blocks([b34], False, 16, b'bad-blk-sigops', reconnect=True)
# CHECKSIGVERIFY
self.log.info("Accept a block with the max number of OP_CHECKSIGVERIFY sigops")
self.move_tip(33)
lots_of_checksigs = CScript([OP_CHECKSIGVERIFY] * (MAX_BLOCK_SIGOPS - 1))
b35 = self.next_block(35, spend=out[10], script=lots_of_checksigs)
- yield self.accepted()
+ self.sync_blocks([b35], True)
self.save_spendable_output()
self.log.info("Reject a block with too many OP_CHECKSIGVERIFY sigops")
too_many_checksigs = CScript([OP_CHECKSIGVERIFY] * (MAX_BLOCK_SIGOPS))
- self.next_block(36, spend=out[11], script=too_many_checksigs)
- yield self.rejected(RejectResult(16, b'bad-blk-sigops'))
+ b36 = self.next_block(36, spend=out[11], script=too_many_checksigs)
+ self.sync_blocks([b36], False, 16, b'bad-blk-sigops', reconnect=True)
# Check spending of a transaction in a block which failed to connect
#
@@ -422,12 +402,12 @@ class FullBlockTest(ComparisonTestFramework):
txout_b37 = PreviousSpendableOutput(b37.vtx[1], 0)
tx = self.create_and_sign_transaction(out[11].tx, out[11].n, 0)
b37 = self.update_block(37, [tx])
- yield self.rejected(RejectResult(16, b'bad-txns-inputs-missingorspent'))
+ self.sync_blocks([b37], False, 16, b'bad-txns-inputs-missingorspent', reconnect=True)
# attempt to spend b37's first non-coinbase tx, at which point b37 was still considered valid
self.move_tip(35)
- self.next_block(38, spend=txout_b37)
- yield self.rejected(RejectResult(16, b'bad-txns-inputs-missingorspent'))
+ b38 = self.next_block(38, spend=txout_b37)
+ self.sync_blocks([b38], False, 16, b'bad-txns-inputs-missingorspent', reconnect=True)
# Check P2SH SigOp counting
#
@@ -477,7 +457,7 @@ class FullBlockTest(ComparisonTestFramework):
b39_outputs += 1
b39 = self.update_block(39, [])
- yield self.accepted()
+ self.sync_blocks([b39], True)
self.save_spendable_output()
# Test sigops in P2SH redeem scripts
@@ -519,12 +499,12 @@ class FullBlockTest(ComparisonTestFramework):
tx.rehash()
new_txs.append(tx)
self.update_block(40, new_txs)
- yield self.rejected(RejectResult(16, b'bad-blk-sigops'))
+ self.sync_blocks([b40], False, 16, b'bad-blk-sigops', reconnect=True)
# same as b40, but one less sigop
self.log.info("Accept a block with the max number of P2SH sigops")
self.move_tip(39)
- self.next_block(41, spend=None)
+ b41 = self.next_block(41, spend=None)
self.update_block(41, b40.vtx[1:-1])
b41_sigops_to_fill = b40_sigops_to_fill - 1
tx = CTransaction()
@@ -532,7 +512,7 @@ class FullBlockTest(ComparisonTestFramework):
tx.vout.append(CTxOut(1, CScript([OP_CHECKSIG] * b41_sigops_to_fill)))
tx.rehash()
self.update_block(41, [tx])
- yield self.accepted()
+ self.sync_blocks([b41], True)
# Fork off of b39 to create a constant base again
#
@@ -540,13 +520,12 @@ class FullBlockTest(ComparisonTestFramework):
# \-> b41 (12)
#
self.move_tip(39)
- self.next_block(42, spend=out[12])
- yield self.rejected()
+ b42 = self.next_block(42, spend=out[12])
self.save_spendable_output()
- self.next_block(43, spend=out[13])
- yield self.accepted()
+ b43 = self.next_block(43, spend=out[13])
self.save_spendable_output()
+ self.sync_blocks([b42, b43], True)
# Test a number of really invalid scenarios
#
@@ -568,7 +547,7 @@ class FullBlockTest(ComparisonTestFramework):
self.tip = b44
self.block_heights[b44.sha256] = height
self.blocks[44] = b44
- yield self.accepted()
+ self.sync_blocks([b44], True)
self.log.info("Reject a block with a non-coinbase as the first tx")
non_coinbase = self.create_tx(out[15].tx, out[15].n, 1)
@@ -583,7 +562,7 @@ class FullBlockTest(ComparisonTestFramework):
self.block_heights[b45.sha256] = self.block_heights[self.tip.sha256] + 1
self.tip = b45
self.blocks[45] = b45
- yield self.rejected(RejectResult(16, b'bad-cb-missing'))
+ self.sync_blocks([b45], False, 16, b'bad-cb-missing', reconnect=True)
self.log.info("Reject a block with no transactions")
self.move_tip(44)
@@ -598,44 +577,44 @@ class FullBlockTest(ComparisonTestFramework):
self.tip = b46
assert 46 not in self.blocks
self.blocks[46] = b46
- yield self.rejected(RejectResult(16, b'bad-blk-length'))
+ self.sync_blocks([b46], False, 16, b'bad-blk-length', reconnect=True)
self.log.info("Reject a block with invalid work")
self.move_tip(44)
b47 = self.next_block(47, solve=False)
target = uint256_from_compact(b47.nBits)
- while b47.sha256 < target: # changed > to <
+ while b47.sha256 < target:
b47.nNonce += 1
b47.rehash()
- yield self.rejected(RejectResult(16, b'high-hash'))
+ self.sync_blocks([b47], False, request_block=False)
self.log.info("Reject a block with a timestamp >2 hours in the future")
self.move_tip(44)
b48 = self.next_block(48, solve=False)
b48.nTime = int(time.time()) + 60 * 60 * 3
b48.solve()
- yield self.rejected(RejectResult(16, b'time-too-new'))
+ self.sync_blocks([b48], False, request_block=False)
self.log.info("Reject a block with invalid merkle hash")
self.move_tip(44)
b49 = self.next_block(49)
b49.hashMerkleRoot += 1
b49.solve()
- yield self.rejected(RejectResult(16, b'bad-txnmrklroot'))
+ self.sync_blocks([b49], False, 16, b'bad-txnmrklroot', reconnect=True)
self.log.info("Reject a block with incorrect POW limit")
self.move_tip(44)
b50 = self.next_block(50)
b50.nBits = b50.nBits - 1
b50.solve()
- yield self.rejected(RejectResult(16, b'bad-diffbits'))
+ self.sync_blocks([b50], False, request_block=False, reconnect=True)
self.log.info("Reject a block with two coinbase transactions")
self.move_tip(44)
- self.next_block(51)
+ b51 = self.next_block(51)
cb2 = create_coinbase(51, self.coinbase_pubkey)
- self.update_block(51, [cb2])
- yield self.rejected(RejectResult(16, b'bad-cb-multiple'))
+ b51 = self.update_block(51, [cb2])
+ self.sync_blocks([b51], False, 16, b'bad-cb-multiple', reconnect=True)
self.log.info("Reject a block with duplicate transactions")
# Note: txns have to be in the right position in the merkle tree to trigger this error
@@ -643,32 +622,32 @@ class FullBlockTest(ComparisonTestFramework):
b52 = self.next_block(52, spend=out[15])
tx = self.create_tx(b52.vtx[1], 0, 1)
b52 = self.update_block(52, [tx, tx])
- yield self.rejected(RejectResult(16, b'bad-txns-duplicate'))
+ self.sync_blocks([b52], False, 16, b'bad-txns-duplicate', reconnect=True)
# Test block timestamps
# -> b31 (8) -> b33 (9) -> b35 (10) -> b39 (11) -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15)
# \-> b54 (15)
#
self.move_tip(43)
- self.next_block(53, spend=out[14])
- yield self.rejected() # rejected since b44 is at same height
+ b53 = self.next_block(53, spend=out[14])
+ self.sync_blocks([b53], False)
self.save_spendable_output()
self.log.info("Reject a block with timestamp before MedianTimePast")
b54 = self.next_block(54, spend=out[15])
b54.nTime = b35.nTime - 1
b54.solve()
- yield self.rejected(RejectResult(16, b'time-too-old'))
+ self.sync_blocks([b54], False, request_block=False)
# valid timestamp
self.move_tip(53)
b55 = self.next_block(55, spend=out[15])
b55.nTime = b35.nTime
self.update_block(55, [])
- yield self.accepted()
+ self.sync_blocks([b55], True)
self.save_spendable_output()
- # Test CVE-2012-2459
+ # Test Merkle tree malleability
#
# -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) -> b57p2 (16)
# \-> b57 (16)
@@ -710,7 +689,7 @@ class FullBlockTest(ComparisonTestFramework):
assert_equal(len(b56.vtx), 3)
b56 = self.update_block(56, [tx1])
assert_equal(b56.hash, b57.hash)
- yield self.rejected(RejectResult(16, b'bad-txns-duplicate'))
+ self.sync_blocks([b56], False, 16, b'bad-txns-duplicate', reconnect=True)
# b57p2 - a good block with 6 tx'es, don't submit until end
self.move_tip(55)
@@ -730,13 +709,13 @@ class FullBlockTest(ComparisonTestFramework):
assert_equal(b56p2.hash, b57p2.hash)
assert_equal(len(b56p2.vtx), 6)
b56p2 = self.update_block("b56p2", [tx3, tx4])
- yield self.rejected(RejectResult(16, b'bad-txns-duplicate'))
+ self.sync_blocks([b56p2], False, 16, b'bad-txns-duplicate', reconnect=True)
self.move_tip("57p2")
- yield self.accepted()
+ self.sync_blocks([b57p2], True)
self.move_tip(57)
- yield self.rejected() # rejected because 57p2 seen first
+ self.sync_blocks([b57], False) # The tip is not updated because 57p2 seen first
self.save_spendable_output()
# Test a few invalid tx types
@@ -748,27 +727,27 @@ class FullBlockTest(ComparisonTestFramework):
# tx with prevout.n out of range
self.log.info("Reject a block with a transaction with prevout.n out of range")
self.move_tip(57)
- self.next_block(58, spend=out[17])
+ b58 = self.next_block(58, spend=out[17])
tx = CTransaction()
assert(len(out[17].tx.vout) < 42)
tx.vin.append(CTxIn(COutPoint(out[17].tx.sha256, 42), CScript([OP_TRUE]), 0xffffffff))
tx.vout.append(CTxOut(0, b""))
tx.calc_sha256()
- self.update_block(58, [tx])
- yield self.rejected(RejectResult(16, b'bad-txns-inputs-missingorspent'))
+ b58 = self.update_block(58, [tx])
+ self.sync_blocks([b58], False, 16, b'bad-txns-inputs-missingorspent', reconnect=True)
- # tx with output value > input value out of range
+ # tx with output value > input value
self.log.info("Reject a block with a transaction with outputs > inputs")
self.move_tip(57)
- self.next_block(59)
+ b59 = self.next_block(59)
tx = self.create_and_sign_transaction(out[17].tx, out[17].n, 51 * COIN)
- self.update_block(59, [tx])
- yield self.rejected(RejectResult(16, b'bad-txns-in-belowout'))
+ b59 = self.update_block(59, [tx])
+ self.sync_blocks([b59], False, 16, b'bad-txns-in-belowout', reconnect=True)
# reset to good chain
self.move_tip(57)
b60 = self.next_block(60, spend=out[17])
- yield self.accepted()
+ self.sync_blocks([b60], True)
self.save_spendable_output()
# Test BIP30
@@ -783,11 +762,11 @@ class FullBlockTest(ComparisonTestFramework):
self.log.info("Reject a block with a transaction with a duplicate hash of a previous transaction (BIP30)")
self.move_tip(60)
b61 = self.next_block(61, spend=out[18])
- b61.vtx[0].vin[0].scriptSig = b60.vtx[0].vin[0].scriptSig # equalize the coinbases
+ b61.vtx[0].vin[0].scriptSig = b60.vtx[0].vin[0].scriptSig # Equalize the coinbases
b61.vtx[0].rehash()
b61 = self.update_block(61, [])
assert_equal(b60.vtx[0].serialize(), b61.vtx[0].serialize())
- yield self.rejected(RejectResult(16, b'bad-txns-BIP30'))
+ self.sync_blocks([b61], False, 16, b'bad-txns-BIP30', reconnect=True)
# Test tx.isFinal is properly rejected (not an exhaustive tx.isFinal test, that should be in data-driven transaction tests)
#
@@ -796,7 +775,7 @@ class FullBlockTest(ComparisonTestFramework):
#
self.log.info("Reject a block with a transaction with a nonfinal locktime")
self.move_tip(60)
- self.next_block(62)
+ b62 = self.next_block(62)
tx = CTransaction()
tx.nLockTime = 0xffffffff # this locktime is non-final
assert(out[18].n < len(out[18].tx.vout))
@@ -804,8 +783,8 @@ class FullBlockTest(ComparisonTestFramework):
tx.vout.append(CTxOut(0, CScript([OP_TRUE])))
assert(tx.vin[0].nSequence < 0xffffffff)
tx.calc_sha256()
- self.update_block(62, [tx])
- yield self.rejected(RejectResult(16, b'bad-txns-nonfinal'))
+ b62 = self.update_block(62, [tx])
+ self.sync_blocks([b62], False, 16, b'bad-txns-nonfinal')
# Test a non-final coinbase is also rejected
#
@@ -819,7 +798,7 @@ class FullBlockTest(ComparisonTestFramework):
b63.vtx[0].vin[0].nSequence = 0xDEADBEEF
b63.vtx[0].rehash()
b63 = self.update_block(63, [])
- yield self.rejected(RejectResult(16, b'bad-txns-nonfinal'))
+ self.sync_blocks([b63], False, 16, b'bad-txns-nonfinal')
# This checks that a block with a bloated VARINT between the block_header and the array of tx such that
# the block is > MAX_BLOCK_BASE_SIZE with the bloated varint, but <= MAX_BLOCK_BASE_SIZE without the bloated varint,
@@ -853,10 +832,14 @@ class FullBlockTest(ComparisonTestFramework):
tx.vin.append(CTxIn(COutPoint(b64a.vtx[1].sha256, 0)))
b64a = self.update_block("64a", [tx])
assert_equal(len(b64a.serialize()), MAX_BLOCK_BASE_SIZE + 8)
- yield TestInstance([[self.tip, None]])
+ self.sync_blocks([b64a], False, 1, b'error parsing message')
- # comptool workaround: to make sure b64 is delivered, manually erase b64a from blockstore
- self.test.block_store.erase(b64a.sha256)
+ # bitcoind doesn't disconnect us for sending a bloated block, but if we subsequently
+ # resend the header message, it won't send us the getdata message again. Just
+ # disconnect and reconnect and then call sync_blocks.
+ # TODO: improve this test to be less dependent on P2P DOS behaviour.
+ node.disconnect_p2ps()
+ self.reconnect_p2p()
self.move_tip(60)
b64 = CBlock(b64a)
@@ -864,8 +847,8 @@ class FullBlockTest(ComparisonTestFramework):
assert_equal(b64.hash, b64a.hash)
assert_equal(len(b64.serialize()), MAX_BLOCK_BASE_SIZE)
self.blocks[64] = b64
- self.update_block(64, [])
- yield self.accepted()
+ b64 = self.update_block(64, [])
+ self.sync_blocks([b64], True)
self.save_spendable_output()
# Spend an output created in the block itself
@@ -874,11 +857,11 @@ class FullBlockTest(ComparisonTestFramework):
#
self.log.info("Accept a block with a transaction spending an output created in the same block")
self.move_tip(64)
- self.next_block(65)
+ b65 = self.next_block(65)
tx1 = self.create_and_sign_transaction(out[19].tx, out[19].n, out[19].tx.vout[0].nValue)
tx2 = self.create_and_sign_transaction(tx1, 0, 0)
- self.update_block(65, [tx1, tx2])
- yield self.accepted()
+ b65 = self.update_block(65, [tx1, tx2])
+ self.sync_blocks([b65], True)
self.save_spendable_output()
# Attempt to spend an output created later in the same block
@@ -887,11 +870,11 @@ class FullBlockTest(ComparisonTestFramework):
# \-> b66 (20)
self.log.info("Reject a block with a transaction spending an output created later in the same block")
self.move_tip(65)
- self.next_block(66)
+ b66 = self.next_block(66)
tx1 = self.create_and_sign_transaction(out[20].tx, out[20].n, out[20].tx.vout[0].nValue)
tx2 = self.create_and_sign_transaction(tx1, 0, 1)
- self.update_block(66, [tx2, tx1])
- yield self.rejected(RejectResult(16, b'bad-txns-inputs-missingorspent'))
+ b66 = self.update_block(66, [tx2, tx1])
+ self.sync_blocks([b66], False, 16, b'bad-txns-inputs-missingorspent', reconnect=True)
# Attempt to double-spend a transaction created in a block
#
@@ -901,12 +884,12 @@ class FullBlockTest(ComparisonTestFramework):
#
self.log.info("Reject a block with a transaction double spending a transaction creted in the same block")
self.move_tip(65)
- self.next_block(67)
+ b67 = self.next_block(67)
tx1 = self.create_and_sign_transaction(out[20].tx, out[20].n, out[20].tx.vout[0].nValue)
tx2 = self.create_and_sign_transaction(tx1, 0, 1)
tx3 = self.create_and_sign_transaction(tx1, 0, 2)
- self.update_block(67, [tx1, tx2, tx3])
- yield self.rejected(RejectResult(16, b'bad-txns-inputs-missingorspent'))
+ b67 = self.update_block(67, [tx1, tx2, tx3])
+ self.sync_blocks([b67], False, 16, b'bad-txns-inputs-missingorspent', reconnect=True)
# More tests of block subsidy
#
@@ -922,17 +905,17 @@ class FullBlockTest(ComparisonTestFramework):
#
self.log.info("Reject a block trying to claim too much subsidy in the coinbase transaction")
self.move_tip(65)
- self.next_block(68, additional_coinbase_value=10)
+ b68 = self.next_block(68, additional_coinbase_value=10)
tx = self.create_and_sign_transaction(out[20].tx, out[20].n, out[20].tx.vout[0].nValue - 9)
- self.update_block(68, [tx])
- yield self.rejected(RejectResult(16, b'bad-cb-amount'))
+ b68 = self.update_block(68, [tx])
+ self.sync_blocks([b68], False, 16, b'bad-cb-amount', reconnect=True)
self.log.info("Accept a block claiming the correct subsidy in the coinbase transaction")
self.move_tip(65)
b69 = self.next_block(69, additional_coinbase_value=10)
tx = self.create_and_sign_transaction(out[20].tx, out[20].n, out[20].tx.vout[0].nValue - 10)
self.update_block(69, [tx])
- yield self.accepted()
+ self.sync_blocks([b69], True)
self.save_spendable_output()
# Test spending the outpoint of a non-existent transaction
@@ -942,14 +925,14 @@ class FullBlockTest(ComparisonTestFramework):
#
self.log.info("Reject a block containing a transaction spending from a non-existent input")
self.move_tip(69)
- self.next_block(70, spend=out[21])
+ b70 = self.next_block(70, spend=out[21])
bogus_tx = CTransaction()
bogus_tx.sha256 = uint256_from_str(b"23c70ed7c0506e9178fc1a987f40a33946d4ad4c962b5ae3a52546da53af0c5c")
tx = CTransaction()
tx.vin.append(CTxIn(COutPoint(bogus_tx.sha256, 0), b"", 0xffffffff))
tx.vout.append(CTxOut(1, b""))
- self.update_block(70, [tx])
- yield self.rejected(RejectResult(16, b'bad-txns-inputs-missingorspent'))
+ b70 = self.update_block(70, [tx])
+ self.sync_blocks([b70], False, 16, b'bad-txns-inputs-missingorspent', reconnect=True)
# Test accepting an invalid block which has the same hash as a valid one (via merkle tree tricks)
#
@@ -957,7 +940,7 @@ class FullBlockTest(ComparisonTestFramework):
# \-> b71 (21)
#
# b72 is a good block.
- # b71 is a copy of 72, but re-adds one of its transactions. However, it has the same hash as b71.
+ # b71 is a copy of 72, but re-adds one of its transactions. However, it has the same hash as b72.
self.log.info("Reject a block containing a duplicate transaction but with the same Merkle root (Merkle tree malleability")
self.move_tip(69)
b72 = self.next_block(72)
@@ -974,9 +957,10 @@ class FullBlockTest(ComparisonTestFramework):
assert_equal(b72.sha256, b71.sha256)
self.move_tip(71)
- yield self.rejected(RejectResult(16, b'bad-txns-duplicate'))
+ self.sync_blocks([b71], False, 16, b'bad-txns-duplicate', reconnect=True)
+
self.move_tip(72)
- yield self.accepted()
+ self.sync_blocks([b72], True)
self.save_spendable_output()
# Test some invalid scripts and MAX_BLOCK_SIGOPS
@@ -1011,7 +995,7 @@ class FullBlockTest(ComparisonTestFramework):
tx = self.create_and_sign_transaction(out[22].tx, 0, 1, CScript(a))
b73 = self.update_block(73, [tx])
assert_equal(get_legacy_sigopcount_block(b73), MAX_BLOCK_SIGOPS + 1)
- yield self.rejected(RejectResult(16, b'bad-blk-sigops'))
+ self.sync_blocks([b73], False, 16, b'bad-blk-sigops', reconnect=True)
# b74/75 - if we push an invalid script element, all prevous sigops are counted,
# but sigops after the element are not counted.
@@ -1025,7 +1009,7 @@ class FullBlockTest(ComparisonTestFramework):
# b75 succeeds because we put MAX_BLOCK_SIGOPS before the element
self.log.info("Check sigops are counted correctly after an invalid script element")
self.move_tip(72)
- self.next_block(74)
+ b74 = self.next_block(74)
size = MAX_BLOCK_SIGOPS - 1 + MAX_SCRIPT_ELEMENT_SIZE + 42 # total = 20,561
a = bytearray([OP_CHECKSIG] * size)
a[MAX_BLOCK_SIGOPS] = 0x4e
@@ -1034,11 +1018,11 @@ class FullBlockTest(ComparisonTestFramework):
a[MAX_BLOCK_SIGOPS + 3] = 0xff
a[MAX_BLOCK_SIGOPS + 4] = 0xff
tx = self.create_and_sign_transaction(out[22].tx, 0, 1, CScript(a))
- self.update_block(74, [tx])
- yield self.rejected(RejectResult(16, b'bad-blk-sigops'))
+ b74 = self.update_block(74, [tx])
+ self.sync_blocks([b74], False, 16, b'bad-blk-sigops', reconnect=True)
self.move_tip(72)
- self.next_block(75)
+ b75 = self.next_block(75)
size = MAX_BLOCK_SIGOPS - 1 + MAX_SCRIPT_ELEMENT_SIZE + 42
a = bytearray([OP_CHECKSIG] * size)
a[MAX_BLOCK_SIGOPS - 1] = 0x4e
@@ -1047,19 +1031,19 @@ class FullBlockTest(ComparisonTestFramework):
a[MAX_BLOCK_SIGOPS + 2] = 0xff
a[MAX_BLOCK_SIGOPS + 3] = 0xff
tx = self.create_and_sign_transaction(out[22].tx, 0, 1, CScript(a))
- self.update_block(75, [tx])
- yield self.accepted()
+ b75 = self.update_block(75, [tx])
+ self.sync_blocks([b75], True)
self.save_spendable_output()
# Check that if we push an element filled with CHECKSIGs, they are not counted
self.move_tip(75)
- self.next_block(76)
+ b76 = self.next_block(76)
size = MAX_BLOCK_SIGOPS - 1 + MAX_SCRIPT_ELEMENT_SIZE + 1 + 5
a = bytearray([OP_CHECKSIG] * size)
a[MAX_BLOCK_SIGOPS - 1] = 0x4e # PUSHDATA4, but leave the following bytes as just checksigs
tx = self.create_and_sign_transaction(out[23].tx, 0, 1, CScript(a))
- self.update_block(76, [tx])
- yield self.accepted()
+ b76 = self.update_block(76, [tx])
+ self.sync_blocks([b76], True)
self.save_spendable_output()
# Test transaction resurrection
@@ -1081,36 +1065,36 @@ class FullBlockTest(ComparisonTestFramework):
# updated. (Perhaps to spend to a P2SH OP_TRUE script)
self.log.info("Test transaction resurrection during a re-org")
self.move_tip(76)
- self.next_block(77)
+ b77 = self.next_block(77)
tx77 = self.create_and_sign_transaction(out[24].tx, out[24].n, 10 * COIN)
- self.update_block(77, [tx77])
- yield self.accepted()
+ b77 = self.update_block(77, [tx77])
+ self.sync_blocks([b77], True)
self.save_spendable_output()
- self.next_block(78)
+ b78 = self.next_block(78)
tx78 = self.create_tx(tx77, 0, 9 * COIN)
- self.update_block(78, [tx78])
- yield self.accepted()
+ b78 = self.update_block(78, [tx78])
+ self.sync_blocks([b78], True)
- self.next_block(79)
+ b79 = self.next_block(79)
tx79 = self.create_tx(tx78, 0, 8 * COIN)
- self.update_block(79, [tx79])
- yield self.accepted()
+ b79 = self.update_block(79, [tx79])
+ self.sync_blocks([b79], True)
# mempool should be empty
assert_equal(len(self.nodes[0].getrawmempool()), 0)
self.move_tip(77)
- self.next_block(80, spend=out[25])
- yield self.rejected()
+ b80 = self.next_block(80, spend=out[25])
+ self.sync_blocks([b80], False, request_block=False)
self.save_spendable_output()
- self.next_block(81, spend=out[26])
- yield self.rejected() # other chain is same length
+ b81 = self.next_block(81, spend=out[26])
+ self.sync_blocks([b81], False, request_block=False) # other chain is same length
self.save_spendable_output()
- self.next_block(82, spend=out[27])
- yield self.accepted() # now this chain is longer, triggers re-org
+ b82 = self.next_block(82, spend=out[27])
+ self.sync_blocks([b82], True) # now this chain is longer, triggers re-org
self.save_spendable_output()
# now check that tx78 and tx79 have been put back into the peer's mempool
@@ -1124,7 +1108,7 @@ class FullBlockTest(ComparisonTestFramework):
# -> b81 (26) -> b82 (27) -> b83 (28)
#
self.log.info("Accept a block with invalid opcodes in dead execution paths")
- self.next_block(83)
+ b83 = self.next_block(83)
op_codes = [OP_IF, OP_INVALIDOPCODE, OP_ELSE, OP_TRUE, OP_ENDIF]
script = CScript(op_codes)
tx1 = self.create_and_sign_transaction(out[28].tx, out[28].n, out[28].tx.vout[0].nValue, script)
@@ -1133,8 +1117,8 @@ class FullBlockTest(ComparisonTestFramework):
tx2.vin[0].scriptSig = CScript([OP_FALSE])
tx2.rehash()
- self.update_block(83, [tx1, tx2])
- yield self.accepted()
+ b83 = self.update_block(83, [tx1, tx2])
+ self.sync_blocks([b83], True)
self.save_spendable_output()
# Reorg on/off blocks that have OP_RETURN in them (and try to spend them)
@@ -1143,7 +1127,7 @@ class FullBlockTest(ComparisonTestFramework):
# \-> b85 (29) -> b86 (30) \-> b89a (32)
#
self.log.info("Test re-orging blocks with OP_RETURN in them")
- self.next_block(84)
+ b84 = self.next_block(84)
tx1 = self.create_tx(out[29].tx, out[29].n, 0, CScript([OP_RETURN]))
tx1.vout.append(CTxOut(0, CScript([OP_TRUE])))
tx1.vout.append(CTxOut(0, CScript([OP_TRUE])))
@@ -1160,37 +1144,37 @@ class FullBlockTest(ComparisonTestFramework):
tx4.vout.append(CTxOut(0, CScript([OP_RETURN])))
tx5 = self.create_tx(tx1, 4, 0, CScript([OP_RETURN]))
- self.update_block(84, [tx1, tx2, tx3, tx4, tx5])
- yield self.accepted()
+ b84 = self.update_block(84, [tx1, tx2, tx3, tx4, tx5])
+ self.sync_blocks([b84], True)
self.save_spendable_output()
self.move_tip(83)
- self.next_block(85, spend=out[29])
- yield self.rejected()
+ b85 = self.next_block(85, spend=out[29])
+ self.sync_blocks([b85], False) # other chain is same length
- self.next_block(86, spend=out[30])
- yield self.accepted()
+ b86 = self.next_block(86, spend=out[30])
+ self.sync_blocks([b86], True)
self.move_tip(84)
- self.next_block(87, spend=out[30])
- yield self.rejected()
+ b87 = self.next_block(87, spend=out[30])
+ self.sync_blocks([b87], False) # other chain is same length
self.save_spendable_output()
- self.next_block(88, spend=out[31])
- yield self.accepted()
+ b88 = self.next_block(88, spend=out[31])
+ self.sync_blocks([b88], True)
self.save_spendable_output()
# trying to spend the OP_RETURN output is rejected
- self.next_block("89a", spend=out[32])
+ b89a = self.next_block("89a", spend=out[32])
tx = self.create_tx(tx1, 0, 0, CScript([OP_TRUE]))
- self.update_block("89a", [tx])
- yield self.rejected()
+ b89a = self.update_block("89a", [tx])
+ self.sync_blocks([b89a], False, 16, b'bad-txns-inputs-missingorspent', reconnect=True)
self.log.info("Test a re-org of one week's worth of blocks (1088 blocks)")
self.move_tip(88)
LARGE_REORG_SIZE = 1088
- test1 = TestInstance(sync_every_block=False)
+ blocks = []
spend = out[32]
for i in range(89, LARGE_REORG_SIZE + 89):
b = self.next_block(i, spend)
@@ -1201,33 +1185,30 @@ class FullBlockTest(ComparisonTestFramework):
tx.vin.append(CTxIn(COutPoint(b.vtx[1].sha256, 0)))
b = self.update_block(i, [tx])
assert_equal(len(b.serialize()), MAX_BLOCK_BASE_SIZE)
- test1.blocks_and_transactions.append([self.tip, True])
+ blocks.append(b)
self.save_spendable_output()
spend = self.get_spendable_output()
- yield test1
+ self.sync_blocks(blocks, True, timeout=180)
chain1_tip = i
# now create alt chain of same length
self.move_tip(88)
- test2 = TestInstance(sync_every_block=False)
+ blocks2 = []
for i in range(89, LARGE_REORG_SIZE + 89):
- self.next_block("alt" + str(i))
- test2.blocks_and_transactions.append([self.tip, False])
- yield test2
+ blocks2.append(self.next_block("alt" + str(i)))
+ self.sync_blocks(blocks2, False, request_block=False)
# extend alt chain to trigger re-org
- self.next_block("alt" + str(chain1_tip + 1))
- yield self.accepted()
+ block = self.next_block("alt" + str(chain1_tip + 1))
+ self.sync_blocks([block], True, timeout=180)
# ... and re-org back to the first chain
self.move_tip(chain1_tip)
- self.next_block(chain1_tip + 1)
- yield self.rejected()
- self.next_block(chain1_tip + 2)
- yield self.accepted()
-
- chain1_tip += 2
+ block = self.next_block(chain1_tip + 1)
+ self.sync_blocks([block], False, request_block=False)
+ block = self.next_block(chain1_tip + 2)
+ self.sync_blocks([block], True, timeout=180)
# Helper methods
################
@@ -1238,8 +1219,7 @@ class FullBlockTest(ComparisonTestFramework):
# this is a little handier to use than the version in blocktools.py
def create_tx(self, spend_tx, n, value, script=CScript([OP_TRUE])):
- tx = create_transaction(spend_tx, n, b"", value, script)
- return tx
+ return create_transaction(spend_tx, n, b"", value, script)
# sign a transaction, using the key we know about
# this signs input 0 in tx, which is assumed to be spending output n in spend_tx
@@ -1289,23 +1269,14 @@ class FullBlockTest(ComparisonTestFramework):
# save the current tip so it can be spent by a later block
def save_spendable_output(self):
+ self.log.debug("saving spendable output %s" % self.tip.vtx[0])
self.spendable_outputs.append(self.tip)
# get an output that we previously marked as spendable
def get_spendable_output(self):
+ self.log.debug("getting spendable output %s" % self.spendable_outputs[0].vtx[0])
return PreviousSpendableOutput(self.spendable_outputs.pop(0).vtx[0], 0)
- # returns a test case that asserts that the current tip was accepted
- def accepted(self):
- return TestInstance([[self.tip, True]])
-
- # returns a test case that asserts that the current tip was rejected
- def rejected(self, reject=None):
- if reject is None:
- return TestInstance([[self.tip, False]])
- else:
- return TestInstance([[self.tip, reject]])
-
# move the tip back to a previous block
def move_tip(self, number):
self.tip = self.blocks[number]
@@ -1325,6 +1296,26 @@ class FullBlockTest(ComparisonTestFramework):
self.blocks[block_number] = block
return block
+ def reconnect_p2p(self):
+ """Add a P2P connection to the node.
+
+ The node gets disconnected several times in this test. This helper
+ method reconnects the p2p and restarts the network thread."""
+
+ network_thread_join()
+ self.nodes[0].disconnect_p2ps()
+ self.nodes[0].add_p2p_connection(P2PDataStore())
+ network_thread_start()
+ self.nodes[0].p2p.wait_for_verack()
+
+ def sync_blocks(self, blocks, success=True, reject_code=None, reject_reason=None, request_block=True, reconnect=False, timeout=60):
+ """Sends blocks to test node. Syncs and verifies that tip has advanced to most recent block.
+
+ Call with success = False if the tip shouldn't advance to the most recent block."""
+ self.nodes[0].p2p.send_blocks_and_test(blocks, self.nodes[0], success=success, reject_code=reject_code, reject_reason=reject_reason, request_block=request_block, timeout=timeout)
+
+ if reconnect:
+ self.reconnect_p2p()
if __name__ == '__main__':
FullBlockTest().main()