Skip to content

Commit 929fd72

Browse files
author
MarcoFalke
committed
Merge #10695: [qa] Rewrite BIP65/BIP66 functional tests
4ccc12a [qa] Rewrite BIP66 functional tests (Suhas Daftuar) d4f0d87 [qa] Rewrite BIP65 functional tests (Suhas Daftuar) Pull request description: After 122786d, BIP65 and BIP66 activate at particular fixed heights (without regard to version numbers of blocks below those heights). Rewrite the functional tests to take this into account, and remove two tests that weren't really testing anything. Moves the rewritten functional tests out of the extended test suite, so that they run in travis regularly. Note: I discovered that the ComparisonTestFramework (which the original versions of these p2p tests were written is, has a bug that caused them to not catch obvious errors, eg if you just comment out setting the script flags for these softforks in ConnectBlock, the versions of these tests in master do not fail(!) -- will separately PR a fix for the comparison test framework). Tree-SHA512: 2108b79951f2e980854d0d14ccc0fd1810a43dd4251fd6e3b203e7f104ea55e00650bb1a60a28c2801b4249f46563a8559ac3e3cd39db220914acfed0b3b163d
2 parents 2507fd5 + 4ccc12a commit 929fd72

File tree

5 files changed

+213
-414
lines changed

5 files changed

+213
-414
lines changed

test/functional/bip65-cltv-p2p.py

Lines changed: 115 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -4,173 +4,162 @@
44
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
55
"""Test BIP65 (CHECKLOCKTIMEVERIFY).
66
7-
Connect to a single node.
8-
Mine 2 (version 3) blocks (save the coinbases for later).
9-
Generate 98 more version 3 blocks, verify the node accepts.
10-
Mine 749 version 4 blocks, verify the node accepts.
11-
Check that the new CLTV rules are not enforced on the 750th version 4 block.
12-
Check that the new CLTV rules are enforced on the 751st version 4 block.
13-
Mine 199 new version blocks.
14-
Mine 1 old-version block.
15-
Mine 1 new version block.
16-
Mine 1 old version block, see that the node rejects.
7+
Test that the CHECKLOCKTIMEVERIFY soft-fork activates at (regtest) block height
8+
1351.
179
"""
1810

19-
from test_framework.test_framework import ComparisonTestFramework
11+
from test_framework.test_framework import BitcoinTestFramework
2012
from test_framework.util import *
21-
from test_framework.mininode import CTransaction, NetworkThread
13+
from test_framework.mininode import *
2214
from test_framework.blocktools import create_coinbase, create_block
23-
from test_framework.comptool import TestInstance, TestManager
24-
from test_framework.script import CScript, OP_1NEGATE, OP_CHECKLOCKTIMEVERIFY, OP_DROP
15+
from test_framework.script import CScript, OP_1NEGATE, OP_CHECKLOCKTIMEVERIFY, OP_DROP, CScriptNum
2516
from io import BytesIO
26-
import time
17+
18+
CLTV_HEIGHT = 1351
19+
20+
# Reject codes that we might receive in this test
21+
REJECT_INVALID = 16
22+
REJECT_OBSOLETE = 17
23+
REJECT_NONSTANDARD = 64
2724

2825
def cltv_invalidate(tx):
2926
'''Modify the signature in vin 0 of the tx to fail CLTV
3027
3128
Prepends -1 CLTV DROP in the scriptSig itself.
29+
30+
TODO: test more ways that transactions using CLTV could be invalid (eg
31+
locktime requirements fail, sequence time requirements fail, etc).
3232
'''
3333
tx.vin[0].scriptSig = CScript([OP_1NEGATE, OP_CHECKLOCKTIMEVERIFY, OP_DROP] +
3434
list(CScript(tx.vin[0].scriptSig)))
3535

36-
37-
class BIP65Test(ComparisonTestFramework):
36+
def cltv_validate(node, tx, height):
37+
'''Modify the signature in vin 0 of the tx to pass CLTV
38+
Prepends <height> CLTV DROP in the scriptSig, and sets
39+
the locktime to height'''
40+
tx.vin[0].nSequence = 0
41+
tx.nLockTime = height
42+
43+
# Need to re-sign, since nSequence and nLockTime changed
44+
signed_result = node.signrawtransaction(ToHex(tx))
45+
new_tx = CTransaction()
46+
new_tx.deserialize(BytesIO(hex_str_to_bytes(signed_result['hex'])))
47+
48+
new_tx.vin[0].scriptSig = CScript([CScriptNum(height), OP_CHECKLOCKTIMEVERIFY, OP_DROP] +
49+
list(CScript(new_tx.vin[0].scriptSig)))
50+
return new_tx
51+
52+
def create_transaction(node, coinbase, to_address, amount):
53+
from_txid = node.getblock(coinbase)['tx'][0]
54+
inputs = [{ "txid" : from_txid, "vout" : 0}]
55+
outputs = { to_address : amount }
56+
rawtx = node.createrawtransaction(inputs, outputs)
57+
signresult = node.signrawtransaction(rawtx)
58+
tx = CTransaction()
59+
tx.deserialize(BytesIO(hex_str_to_bytes(signresult['hex'])))
60+
return tx
61+
62+
class BIP65Test(BitcoinTestFramework):
3863

3964
def __init__(self):
4065
super().__init__()
4166
self.num_nodes = 1
42-
self.extra_args = [['-whitelist=127.0.0.1', '-blockversion=3']]
67+
self.extra_args = [['-promiscuousmempoolflags=1', '-whitelist=127.0.0.1']]
68+
self.setup_clean_chain = True
4369

4470
def run_test(self):
45-
test = TestManager(self, self.options.tmpdir)
46-
test.add_all_connections(self.nodes)
71+
node0 = NodeConnCB()
72+
connections = []
73+
connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], node0))
74+
node0.add_connection(connections[0])
75+
4776
NetworkThread().start() # Start up network handling in another thread
48-
test.run()
49-
50-
def create_transaction(self, node, coinbase, to_address, amount):
51-
from_txid = node.getblock(coinbase)['tx'][0]
52-
inputs = [{ "txid" : from_txid, "vout" : 0}]
53-
outputs = { to_address : amount }
54-
rawtx = node.createrawtransaction(inputs, outputs)
55-
signresult = node.signrawtransaction(rawtx)
56-
tx = CTransaction()
57-
f = BytesIO(hex_str_to_bytes(signresult['hex']))
58-
tx.deserialize(f)
59-
return tx
60-
61-
def get_tests(self):
62-
63-
self.coinbase_blocks = self.nodes[0].generate(2)
64-
height = 3 # height of the next block to build
65-
self.tip = int("0x" + self.nodes[0].getbestblockhash(), 0)
77+
78+
# wait_for_verack ensures that the P2P connection is fully up.
79+
node0.wait_for_verack()
80+
81+
self.log.info("Mining %d blocks", CLTV_HEIGHT - 2)
82+
self.coinbase_blocks = self.nodes[0].generate(CLTV_HEIGHT - 2)
6683
self.nodeaddress = self.nodes[0].getnewaddress()
67-
self.last_block_time = int(time.time())
68-
69-
''' 398 more version 3 blocks '''
70-
test_blocks = []
71-
for i in range(398):
72-
block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1)
73-
block.nVersion = 3
74-
block.rehash()
75-
block.solve()
76-
test_blocks.append([block, True])
77-
self.last_block_time += 1
78-
self.tip = block.sha256
79-
height += 1
80-
yield TestInstance(test_blocks, sync_every_block=False)
81-
82-
''' Mine 749 version 4 blocks '''
83-
test_blocks = []
84-
for i in range(749):
85-
block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1)
86-
block.nVersion = 4
87-
block.rehash()
88-
block.solve()
89-
test_blocks.append([block, True])
90-
self.last_block_time += 1
91-
self.tip = block.sha256
92-
height += 1
93-
yield TestInstance(test_blocks, sync_every_block=False)
94-
95-
'''
96-
Check that the new CLTV rules are not enforced in the 750th
97-
version 3 block.
98-
'''
99-
spendtx = self.create_transaction(self.nodes[0],
100-
self.coinbase_blocks[0], self.nodeaddress, 1.0)
84+
85+
self.log.info("Test that an invalid-according-to-CLTV transaction can still appear in a block")
86+
87+
spendtx = create_transaction(self.nodes[0], self.coinbase_blocks[0],
88+
self.nodeaddress, 1.0)
10189
cltv_invalidate(spendtx)
10290
spendtx.rehash()
10391

104-
block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1)
105-
block.nVersion = 4
92+
tip = self.nodes[0].getbestblockhash()
93+
block_time = self.nodes[0].getblockheader(tip)['mediantime'] + 1
94+
block = create_block(int(tip, 16), create_coinbase(CLTV_HEIGHT - 1), block_time)
95+
block.nVersion = 3
10696
block.vtx.append(spendtx)
10797
block.hashMerkleRoot = block.calc_merkle_root()
108-
block.rehash()
10998
block.solve()
11099

111-
self.last_block_time += 1
112-
self.tip = block.sha256
113-
height += 1
114-
yield TestInstance([[block, True]])
115-
116-
''' Mine 199 new version blocks on last valid tip '''
117-
test_blocks = []
118-
for i in range(199):
119-
block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1)
120-
block.nVersion = 4
121-
block.rehash()
122-
block.solve()
123-
test_blocks.append([block, True])
124-
self.last_block_time += 1
125-
self.tip = block.sha256
126-
height += 1
127-
yield TestInstance(test_blocks, sync_every_block=False)
128-
129-
''' Mine 1 old version block '''
130-
block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1)
100+
node0.send_and_ping(msg_block(block))
101+
assert_equal(self.nodes[0].getbestblockhash(), block.hash)
102+
103+
self.log.info("Test that blocks must now be at least version 4")
104+
tip = block.sha256
105+
block_time += 1
106+
block = create_block(tip, create_coinbase(CLTV_HEIGHT), block_time)
131107
block.nVersion = 3
132-
block.rehash()
133108
block.solve()
134-
self.last_block_time += 1
135-
self.tip = block.sha256
136-
height += 1
137-
yield TestInstance([[block, True]])
109+
node0.send_and_ping(msg_block(block))
110+
assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)
138111

139-
''' Mine 1 new version block '''
140-
block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1)
112+
assert wait_until(lambda: "reject" in node0.last_message.keys())
113+
with mininode_lock:
114+
assert_equal(node0.last_message["reject"].code, REJECT_OBSOLETE)
115+
assert_equal(node0.last_message["reject"].reason, b'bad-version(0x00000003)')
116+
assert_equal(node0.last_message["reject"].data, block.sha256)
117+
del node0.last_message["reject"]
118+
119+
self.log.info("Test that invalid-according-to-cltv transactions cannot appear in a block")
141120
block.nVersion = 4
142-
block.rehash()
143-
block.solve()
144-
self.last_block_time += 1
145-
self.tip = block.sha256
146-
height += 1
147-
yield TestInstance([[block, True]])
148-
149-
'''
150-
Check that the new CLTV rules are enforced in the 951st version 4
151-
block.
152-
'''
153-
spendtx = self.create_transaction(self.nodes[0],
154-
self.coinbase_blocks[1], self.nodeaddress, 1.0)
121+
122+
spendtx = create_transaction(self.nodes[0], self.coinbase_blocks[1],
123+
self.nodeaddress, 1.0)
155124
cltv_invalidate(spendtx)
156125
spendtx.rehash()
157126

158-
block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1)
159-
block.nVersion = 4
127+
# First we show that this tx is valid except for CLTV by getting it
128+
# accepted to the mempool (which we can achieve with
129+
# -promiscuousmempoolflags).
130+
node0.send_and_ping(msg_tx(spendtx))
131+
assert spendtx.hash in self.nodes[0].getrawmempool()
132+
133+
# Now we verify that a block with this transaction is invalid.
160134
block.vtx.append(spendtx)
161135
block.hashMerkleRoot = block.calc_merkle_root()
162-
block.rehash()
163136
block.solve()
164-
self.last_block_time += 1
165-
yield TestInstance([[block, False]])
166137

167-
''' Mine 1 old version block, should be invalid '''
168-
block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1)
169-
block.nVersion = 3
170-
block.rehash()
138+
node0.send_and_ping(msg_block(block))
139+
assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)
140+
141+
assert wait_until (lambda: "reject" in node0.last_message.keys())
142+
with mininode_lock:
143+
assert node0.last_message["reject"].code in [REJECT_INVALID, REJECT_NONSTANDARD]
144+
assert_equal(node0.last_message["reject"].data, block.sha256)
145+
if node0.last_message["reject"].code == REJECT_INVALID:
146+
# Generic rejection when a block is invalid
147+
assert_equal(node0.last_message["reject"].reason, b'block-validation-failed')
148+
else:
149+
assert b'Negative locktime' in node0.last_message["reject"].reason
150+
151+
self.log.info("Test that a version 4 block with a valid-according-to-CLTV transaction is accepted")
152+
spendtx = cltv_validate(self.nodes[0], spendtx, CLTV_HEIGHT - 1)
153+
spendtx.rehash()
154+
155+
block.vtx.pop(1)
156+
block.vtx.append(spendtx)
157+
block.hashMerkleRoot = block.calc_merkle_root()
171158
block.solve()
172-
self.last_block_time += 1
173-
yield TestInstance([[block, False]])
159+
160+
node0.send_and_ping(msg_block(block))
161+
assert_equal(int(self.nodes[0].getbestblockhash(), 16), block.sha256)
162+
174163

175164
if __name__ == '__main__':
176165
BIP65Test().main()

test/functional/bip65-cltv.py

Lines changed: 0 additions & 82 deletions
This file was deleted.

0 commit comments

Comments
 (0)