Skip to content

Commit fa091b0

Browse files
author
MarcoFalke
committed
qa: Add tests for submitheader
1 parent 36b1b63 commit fa091b0

File tree

1 file changed

+74
-5
lines changed

1 file changed

+74
-5
lines changed

test/functional/mining_basic.py

Lines changed: 74 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,23 @@
99
- submitblock"""
1010

1111
import copy
12-
from binascii import b2a_hex
1312
from decimal import Decimal
1413

1514
from test_framework.blocktools import create_coinbase
16-
from test_framework.messages import CBlock
15+
from test_framework.messages import (
16+
CBlock,
17+
CBlockHeader,
18+
)
19+
from test_framework.mininode import (
20+
P2PDataStore,
21+
)
1722
from test_framework.test_framework import BitcoinTestFramework
18-
from test_framework.util import assert_equal, assert_raises_rpc_error
23+
from test_framework.util import (
24+
assert_equal,
25+
assert_raises_rpc_error,
26+
bytes_to_hex_str as b2x,
27+
)
1928

20-
def b2x(b):
21-
return b2a_hex(b).decode('ascii')
2229

2330
def assert_template(node, block, expect, rehash=True):
2431
if rehash:
@@ -131,5 +138,67 @@ def run_test(self):
131138
bad_block.hashPrevBlock = 123
132139
assert_template(node, bad_block, 'inconclusive-not-best-prevblk')
133140

141+
self.log.info('submitheader tests')
142+
assert_raises_rpc_error(-22, 'Block header decode failed', lambda: node.submitheader(hexdata='xx' * 80))
143+
assert_raises_rpc_error(-22, 'Block header decode failed', lambda: node.submitheader(hexdata='ff' * 78))
144+
assert_raises_rpc_error(-25, 'Must submit previous header', lambda: node.submitheader(hexdata='ff' * 80))
145+
146+
block.solve()
147+
148+
def chain_tip(b_hash, *, status='headers-only', branchlen=1):
149+
return {'hash': b_hash, 'height': 202, 'branchlen': branchlen, 'status': status}
150+
151+
assert chain_tip(block.hash) not in node.getchaintips()
152+
node.submitheader(hexdata=b2x(block.serialize()))
153+
assert chain_tip(block.hash) in node.getchaintips()
154+
node.submitheader(hexdata=b2x(CBlockHeader(block).serialize())) # Noop
155+
assert chain_tip(block.hash) in node.getchaintips()
156+
157+
bad_block_root = copy.deepcopy(block)
158+
bad_block_root.hashMerkleRoot += 2
159+
bad_block_root.solve()
160+
assert chain_tip(bad_block_root.hash) not in node.getchaintips()
161+
node.submitheader(hexdata=b2x(CBlockHeader(bad_block_root).serialize()))
162+
assert chain_tip(bad_block_root.hash) in node.getchaintips()
163+
# Should still reject invalid blocks, even if we have the header:
164+
assert_equal(node.submitblock(hexdata=b2x(bad_block_root.serialize())), 'invalid')
165+
assert chain_tip(bad_block_root.hash) in node.getchaintips()
166+
# We know the header for this invalid block, so should just return early without error:
167+
node.submitheader(hexdata=b2x(CBlockHeader(bad_block_root).serialize()))
168+
assert chain_tip(bad_block_root.hash) in node.getchaintips()
169+
170+
bad_block_lock = copy.deepcopy(block)
171+
bad_block_lock.vtx[0].nLockTime = 2**32 - 1
172+
bad_block_lock.vtx[0].rehash()
173+
bad_block_lock.hashMerkleRoot = bad_block_lock.calc_merkle_root()
174+
bad_block_lock.solve()
175+
assert_equal(node.submitblock(hexdata=b2x(bad_block_lock.serialize())), 'invalid')
176+
# Build a "good" block on top of the submitted bad block
177+
bad_block2 = copy.deepcopy(block)
178+
bad_block2.hashPrevBlock = bad_block_lock.sha256
179+
bad_block2.solve()
180+
assert_raises_rpc_error(-25, 'bad-prevblk', lambda: node.submitheader(hexdata=b2x(CBlockHeader(bad_block2).serialize())))
181+
182+
# Should reject invalid header right away
183+
bad_block_time = copy.deepcopy(block)
184+
bad_block_time.nTime = 1
185+
bad_block_time.solve()
186+
assert_raises_rpc_error(-25, 'time-too-old', lambda: node.submitheader(hexdata=b2x(CBlockHeader(bad_block_time).serialize())))
187+
188+
# Should ask for the block from a p2p node, if they announce the header as well:
189+
node.add_p2p_connection(P2PDataStore())
190+
node.p2p.wait_for_getheaders(timeout=5) # Drop the first getheaders
191+
node.p2p.send_blocks_and_test(blocks=[block], rpc=node)
192+
# Must be active now:
193+
assert chain_tip(block.hash, status='active', branchlen=0) in node.getchaintips()
194+
195+
# Building a few blocks should give the same results
196+
node.generate(10)
197+
assert_raises_rpc_error(-25, 'time-too-old', lambda: node.submitheader(hexdata=b2x(CBlockHeader(bad_block_time).serialize())))
198+
assert_raises_rpc_error(-25, 'bad-prevblk', lambda: node.submitheader(hexdata=b2x(CBlockHeader(bad_block2).serialize())))
199+
node.submitheader(hexdata=b2x(CBlockHeader(block).serialize()))
200+
node.submitheader(hexdata=b2x(CBlockHeader(bad_block_root).serialize()))
201+
202+
134203
if __name__ == '__main__':
135204
MiningTest().main()

0 commit comments

Comments
 (0)