wallet_orphanedreward.py
1 #!/usr/bin/env python3 2 # Copyright (c) 2020-present The Bitcoin Core developers 3 # Distributed under the MIT software license, see the accompanying 4 # file COPYING or http://www.opensource.org/licenses/mit-license.php. 5 """Test orphaned block rewards in the wallet.""" 6 7 from test_framework.test_framework import BitcoinTestFramework 8 from test_framework.util import assert_equal 9 10 class OrphanedBlockRewardTest(BitcoinTestFramework): 11 def set_test_params(self): 12 self.setup_clean_chain = True 13 self.num_nodes = 2 14 15 def skip_test_if_missing_module(self): 16 self.skip_if_no_wallet() 17 18 def run_test(self): 19 # Generate some blocks and obtain some coins on node 0. We send 20 # some balance to node 1, which will hold it as a single coin. 21 self.generate(self.nodes[0], 150) 22 self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 10) 23 self.generate(self.nodes[0], 1) 24 25 # Get a block reward with node 1 and remember the block so we can orphan 26 # it later. 27 self.sync_blocks() 28 blk = self.generate(self.nodes[1], 1)[0] 29 30 # Let the block reward mature and send coins including both 31 # the existing balance and the block reward. 32 self.generate(self.nodes[0], 150) 33 assert_equal(self.nodes[1].getbalance(), 10 + 25) 34 pre_reorg_conf_bals = self.nodes[1].getbalances() 35 txid = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 30) 36 orig_chain_tip = self.nodes[0].getbestblockhash() 37 self.sync_mempools() 38 39 # Orphan the block reward and make sure that the original coins 40 # from the wallet can still be spent. 41 self.nodes[0].invalidateblock(blk) 42 blocks = self.generate(self.nodes[0], 152) 43 conflict_block = blocks[0] 44 # We expect the descendants of orphaned rewards to no longer be considered 45 assert_equal(self.nodes[1].getbalances()["mine"], { 46 "trusted": 10, 47 "untrusted_pending": 0, 48 "immature": 0, 49 "nonmempool": 0, 50 }) 51 # And the unconfirmed tx to be abandoned 52 assert_equal(self.nodes[1].gettransaction(txid)["details"][0]["abandoned"], True) 53 54 # The abandoning should persist through reloading 55 self.nodes[1].unloadwallet(self.default_wallet_name) 56 self.nodes[1].loadwallet(self.default_wallet_name) 57 assert_equal(self.nodes[1].gettransaction(txid)["details"][0]["abandoned"], True) 58 59 # If the orphaned reward is reorged back into the main chain, any unconfirmed 60 # descendant txs at the time of the original reorg remain abandoned. 61 self.nodes[0].invalidateblock(conflict_block) 62 self.nodes[0].reconsiderblock(blk) 63 assert_equal(self.nodes[0].getbestblockhash(), orig_chain_tip) 64 self.generate(self.nodes[0], 3) 65 66 balances = self.nodes[1].getbalances() 67 del balances["lastprocessedblock"] 68 del pre_reorg_conf_bals["lastprocessedblock"] 69 assert_equal(balances, pre_reorg_conf_bals) 70 assert_equal(self.nodes[1].gettransaction(txid)["details"][0]["abandoned"], True) 71 72 73 if __name__ == '__main__': 74 OrphanedBlockRewardTest(__file__).main()