Changeset View
Changeset View
Standalone View
Standalone View
test/functional/mining_basic.py
#!/usr/bin/env python3 | #!/usr/bin/env python3 | ||||
# Copyright (c) 2014-2016 The Bitcoin Core developers | # Copyright (c) 2014-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 mining RPCs | """Test mining RPCs | ||||
- getmininginfo | - getmininginfo | ||||
- getblocktemplate proposal mode | - getblocktemplate proposal mode | ||||
- submitblock""" | - submitblock""" | ||||
from binascii import b2a_hex | |||||
import copy | import copy | ||||
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, | |||||
def b2x(b): | bytes_to_hex_str as b2x, | ||||
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: | ||||
block.hashMerkleRoot = block.calc_merkle_root() | block.hashMerkleRoot = block.calc_merkle_root() | ||||
rsp = node.getblocktemplate( | rsp = node.getblocktemplate( | ||||
{'data': b2x(block.serialize()), 'mode': 'proposal'}) | {'data': b2x(block.serialize()), 'mode': 'proposal'}) | ||||
assert_equal(rsp, expect) | assert_equal(rsp, expect) | ||||
▲ Show 20 Lines • Show All 106 Lines • ▼ Show 20 Lines | def run_test(self): | ||||
bad_block.nTime = 0 | bad_block.nTime = 0 | ||||
assert_template(node, bad_block, 'time-too-old') | assert_template(node, bad_block, 'time-too-old') | ||||
self.log.info("getblocktemplate: Test not best block") | self.log.info("getblocktemplate: Test not best block") | ||||
bad_block = copy.deepcopy(block) | bad_block = copy.deepcopy(block) | ||||
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() | |||||
# Noop | |||||
node.submitheader(hexdata=b2x(CBlockHeader(block).serialize())) | |||||
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()) | |||||
# Drop the first getheaders | |||||
node.p2p.wait_for_getheaders(timeout=5) | |||||
node.p2p.send_blocks_and_test(blocks=[block], node=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() |