Changeset View
Changeset View
Standalone View
Standalone View
test/functional/feature_minchainwork.py
Show All 26 Lines | |||||
class MinimumChainWorkTest(BitcoinTestFramework): | class MinimumChainWorkTest(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 = [[], ["-minimumchainwork=0x65"], | self.extra_args = [[], ["-minimumchainwork=0x65"], | ||||
["-minimumchainwork=0x65"]] | ["-minimumchainwork=0x65"]] | ||||
self.node_min_work = [0, 101, 101] | self.node_min_work = [0, 101, 101] | ||||
def skip_test_if_missing_module(self): | |||||
self.skip_if_no_wallet() | |||||
def setup_network(self): | def setup_network(self): | ||||
# This test relies on the chain setup being: | # This test relies on the chain setup being: | ||||
# node0 <- node1 <- node2 | # node0 <- node1 <- node2 | ||||
# Before leaving IBD, nodes prefer to download blocks from outbound | # Before leaving IBD, nodes prefer to download blocks from outbound | ||||
# peers, so ensure that we're mining on an outbound peer and testing | # peers, so ensure that we're mining on an outbound peer and testing | ||||
# block relay to inbound peers. | # block relay to inbound peers. | ||||
self.setup_nodes() | self.setup_nodes() | ||||
for i in range(self.num_nodes - 1): | for i in range(self.num_nodes - 1): | ||||
connect_nodes(self.nodes[i + 1], self.nodes[i]) | connect_nodes(self.nodes[i + 1], self.nodes[i]) | ||||
def run_test(self): | def run_test(self): | ||||
# Start building a chain on node0. node2 shouldn't be able to sync until node1's | # Start building a chain on node0. node2 shouldn't be able to sync until node1's | ||||
# minchainwork is exceeded | # minchainwork is exceeded | ||||
starting_chain_work = REGTEST_WORK_PER_BLOCK # Genesis block's work | starting_chain_work = REGTEST_WORK_PER_BLOCK # Genesis block's work | ||||
self.log.info( | self.log.info( | ||||
"Testing relay across node {} (minChainWork = {})".format( | "Testing relay across node {} (minChainWork = {})".format( | ||||
1, self.node_min_work[1])) | 1, self.node_min_work[1])) | ||||
starting_blockcount = self.nodes[2].getblockcount() | starting_blockcount = self.nodes[2].getblockcount() | ||||
num_blocks_to_generate = int( | num_blocks_to_generate = int( | ||||
(self.node_min_work[1] - starting_chain_work) / REGTEST_WORK_PER_BLOCK) | (self.node_min_work[1] - starting_chain_work) / REGTEST_WORK_PER_BLOCK) | ||||
self.log.info("Generating {} blocks on node0".format( | self.log.info("Generating {} blocks on node0".format( | ||||
num_blocks_to_generate)) | num_blocks_to_generate)) | ||||
hashes = self.nodes[0].generate(num_blocks_to_generate) | hashes = self.nodes[0].generatetoaddress(num_blocks_to_generate, | ||||
self.nodes[0].get_deterministic_priv_key().address) | |||||
self.log.info("Node0 current chain work: {}".format( | self.log.info("Node0 current chain work: {}".format( | ||||
self.nodes[0].getblockheader(hashes[-1])['chainwork'])) | self.nodes[0].getblockheader(hashes[-1])['chainwork'])) | ||||
# Sleep a few seconds and verify that node2 didn't get any new blocks | # Sleep a few seconds and verify that node2 didn't get any new blocks | ||||
# or headers. We sleep, rather than sync_blocks(node0, node1) because | # or headers. We sleep, rather than sync_blocks(node0, node1) because | ||||
# it's reasonable either way for node1 to get the blocks, or not get | # it's reasonable either way for node1 to get the blocks, or not get | ||||
# them (since they're below node1's minchainwork). | # them (since they're below node1's minchainwork). | ||||
time.sleep(3) | time.sleep(3) | ||||
self.log.info("Verifying node 2 has no more blocks than before") | self.log.info("Verifying node 2 has no more blocks than before") | ||||
self.log.info("Blockcounts: {}".format( | self.log.info("Blockcounts: {}".format( | ||||
[n.getblockcount() for n in self.nodes])) | [n.getblockcount() for n in self.nodes])) | ||||
# Node2 shouldn't have any new headers yet, because node1 should not | # Node2 shouldn't have any new headers yet, because node1 should not | ||||
# have relayed anything. | # have relayed anything. | ||||
assert_equal(len(self.nodes[2].getchaintips()), 1) | assert_equal(len(self.nodes[2].getchaintips()), 1) | ||||
assert_equal(self.nodes[2].getchaintips()[0]['height'], 0) | assert_equal(self.nodes[2].getchaintips()[0]['height'], 0) | ||||
assert self.nodes[1].getbestblockhash( | assert self.nodes[1].getbestblockhash( | ||||
) != self.nodes[0].getbestblockhash() | ) != self.nodes[0].getbestblockhash() | ||||
assert_equal(self.nodes[2].getblockcount(), starting_blockcount) | assert_equal(self.nodes[2].getblockcount(), starting_blockcount) | ||||
self.log.info("Generating one more block") | self.log.info("Generating one more block") | ||||
self.nodes[0].generate(1) | self.nodes[0].generatetoaddress( | ||||
1, self.nodes[0].get_deterministic_priv_key().address) | |||||
self.log.info("Verifying nodes are all synced") | self.log.info("Verifying nodes are all synced") | ||||
# Because nodes in regtest are all manual connections (eg using | # Because nodes in regtest are all manual connections (eg using | ||||
# addnode), node1 should not have disconnected node0. If not for that, | # addnode), node1 should not have disconnected node0. If not for that, | ||||
# we'd expect node1 to have disconnected node0 for serving an | # we'd expect node1 to have disconnected node0 for serving an | ||||
# insufficient work chain, in which case we'd need to reconnect them to | # insufficient work chain, in which case we'd need to reconnect them to | ||||
# continue the test. | # continue the test. | ||||
self.sync_all() | self.sync_all() | ||||
self.log.info("Blockcounts: {}".format( | self.log.info("Blockcounts: {}".format( | ||||
[n.getblockcount() for n in self.nodes])) | [n.getblockcount() for n in self.nodes])) | ||||
if __name__ == '__main__': | if __name__ == '__main__': | ||||
MinimumChainWorkTest().main() | MinimumChainWorkTest().main() |