Changeset View
Changeset View
Standalone View
Standalone View
test/functional/rpc_invalidateblock.py
#!/usr/bin/env python3 | #!/usr/bin/env python3 | ||||
# Copyright (c) 2014-2019 The Bitcoin Core developers | # Copyright (c) 2014-2019 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 the invalidateblock RPC.""" | """Test the invalidateblock RPC.""" | ||||
import time | from test_framework.address import ADDRESS_BCHREG_UNSPENDABLE | ||||
from test_framework.test_framework import BitcoinTestFramework | from test_framework.test_framework import BitcoinTestFramework | ||||
from test_framework.util import ( | from test_framework.util import ( | ||||
assert_equal, | assert_equal, | ||||
connect_nodes, | connect_nodes, | ||||
wait_until, | |||||
) | ) | ||||
class InvalidateTest(BitcoinTestFramework): | class InvalidateTest(BitcoinTestFramework): | ||||
def set_test_params(self): | def set_test_params(self): | ||||
self.setup_clean_chain = True | self.setup_clean_chain = True | ||||
self.num_nodes = 3 | self.num_nodes = 3 | ||||
self.extra_args = [["-noparkdeepreorg"], [], []] | self.extra_args = [["-noparkdeepreorg"], [], []] | ||||
def setup_network(self): | def setup_network(self): | ||||
self.setup_nodes() | self.setup_nodes() | ||||
def run_test(self): | def run_test(self): | ||||
self.log.info( | self.log.info( | ||||
"Make sure we repopulate setBlockIndexCandidates after InvalidateBlock:") | "Make sure we repopulate setBlockIndexCandidates after InvalidateBlock:") | ||||
self.log.info("Mine 4 blocks on Node 0") | self.log.info("Mine 4 blocks on Node 0") | ||||
self.nodes[0].generatetoaddress( | self.nodes[0].generatetoaddress( | ||||
4, self.nodes[0].get_deterministic_priv_key().address) | 4, self.nodes[0].get_deterministic_priv_key().address) | ||||
assert self.nodes[0].getblockcount() == 4 | assert_equal(self.nodes[0].getblockcount(), 4) | ||||
besthash = self.nodes[0].getbestblockhash() | besthash_n0 = self.nodes[0].getbestblockhash() | ||||
self.log.info("Mine competing 6 blocks on Node 1") | self.log.info("Mine competing 6 blocks on Node 1") | ||||
self.nodes[1].generatetoaddress( | self.nodes[1].generatetoaddress( | ||||
6, self.nodes[1].get_deterministic_priv_key().address) | 6, self.nodes[1].get_deterministic_priv_key().address) | ||||
assert self.nodes[1].getblockcount() == 6 | assert_equal(self.nodes[1].getblockcount(), 6) | ||||
self.log.info("Connect nodes to force a reorg") | self.log.info("Connect nodes to force a reorg") | ||||
connect_nodes(self.nodes[0], self.nodes[1]) | connect_nodes(self.nodes[0], self.nodes[1]) | ||||
self.sync_blocks(self.nodes[0:2]) | self.sync_blocks(self.nodes[0:2]) | ||||
assert self.nodes[0].getblockcount() == 6 | assert_equal(self.nodes[0].getblockcount(), 6) | ||||
badhash = self.nodes[1].getblockhash(2) | badhash = self.nodes[1].getblockhash(2) | ||||
self.log.info( | self.log.info( | ||||
"Invalidate block 2 on node 0 and verify we reorg to node 0's original chain") | "Invalidate block 2 on node 0 and verify we reorg to node 0's original chain") | ||||
self.nodes[0].invalidateblock(badhash) | self.nodes[0].invalidateblock(badhash) | ||||
newheight = self.nodes[0].getblockcount() | assert_equal(self.nodes[0].getblockcount(), 4) | ||||
newhash = self.nodes[0].getbestblockhash() | assert_equal(self.nodes[0].getbestblockhash(), besthash_n0) | ||||
if (newheight != 4 or newhash != besthash): | |||||
raise AssertionError( | |||||
"Wrong tip for node0, hash {}, height {}".format(newhash, newheight)) | |||||
self.log.info("\nMake sure we won't reorg to a lower work chain:") | self.log.info("\nMake sure we won't reorg to a lower work chain:") | ||||
connect_nodes(self.nodes[1], self.nodes[2]) | connect_nodes(self.nodes[1], self.nodes[2]) | ||||
self.log.info("Sync node 2 to node 1 so both have 6 blocks") | self.log.info("Sync node 2 to node 1 so both have 6 blocks") | ||||
self.sync_blocks(self.nodes[1:3]) | self.sync_blocks(self.nodes[1:3]) | ||||
assert self.nodes[2].getblockcount() == 6 | assert_equal(self.nodes[2].getblockcount(), 6) | ||||
self.log.info("Invalidate block 5 on node 1 so its tip is now at 4") | self.log.info("Invalidate block 5 on node 1 so its tip is now at 4") | ||||
self.nodes[1].invalidateblock(self.nodes[1].getblockhash(5)) | self.nodes[1].invalidateblock(self.nodes[1].getblockhash(5)) | ||||
assert self.nodes[1].getblockcount() == 4 | assert_equal(self.nodes[1].getblockcount(), 4) | ||||
self.log.info("Invalidate block 3 on node 2, so its tip is now 2") | self.log.info("Invalidate block 3 on node 2, so its tip is now 2") | ||||
self.nodes[2].invalidateblock(self.nodes[2].getblockhash(3)) | self.nodes[2].invalidateblock(self.nodes[2].getblockhash(3)) | ||||
assert self.nodes[2].getblockcount() == 2 | assert_equal(self.nodes[2].getblockcount(), 2) | ||||
self.log.info("..and then mine a block") | self.log.info("..and then mine a block") | ||||
self.nodes[2].generatetoaddress( | self.nodes[2].generatetoaddress( | ||||
1, self.nodes[2].get_deterministic_priv_key().address) | 1, self.nodes[2].get_deterministic_priv_key().address) | ||||
self.log.info("Verify all nodes are at the right height") | self.log.info("Verify all nodes are at the right height") | ||||
time.sleep(5) | wait_until(lambda: self.nodes[2].getblockcount() == 3, timeout=5) | ||||
assert_equal(self.nodes[2].getblockcount(), 3) | wait_until(lambda: self.nodes[0].getblockcount() == 4, timeout=5) | ||||
assert_equal(self.nodes[0].getblockcount(), 4) | wait_until(lambda: self.nodes[1].getblockcount() == 4, timeout=5) | ||||
node1height = self.nodes[1].getblockcount() | |||||
if node1height < 4: | self.log.info("Verify that we reconsider all ancestors as well") | ||||
raise AssertionError( | blocks = self.nodes[1].generatetoaddress( | ||||
"Node 1 reorged to a lower height: {}".format(node1height)) | 10, ADDRESS_BCHREG_UNSPENDABLE) | ||||
assert_equal(self.nodes[1].getbestblockhash(), blocks[-1]) | |||||
# Invalidate the two blocks at the tip | |||||
self.nodes[1].invalidateblock(blocks[-1]) | |||||
self.nodes[1].invalidateblock(blocks[-2]) | |||||
assert_equal(self.nodes[1].getbestblockhash(), blocks[-3]) | |||||
# Reconsider only the previous tip | |||||
self.nodes[1].reconsiderblock(blocks[-1]) | |||||
# Should be back at the tip by now | |||||
assert_equal(self.nodes[1].getbestblockhash(), blocks[-1]) | |||||
self.log.info("Verify that we reconsider all descendants") | |||||
blocks = self.nodes[1].generatetoaddress( | |||||
10, ADDRESS_BCHREG_UNSPENDABLE) | |||||
assert_equal(self.nodes[1].getbestblockhash(), blocks[-1]) | |||||
# Invalidate the two blocks at the tip | |||||
self.nodes[1].invalidateblock(blocks[-2]) | |||||
self.nodes[1].invalidateblock(blocks[-4]) | |||||
assert_equal(self.nodes[1].getbestblockhash(), blocks[-5]) | |||||
# Reconsider only the previous tip | |||||
self.nodes[1].reconsiderblock(blocks[-4]) | |||||
# Should be back at the tip by now | |||||
assert_equal(self.nodes[1].getbestblockhash(), blocks[-1]) | |||||
if __name__ == '__main__': | if __name__ == '__main__': | ||||
InvalidateTest().main() | InvalidateTest().main() |