mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-09-08 06:02:12 +02:00
qa: Add tests for submitheader
This commit is contained in:
@@ -9,16 +9,23 @@
|
|||||||
- submitblock"""
|
- submitblock"""
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
from binascii import b2a_hex
|
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
from test_framework.blocktools import create_coinbase
|
from test_framework.blocktools import create_coinbase
|
||||||
from test_framework.messages import CBlock
|
from test_framework.messages import (
|
||||||
|
CBlock,
|
||||||
|
CBlockHeader,
|
||||||
|
)
|
||||||
|
from test_framework.mininode import (
|
||||||
|
P2PDataStore,
|
||||||
|
)
|
||||||
from test_framework.test_framework import BitcoinTestFramework
|
from test_framework.test_framework import BitcoinTestFramework
|
||||||
from test_framework.util import assert_equal, assert_raises_rpc_error
|
from test_framework.util import (
|
||||||
|
assert_equal,
|
||||||
|
assert_raises_rpc_error,
|
||||||
|
bytes_to_hex_str as b2x,
|
||||||
|
)
|
||||||
|
|
||||||
def b2x(b):
|
|
||||||
return b2a_hex(b).decode('ascii')
|
|
||||||
|
|
||||||
def assert_template(node, block, expect, rehash=True):
|
def assert_template(node, block, expect, rehash=True):
|
||||||
if rehash:
|
if rehash:
|
||||||
@@ -131,5 +138,67 @@ class MiningTest(BitcoinTestFramework):
|
|||||||
bad_block.hashPrevBlock = 123
|
bad_block.hashPrevBlock = 123
|
||||||
assert_template(node, bad_block, 'inconclusive-not-best-prevblk')
|
assert_template(node, bad_block, 'inconclusive-not-best-prevblk')
|
||||||
|
|
||||||
|
self.log.info('submitheader tests')
|
||||||
|
assert_raises_rpc_error(-22, 'Block header decode failed', lambda: node.submitheader(hexdata='xx' * 80))
|
||||||
|
assert_raises_rpc_error(-22, 'Block header decode failed', lambda: node.submitheader(hexdata='ff' * 78))
|
||||||
|
assert_raises_rpc_error(-25, 'Must submit previous header', lambda: node.submitheader(hexdata='ff' * 80))
|
||||||
|
|
||||||
|
block.solve()
|
||||||
|
|
||||||
|
def chain_tip(b_hash, *, status='headers-only', branchlen=1):
|
||||||
|
return {'hash': b_hash, 'height': 202, 'branchlen': branchlen, 'status': status}
|
||||||
|
|
||||||
|
assert chain_tip(block.hash) not in node.getchaintips()
|
||||||
|
node.submitheader(hexdata=b2x(block.serialize()))
|
||||||
|
assert chain_tip(block.hash) in node.getchaintips()
|
||||||
|
node.submitheader(hexdata=b2x(CBlockHeader(block).serialize())) # Noop
|
||||||
|
assert chain_tip(block.hash) in node.getchaintips()
|
||||||
|
|
||||||
|
bad_block_root = copy.deepcopy(block)
|
||||||
|
bad_block_root.hashMerkleRoot += 2
|
||||||
|
bad_block_root.solve()
|
||||||
|
assert chain_tip(bad_block_root.hash) not in node.getchaintips()
|
||||||
|
node.submitheader(hexdata=b2x(CBlockHeader(bad_block_root).serialize()))
|
||||||
|
assert chain_tip(bad_block_root.hash) in node.getchaintips()
|
||||||
|
# Should still reject invalid blocks, even if we have the header:
|
||||||
|
assert_equal(node.submitblock(hexdata=b2x(bad_block_root.serialize())), 'invalid')
|
||||||
|
assert chain_tip(bad_block_root.hash) in node.getchaintips()
|
||||||
|
# We know the header for this invalid block, so should just return early without error:
|
||||||
|
node.submitheader(hexdata=b2x(CBlockHeader(bad_block_root).serialize()))
|
||||||
|
assert chain_tip(bad_block_root.hash) in node.getchaintips()
|
||||||
|
|
||||||
|
bad_block_lock = copy.deepcopy(block)
|
||||||
|
bad_block_lock.vtx[0].nLockTime = 2**32 - 1
|
||||||
|
bad_block_lock.vtx[0].rehash()
|
||||||
|
bad_block_lock.hashMerkleRoot = bad_block_lock.calc_merkle_root()
|
||||||
|
bad_block_lock.solve()
|
||||||
|
assert_equal(node.submitblock(hexdata=b2x(bad_block_lock.serialize())), 'invalid')
|
||||||
|
# Build a "good" block on top of the submitted bad block
|
||||||
|
bad_block2 = copy.deepcopy(block)
|
||||||
|
bad_block2.hashPrevBlock = bad_block_lock.sha256
|
||||||
|
bad_block2.solve()
|
||||||
|
assert_raises_rpc_error(-25, 'bad-prevblk', lambda: node.submitheader(hexdata=b2x(CBlockHeader(bad_block2).serialize())))
|
||||||
|
|
||||||
|
# Should reject invalid header right away
|
||||||
|
bad_block_time = copy.deepcopy(block)
|
||||||
|
bad_block_time.nTime = 1
|
||||||
|
bad_block_time.solve()
|
||||||
|
assert_raises_rpc_error(-25, 'time-too-old', lambda: node.submitheader(hexdata=b2x(CBlockHeader(bad_block_time).serialize())))
|
||||||
|
|
||||||
|
# Should ask for the block from a p2p node, if they announce the header as well:
|
||||||
|
node.add_p2p_connection(P2PDataStore())
|
||||||
|
node.p2p.wait_for_getheaders(timeout=5) # Drop the first getheaders
|
||||||
|
node.p2p.send_blocks_and_test(blocks=[block], rpc=node)
|
||||||
|
# Must be active now:
|
||||||
|
assert chain_tip(block.hash, status='active', branchlen=0) in node.getchaintips()
|
||||||
|
|
||||||
|
# Building a few blocks should give the same results
|
||||||
|
node.generate(10)
|
||||||
|
assert_raises_rpc_error(-25, 'time-too-old', lambda: node.submitheader(hexdata=b2x(CBlockHeader(bad_block_time).serialize())))
|
||||||
|
assert_raises_rpc_error(-25, 'bad-prevblk', lambda: node.submitheader(hexdata=b2x(CBlockHeader(bad_block2).serialize())))
|
||||||
|
node.submitheader(hexdata=b2x(CBlockHeader(block).serialize()))
|
||||||
|
node.submitheader(hexdata=b2x(CBlockHeader(bad_block_root).serialize()))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
MiningTest().main()
|
MiningTest().main()
|
||||||
|
Reference in New Issue
Block a user