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 add_options(self, parser): 12 self.add_wallet_options(parser) 13 14 def set_test_params(self): 15 self.setup_clean_chain = True 16 self.num_nodes = 2 17 18 def skip_test_if_missing_module(self): 19 self.skip_if_no_wallet() 20 21 def run_test(self): 22 # Generate some blocks and obtain some coins on node 0. We send 23 # some balance to node 1, which will hold it as a single coin. 24 self.generate(self.nodes[0], 150) 25 self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 10) 26 self.generate(self.nodes[0], 1) 27 28 # Get a block reward with node 1 and remember the block so we can orphan 29 # it later. 30 self.sync_blocks() 31 blk = self.generate(self.nodes[1], 1)[0] 32 33 # Let the block reward mature and send coins including both 34 # the existing balance and the block reward. 35 self.generate(self.nodes[0], 150) 36 assert_equal(self.nodes[1].getbalance(), 10 + 25) 37 pre_reorg_conf_bals = self.nodes[1].getbalances() 38 txid = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 30) 39 orig_chain_tip = self.nodes[0].getbestblockhash() 40 self.sync_mempools() 41 42 # Orphan the block reward and make sure that the original coins 43 # from the wallet can still be spent. 44 self.nodes[0].invalidateblock(blk) 45 blocks = self.generate(self.nodes[0], 152) 46 conflict_block = blocks[0] 47 # We expect the descendants of orphaned rewards to no longer be considered 48 assert_equal(self.nodes[1].getbalances()["mine"], { 49 "trusted": 10, 50 "untrusted_pending": 0, 51 "immature": 0, 52 }) 53 # And the unconfirmed tx to be abandoned 54 assert_equal(self.nodes[1].gettransaction(txid)["details"][0]["abandoned"], True) 55 56 # The abandoning should persist through reloading 57 self.nodes[1].unloadwallet(self.default_wallet_name) 58 self.nodes[1].loadwallet(self.default_wallet_name) 59 assert_equal(self.nodes[1].gettransaction(txid)["details"][0]["abandoned"], True) 60 61 # If the orphaned reward is reorged back into the main chain, any unconfirmed 62 # descendant txs at the time of the original reorg remain abandoned. 63 self.nodes[0].invalidateblock(conflict_block) 64 self.nodes[0].reconsiderblock(blk) 65 assert_equal(self.nodes[0].getbestblockhash(), orig_chain_tip) 66 self.generate(self.nodes[0], 3) 67 68 balances = self.nodes[1].getbalances() 69 del balances["lastprocessedblock"] 70 del pre_reorg_conf_bals["lastprocessedblock"] 71 assert_equal(balances, pre_reorg_conf_bals) 72 assert_equal(self.nodes[1].gettransaction(txid)["details"][0]["abandoned"], True) 73 74 75 if __name__ == '__main__': 76 OrphanedBlockRewardTest().main()