Changeset View
Changeset View
Standalone View
Standalone View
test/functional/bip68-112-113-p2p.py
#!/usr/bin/env python3 | #!/usr/bin/env python3 | ||||
# Copyright (c) 2015-2016 The Bitcoin Core developers | # Copyright (c) 2015-2016 The Bitcoin Core developers | ||||
# Distributed under the MIT software license, see the accompanying | # Distributed under the MIT software license, see the accompanying | ||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php. | # file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
"""Test activation of the first version bits soft fork. | """Test activation of the first version bits soft fork. | ||||
This soft fork will activate the following BIPS: | This soft fork will activate the following BIPS: | ||||
BIP 68 - nSequence relative lock times | BIP 68 - nSequence relative lock times | ||||
BIP 112 - CHECKSEQUENCEVERIFY | BIP 112 - CHECKSEQUENCEVERIFY | ||||
BIP 113 - MedianTimePast semantics for nLockTime | BIP 113 - MedianTimePast semantics for nLockTime | ||||
regtest lock-in with 108/144 block signalling | regtest lock-in with 108/144 block signalling | ||||
activation after a further 144 blocks | activation after a further 144 blocks | ||||
mine 82 blocks whose coinbases will be used to generate inputs for our tests | mine 82 blocks whose coinbases will be used to generate inputs for our tests | ||||
mine 61 blocks to transition from DEFINED to STARTED | mine 489 blocks and seed block chain with the 82 inputs will use for our tests at height 572 | ||||
mine 144 blocks only 100 of which are signaling readiness in order to fail to change state this period | |||||
mine 144 blocks with 108 signaling and verify STARTED->LOCKED_IN | |||||
mine 140 blocks and seed block chain with the 82 inputs will use for our tests at height 572 | |||||
mine 3 blocks and verify still at LOCKED_IN and test that enforcement has not triggered | mine 3 blocks and verify still at LOCKED_IN and test that enforcement has not triggered | ||||
mine 1 block and test that enforcement has triggered (which triggers ACTIVE) | mine 1 block and test that enforcement has triggered (which triggers ACTIVE) | ||||
Test BIP 113 is enforced | Test BIP 113 is enforced | ||||
Mine 4 blocks so next height is 580 and test BIP 68 is enforced for time and height | Mine 4 blocks so next height is 580 and test BIP 68 is enforced for time and height | ||||
Mine 1 block so next height is 581 and test BIP 68 now passes time but not height | Mine 1 block so next height is 581 and test BIP 68 now passes time but not height | ||||
Mine 1 block so next height is 582 and test BIP 68 now passes time and height | Mine 1 block so next height is 582 and test BIP 68 now passes time and height | ||||
Test that BIP 112 is enforced | Test that BIP 112 is enforced | ||||
▲ Show 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | def all_rlt_txs(txarray): | ||||
for b31 in range(2): | for b31 in range(2): | ||||
for b25 in range(2): | for b25 in range(2): | ||||
for b22 in range(2): | for b22 in range(2): | ||||
for b18 in range(2): | for b18 in range(2): | ||||
txs.append(txarray[b31][b25][b22][b18]) | txs.append(txarray[b31][b25][b22][b18]) | ||||
return txs | return txs | ||||
def get_csv_status(node): | |||||
softforks = node.getblockchaininfo()['softforks'] | |||||
for sf in softforks: | |||||
if sf['id'] == 'csv' and sf['version'] == 5: | |||||
return sf['reject']['status'] | |||||
raise AssertionError('Cannot find CSV fork activation informations') | |||||
class BIP68_112_113Test(ComparisonTestFramework): | class BIP68_112_113Test(ComparisonTestFramework): | ||||
def set_test_params(self): | def set_test_params(self): | ||||
self.num_nodes = 1 | self.num_nodes = 1 | ||||
self.setup_clean_chain = True | self.setup_clean_chain = True | ||||
self.extra_args = [['-whitelist=127.0.0.1', '-blockversion=4']] | self.extra_args = [['-whitelist=127.0.0.1', '-blockversion=4']] | ||||
def run_test(self): | def run_test(self): | ||||
test = TestManager(self, self.options.tmpdir) | test = TestManager(self, self.options.tmpdir) | ||||
Show All 17 Lines | class BIP68_112_113Test(ComparisonTestFramework): | ||||
def sign_transaction(self, node, unsignedtx): | def sign_transaction(self, node, unsignedtx): | ||||
rawtx = ToHex(unsignedtx) | rawtx = ToHex(unsignedtx) | ||||
signresult = node.signrawtransaction(rawtx) | signresult = node.signrawtransaction(rawtx) | ||||
tx = CTransaction() | tx = CTransaction() | ||||
f = BytesIO(hex_str_to_bytes(signresult['hex'])) | f = BytesIO(hex_str_to_bytes(signresult['hex'])) | ||||
tx.deserialize(f) | tx.deserialize(f) | ||||
return tx | return tx | ||||
def generate_blocks(self, number, version, test_blocks=[]): | def generate_blocks(self, number): | ||||
test_blocks = [] | |||||
for i in range(number): | for i in range(number): | ||||
block = self.create_test_block([], version) | block = self.create_test_block([]) | ||||
test_blocks.append([block, True]) | test_blocks.append([block, True]) | ||||
self.last_block_time += 600 | self.last_block_time += 600 | ||||
self.tip = block.sha256 | self.tip = block.sha256 | ||||
self.tipheight += 1 | self.tipheight += 1 | ||||
return test_blocks | return test_blocks | ||||
def create_test_block(self, txs, version=536870912): | def create_test_block(self, txs, version=536870912): | ||||
block = create_block(self.tip, create_coinbase( | block = create_block(self.tip, create_coinbase( | ||||
▲ Show 20 Lines • Show All 82 Lines • ▼ Show 20 Lines | def get_tests(self): | ||||
# Set time back to present so yielded blocks aren't in the future as | # Set time back to present so yielded blocks aren't in the future as | ||||
# we advance last_block_time | # we advance last_block_time | ||||
self.nodes[0].setmocktime(0) | self.nodes[0].setmocktime(0) | ||||
self.tipheight = 82 # height of the next block to build | self.tipheight = 82 # height of the next block to build | ||||
self.last_block_time = long_past_time | self.last_block_time = long_past_time | ||||
self.tip = int("0x" + self.nodes[0].getbestblockhash(), 0) | self.tip = int("0x" + self.nodes[0].getbestblockhash(), 0) | ||||
self.nodeaddress = self.nodes[0].getnewaddress() | self.nodeaddress = self.nodes[0].getnewaddress() | ||||
assert_equal(get_bip9_status(self.nodes[0], 'csv')[ | # CSV is not activated yet. | ||||
'status'], 'defined') | assert_equal(get_csv_status(self.nodes[0]), False) | ||||
test_blocks = self.generate_blocks(61, 4) | |||||
# 489 more version 4 blocks | |||||
test_blocks = self.generate_blocks(489) | |||||
yield TestInstance(test_blocks, sync_every_block=False) # 1 | yield TestInstance(test_blocks, sync_every_block=False) # 1 | ||||
# Advanced from DEFINED to STARTED, height = 143 | |||||
assert_equal(get_bip9_status(self.nodes[0], 'csv')[ | # Still not activated. | ||||
'status'], 'started') | assert_equal(get_csv_status(self.nodes[0]), False) | ||||
# Fail to achieve LOCKED_IN 100 out of 144 signal bit 0 | |||||
# using a variety of bits to simulate multiple parallel softforks | |||||
# 0x20000001 (signalling ready) | |||||
test_blocks = self.generate_blocks(50, 536870913) | |||||
# 0x00000004 (signalling not) | |||||
test_blocks = self.generate_blocks(20, 4, test_blocks) | |||||
# 0x20000101 (signalling ready) | |||||
test_blocks = self.generate_blocks(50, 536871169, test_blocks) | |||||
# 0x20010000 (signalling not) | |||||
test_blocks = self.generate_blocks(24, 536936448, test_blocks) | |||||
yield TestInstance(test_blocks, sync_every_block=False) # 2 | |||||
# Failed to advance past STARTED, height = 287 | |||||
assert_equal(get_bip9_status(self.nodes[0], 'csv')[ | |||||
'status'], 'started') | |||||
# 108 out of 144 signal bit 0 to achieve lock-in | |||||
# using a variety of bits to simulate multiple parallel softforks | |||||
# 0x20000001 (signalling ready) | |||||
test_blocks = self.generate_blocks(58, 536870913) | |||||
# 0x00000004 (signalling not) | |||||
test_blocks = self.generate_blocks(26, 4, test_blocks) | |||||
# 0x20000101 (signalling ready) | |||||
test_blocks = self.generate_blocks(50, 536871169, test_blocks) | |||||
# 0x20010000 (signalling not) | |||||
test_blocks = self.generate_blocks(10, 536936448, test_blocks) | |||||
yield TestInstance(test_blocks, sync_every_block=False) # 3 | |||||
# Advanced from STARTED to LOCKED_IN, height = 431 | |||||
assert_equal(get_bip9_status(self.nodes[0], 'csv')[ | |||||
'status'], 'locked_in') | |||||
# 140 more version 4 blocks | |||||
test_blocks = self.generate_blocks(140, 4) | |||||
yield TestInstance(test_blocks, sync_every_block=False) # 4 | |||||
# Inputs at height = 572 | # Inputs at height = 572 | ||||
# Put inputs for all tests in the chain at height 572 (tip now = 571) (time increases by 600s per block) | # Put inputs for all tests in the chain at height 572 (tip now = 571) (time increases by 600s per block) | ||||
# Note we reuse inputs for v1 and v2 txs so must test these separately | # Note we reuse inputs for v1 and v2 txs so must test these separately | ||||
# 16 normal inputs | # 16 normal inputs | ||||
bip68inputs = [] | bip68inputs = [] | ||||
for i in range(16): | for i in range(16): | ||||
bip68inputs.append(self.send_generic_input_tx( | bip68inputs.append(self.send_generic_input_tx( | ||||
Show All 27 Lines | def get_tests(self): | ||||
self.nodes[0].setmocktime(0) | self.nodes[0].setmocktime(0) | ||||
self.tip = int("0x" + inputblockhash, 0) | self.tip = int("0x" + inputblockhash, 0) | ||||
self.tipheight += 1 | self.tipheight += 1 | ||||
self.last_block_time += 600 | self.last_block_time += 600 | ||||
assert_equal(len(self.nodes[0].getblock( | assert_equal(len(self.nodes[0].getblock( | ||||
inputblockhash, True)["tx"]), 82 + 1) | inputblockhash, True)["tx"]), 82 + 1) | ||||
# 2 more version 4 blocks | # 2 more version 4 blocks | ||||
test_blocks = self.generate_blocks(2, 4) | test_blocks = self.generate_blocks(2) | ||||
yield TestInstance(test_blocks, sync_every_block=False) # 5 | yield TestInstance(test_blocks, sync_every_block=False) # 5 | ||||
# Not yet advanced to ACTIVE, height = 574 (will activate for block 576, not 575) | # Not yet advanced to ACTIVE, height = 574 (will activate for block 576, not 575) | ||||
jasonbcox: Update the comment, since ACTIVE status no longer exists. | |||||
assert_equal(get_bip9_status(self.nodes[0], 'csv')[ | assert_equal(get_csv_status(self.nodes[0]), False) | ||||
'status'], 'locked_in') | |||||
# Test both version 1 and version 2 transactions for all tests | # Test both version 1 and version 2 transactions for all tests | ||||
# BIP113 test transaction will be modified before each use to | # BIP113 test transaction will be modified before each use to | ||||
# put in appropriate block time | # put in appropriate block time | ||||
bip113tx_v1 = self.create_transaction( | bip113tx_v1 = self.create_transaction( | ||||
self.nodes[0], bip113input, self.nodeaddress, Decimal("49.98")) | self.nodes[0], bip113input, self.nodeaddress, Decimal("49.98")) | ||||
bip113tx_v1.vin[0].nSequence = 0xFFFFFFFE | bip113tx_v1.vin[0].nSequence = 0xFFFFFFFE | ||||
bip113tx_v1.nVersion = 1 | bip113tx_v1.nVersion = 1 | ||||
▲ Show 20 Lines • Show All 71 Lines • ▼ Show 20 Lines | def get_tests(self): | ||||
# try BIP 112 with seq=9 txs | # try BIP 112 with seq=9 txs | ||||
success_txs.extend(all_rlt_txs(bip112txs_vary_nSequence_9_v2)) | success_txs.extend(all_rlt_txs(bip112txs_vary_nSequence_9_v2)) | ||||
success_txs.extend(all_rlt_txs(bip112txs_vary_OP_CSV_9_v2)) | success_txs.extend(all_rlt_txs(bip112txs_vary_OP_CSV_9_v2)) | ||||
yield TestInstance([[self.create_test_block(success_txs), True]]) # 7 | yield TestInstance([[self.create_test_block(success_txs), True]]) # 7 | ||||
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) | self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) | ||||
# 1 more version 4 block to get us to height 575 so the fork should | # 1 more version 4 block to get us to height 575 so the fork should | ||||
# now be active for the next block | # now be active for the next block | ||||
test_blocks = self.generate_blocks(1, 4) | test_blocks = self.generate_blocks(1) | ||||
yield TestInstance(test_blocks, sync_every_block=False) # 8 | yield TestInstance(test_blocks, sync_every_block=False) # 8 | ||||
assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'active') | assert_equal(get_csv_status(self.nodes[0]), False) | ||||
self.nodes[0].generate(1) | |||||
assert_equal(get_csv_status(self.nodes[0]), True) | |||||
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) | |||||
################################# | ################################# | ||||
### After Soft Forks Activate ### | ### After Soft Forks Activate ### | ||||
################################# | ################################# | ||||
### BIP 113 ### | ### BIP 113 ### | ||||
# BIP 113 tests should now fail regardless of version number | # BIP 113 tests should now fail regardless of version number | ||||
# if nLockTime isn't satisfied by new rules | # if nLockTime isn't satisfied by new rules | ||||
# = MTP of prior block (not <) but < time put on current block | # = MTP of prior block (not <) but < time put on current block | ||||
Show All 14 Lines | def get_tests(self): | ||||
bip113tx_v2.nLockTime = self.last_block_time - 600 * 5 - 1 | bip113tx_v2.nLockTime = self.last_block_time - 600 * 5 - 1 | ||||
bip113signed2 = self.sign_transaction(self.nodes[0], bip113tx_v2) | bip113signed2 = self.sign_transaction(self.nodes[0], bip113tx_v2) | ||||
for bip113tx in [bip113signed1, bip113signed2]: | for bip113tx in [bip113signed1, bip113signed2]: | ||||
# 11,12 | # 11,12 | ||||
yield TestInstance([[self.create_test_block([bip113tx]), True]]) | yield TestInstance([[self.create_test_block([bip113tx]), True]]) | ||||
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) | self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) | ||||
# Next block height = 580 after 4 blocks of random version | # Next block height = 580 after 4 blocks of random version | ||||
test_blocks = self.generate_blocks(4, 1234) | test_blocks = self.generate_blocks(4) | ||||
yield TestInstance(test_blocks, sync_every_block=False) # 13 | yield TestInstance(test_blocks, sync_every_block=False) # 13 | ||||
### BIP 68 ### | ### BIP 68 ### | ||||
### Version 1 txs ### | ### Version 1 txs ### | ||||
# All still pass | # All still pass | ||||
success_txs = [] | success_txs = [] | ||||
success_txs.extend(all_rlt_txs(bip68txs_v1)) | success_txs.extend(all_rlt_txs(bip68txs_v1)) | ||||
yield TestInstance([[self.create_test_block(success_txs), True]]) # 14 | yield TestInstance([[self.create_test_block(success_txs), True]]) # 14 | ||||
Show All 22 Lines | def get_tests(self): | ||||
for b25 in range(2): | for b25 in range(2): | ||||
for b18 in range(2): | for b18 in range(2): | ||||
bip68heighttxs.append(bip68txs_v2[0][b25][0][b18]) | bip68heighttxs.append(bip68txs_v2[0][b25][0][b18]) | ||||
for tx in bip68heighttxs: | for tx in bip68heighttxs: | ||||
# 20 - 23 | # 20 - 23 | ||||
yield TestInstance([[self.create_test_block([tx]), False]]) | yield TestInstance([[self.create_test_block([tx]), False]]) | ||||
# Advance one block to 581 | # Advance one block to 581 | ||||
test_blocks = self.generate_blocks(1, 1234) | test_blocks = self.generate_blocks(1) | ||||
yield TestInstance(test_blocks, sync_every_block=False) # 24 | yield TestInstance(test_blocks, sync_every_block=False) # 24 | ||||
# Height txs should fail and time txs should now pass 9 * 600 > 10 * 512 | # Height txs should fail and time txs should now pass 9 * 600 > 10 * 512 | ||||
bip68success_txs.extend(bip68timetxs) | bip68success_txs.extend(bip68timetxs) | ||||
# 25 | # 25 | ||||
yield TestInstance([[self.create_test_block(bip68success_txs), True]]) | yield TestInstance([[self.create_test_block(bip68success_txs), True]]) | ||||
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) | self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) | ||||
for tx in bip68heighttxs: | for tx in bip68heighttxs: | ||||
# 26 - 29 | # 26 - 29 | ||||
yield TestInstance([[self.create_test_block([tx]), False]]) | yield TestInstance([[self.create_test_block([tx]), False]]) | ||||
# Advance one block to 582 | # Advance one block to 582 | ||||
test_blocks = self.generate_blocks(1, 1234) | test_blocks = self.generate_blocks(1) | ||||
yield TestInstance(test_blocks, sync_every_block=False) # 30 | yield TestInstance(test_blocks, sync_every_block=False) # 30 | ||||
# All BIP 68 txs should pass | # All BIP 68 txs should pass | ||||
bip68success_txs.extend(bip68heighttxs) | bip68success_txs.extend(bip68heighttxs) | ||||
# 31 | # 31 | ||||
yield TestInstance([[self.create_test_block(bip68success_txs), True]]) | yield TestInstance([[self.create_test_block(bip68success_txs), True]]) | ||||
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) | self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) | ||||
▲ Show 20 Lines • Show All 125 Lines • Show Last 20 Lines |
Update the comment, since ACTIVE status no longer exists.