wallet_orphanedreward.py
1 #!/usr/bin/env python3 2 # Copyright (c) 2020-2022 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 }) 50 # And the unconfirmed tx to be abandoned 51 assert_equal(self.nodes[1].gettransaction(txid)["details"][0]["abandoned"], True) 52 53 # The abandoning should persist through reloading 54 self.nodes[1].unloadwallet(self.default_wallet_name) 55 self.nodes[1].loadwallet(self.default_wallet_name) 56 assert_equal(self.nodes[1].gettransaction(txid)["details"][0]["abandoned"], True) 57 58 # If the orphaned reward is reorged back into the main chain, any unconfirmed 59 # descendant txs at the time of the original reorg remain abandoned. 60 self.nodes[0].invalidateblock(conflict_block) 61 self.nodes[0].reconsiderblock(blk) 62 assert_equal(self.nodes[0].getbestblockhash(), orig_chain_tip) 63 self.generate(self.nodes[0], 3) 64 65 balances = self.nodes[1].getbalances() 66 del balances["lastprocessedblock"] 67 del pre_reorg_conf_bals["lastprocessedblock"] 68 assert_equal(balances, pre_reorg_conf_bals) 69 assert_equal(self.nodes[1].gettransaction(txid)["details"][0]["abandoned"], True) 70 71 72 if __name__ == '__main__': 73 OrphanedBlockRewardTest(__file__).main()