wallet_listreceivedby.py
1 #!/usr/bin/env python3 2 # Copyright (c) 2014-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 the listreceivedbyaddress, listreceivedbylabel, getreceivedybaddress, and getreceivedbylabel RPCs.""" 6 from decimal import Decimal 7 8 from test_framework.blocktools import COINBASE_MATURITY 9 from test_framework.test_framework import BitcoinTestFramework 10 from test_framework.util import ( 11 assert_array_result, 12 assert_equal, 13 assert_raises_rpc_error, 14 ) 15 from test_framework.wallet_util import test_address 16 17 18 class ReceivedByTest(BitcoinTestFramework): 19 def set_test_params(self): 20 self.num_nodes = 2 21 # whitelist peers to speed up tx relay / mempool sync 22 self.noban_tx_relay = True 23 24 def skip_test_if_missing_module(self): 25 self.skip_if_no_wallet() 26 self.skip_if_no_cli() 27 28 def run_test(self): 29 # save the number of coinbase reward addresses so far 30 num_cb_reward_addresses = len(self.nodes[1].listreceivedbyaddress(minconf=0, include_empty=True)) 31 32 self.log.info("listreceivedbyaddress Test") 33 34 # Send from node 0 to 1 35 addr = self.nodes[1].getnewaddress() 36 txid = self.nodes[0].sendtoaddress(addr, 0.1) 37 self.sync_all() 38 39 # Check not listed in listreceivedbyaddress because has 0 confirmations 40 assert_array_result(self.nodes[1].listreceivedbyaddress(), 41 {"address": addr}, 42 {}, 43 True) 44 # Bury Tx under 10 block so it will be returned by listreceivedbyaddress 45 self.generate(self.nodes[1], 10) 46 assert_array_result(self.nodes[1].listreceivedbyaddress(), 47 {"address": addr}, 48 {"address": addr, "label": "", "amount": Decimal("0.1"), "confirmations": 10, "txids": [txid, ]}) 49 # With min confidence < 10 50 assert_array_result(self.nodes[1].listreceivedbyaddress(5), 51 {"address": addr}, 52 {"address": addr, "label": "", "amount": Decimal("0.1"), "confirmations": 10, "txids": [txid, ]}) 53 # With min confidence > 10, should not find Tx 54 assert_array_result(self.nodes[1].listreceivedbyaddress(11), {"address": addr}, {}, True) 55 56 # Empty Tx 57 empty_addr = self.nodes[1].getnewaddress() 58 assert_array_result(self.nodes[1].listreceivedbyaddress(0, True), 59 {"address": empty_addr}, 60 {"address": empty_addr, "label": "", "amount": 0, "confirmations": 0, "txids": []}) 61 62 # No returned addy should be a change addr 63 for node in self.nodes: 64 for addr_obj in node.listreceivedbyaddress(): 65 assert_equal(node.getaddressinfo(addr_obj["address"])["ischange"], False) 66 67 # Test Address filtering 68 # Only on addr 69 expected = {"address": addr, "label": "", "amount": Decimal("0.1"), "confirmations": 10, "txids": [txid, ]} 70 res = self.nodes[1].listreceivedbyaddress(minconf=0, include_empty=True, address_filter=addr) 71 assert_array_result(res, {"address": addr}, expected) 72 assert_equal(len(res), 1) 73 # Test for regression on CLI calls with address string (#14173) 74 cli_res = self.nodes[1].cli.listreceivedbyaddress(0, True, True, addr) 75 assert_array_result(cli_res, {"address": addr}, expected) 76 assert_equal(len(cli_res), 1) 77 # Error on invalid address 78 assert_raises_rpc_error(-4, "address_filter parameter was invalid", self.nodes[1].listreceivedbyaddress, minconf=0, include_empty=True, address_filter="bamboozling") 79 # Another address receive money 80 res = self.nodes[1].listreceivedbyaddress(0, True, True) 81 assert_equal(len(res), 2 + num_cb_reward_addresses) # Right now 2 entries 82 other_addr = self.nodes[1].getnewaddress() 83 txid2 = self.nodes[0].sendtoaddress(other_addr, 0.1) 84 self.generate(self.nodes[0], 1) 85 # Same test as above should still pass 86 expected = {"address": addr, "label": "", "amount": Decimal("0.1"), "confirmations": 11, "txids": [txid, ]} 87 res = self.nodes[1].listreceivedbyaddress(0, True, True, addr) 88 assert_array_result(res, {"address": addr}, expected) 89 assert_equal(len(res), 1) 90 # Same test as above but with other_addr should still pass 91 expected = {"address": other_addr, "label": "", "amount": Decimal("0.1"), "confirmations": 1, "txids": [txid2, ]} 92 res = self.nodes[1].listreceivedbyaddress(0, True, True, other_addr) 93 assert_array_result(res, {"address": other_addr}, expected) 94 assert_equal(len(res), 1) 95 # Should be two entries though without filter 96 res = self.nodes[1].listreceivedbyaddress(0, True, True) 97 assert_equal(len(res), 3 + num_cb_reward_addresses) # Became 3 entries 98 99 # Not on random addr 100 other_addr = self.nodes[0].getnewaddress() # note on node[0]! just a random addr 101 res = self.nodes[1].listreceivedbyaddress(0, True, True, other_addr) 102 assert_equal(len(res), 0) 103 104 self.log.info("getreceivedbyaddress Test") 105 106 # Send from node 0 to 1 107 addr = self.nodes[1].getnewaddress() 108 txid = self.nodes[0].sendtoaddress(addr, 0.1) 109 self.sync_all() 110 111 # Check balance is 0 because of 0 confirmations 112 balance = self.nodes[1].getreceivedbyaddress(addr) 113 assert_equal(balance, Decimal("0.0")) 114 115 # Check balance is 0.1 116 balance = self.nodes[1].getreceivedbyaddress(addr, 0) 117 assert_equal(balance, Decimal("0.1")) 118 119 # Bury Tx under 10 block so it will be returned by the default getreceivedbyaddress 120 self.generate(self.nodes[1], 10) 121 balance = self.nodes[1].getreceivedbyaddress(addr) 122 assert_equal(balance, Decimal("0.1")) 123 124 # Trying to getreceivedby for an address the wallet doesn't own should return an error 125 assert_raises_rpc_error(-4, "Address not found in wallet", self.nodes[0].getreceivedbyaddress, addr) 126 127 # Test multiple transactions to the same address 128 addr_with_multiple_txs = self.nodes[1].getnewaddress() 129 self.nodes[0].sendtoaddress(addr_with_multiple_txs, Decimal("0.1")) 130 self.nodes[0].sendtoaddress(addr_with_multiple_txs, Decimal("0.2")) 131 self.generate(self.nodes[0], 1) 132 balance = self.nodes[1].getreceivedbyaddress(addr_with_multiple_txs) 133 assert_equal(balance, Decimal("0.3")) 134 135 # Test invalid address format error 136 assert_raises_rpc_error(-5, "Invalid Bitcoin address", self.nodes[1].getreceivedbyaddress, "invalid_address") 137 138 self.log.info("listreceivedbylabel + getreceivedbylabel Test") 139 140 # set pre-state 141 label = '' 142 address = self.nodes[1].getnewaddress() 143 test_address(self.nodes[1], address, labels=[label]) 144 received_by_label_json = [r for r in self.nodes[1].listreceivedbylabel() if r["label"] == label][0] 145 balance_by_label = self.nodes[1].getreceivedbylabel(label) 146 147 txid = self.nodes[0].sendtoaddress(addr, 0.1) 148 self.sync_all() 149 150 # getreceivedbylabel returns an error if the wallet doesn't own the label 151 assert_raises_rpc_error(-4, "Label not found in wallet", self.nodes[0].getreceivedbylabel, "dummy") 152 153 # listreceivedbylabel should return received_by_label_json because of 0 confirmations 154 assert_array_result(self.nodes[1].listreceivedbylabel(), 155 {"label": label}, 156 received_by_label_json) 157 158 # getreceivedbylabel should return same balance because of 0 confirmations 159 balance = self.nodes[1].getreceivedbylabel(label) 160 assert_equal(balance, balance_by_label) 161 162 self.generate(self.nodes[1], 10) 163 # listreceivedbylabel should return updated received list 164 assert_array_result(self.nodes[1].listreceivedbylabel(), 165 {"label": label}, 166 {"label": received_by_label_json["label"], "amount": (received_by_label_json["amount"] + Decimal("0.1"))}) 167 168 # getreceivedbylabel should return updated receive total 169 balance = self.nodes[1].getreceivedbylabel(label) 170 assert_equal(balance, balance_by_label + Decimal("0.1")) 171 172 # Create a new label named "mynewlabel" that has a 0 balance 173 address = self.nodes[1].getnewaddress() 174 self.nodes[1].setlabel(address, "mynewlabel") 175 received_by_label_json = [r for r in self.nodes[1].listreceivedbylabel(0, True) if r["label"] == "mynewlabel"][0] 176 177 # Test includeempty of listreceivedbylabel 178 assert_equal(received_by_label_json["amount"], Decimal("0.0")) 179 180 # Test getreceivedbylabel for 0 amount labels 181 balance = self.nodes[1].getreceivedbylabel("mynewlabel") 182 assert_equal(balance, Decimal("0.0")) 183 184 self.log.info("Tests for including coinbase outputs") 185 186 # Generate block reward to address with label 187 label = "label" 188 address = self.nodes[0].getnewaddress(label) 189 190 reward = Decimal("25") 191 self.generatetoaddress(self.nodes[0], 1, address) 192 hash = self.nodes[0].getbestblockhash() 193 194 self.log.info("getreceivedbyaddress returns nothing with defaults") 195 balance = self.nodes[0].getreceivedbyaddress(address) 196 assert_equal(balance, 0) 197 198 self.log.info("getreceivedbyaddress returns block reward when including immature coinbase") 199 balance = self.nodes[0].getreceivedbyaddress(address=address, include_immature_coinbase=True) 200 assert_equal(balance, reward) 201 202 self.log.info("getreceivedbylabel returns nothing with defaults") 203 balance = self.nodes[0].getreceivedbylabel("label") 204 assert_equal(balance, 0) 205 206 self.log.info("getreceivedbylabel returns block reward when including immature coinbase") 207 balance = self.nodes[0].getreceivedbylabel(label="label", include_immature_coinbase=True) 208 assert_equal(balance, reward) 209 210 self.log.info("listreceivedbyaddress does not include address with defaults") 211 assert_array_result(self.nodes[0].listreceivedbyaddress(), 212 {"address": address}, 213 {}, True) 214 215 self.log.info("listreceivedbyaddress includes address when including immature coinbase") 216 assert_array_result(self.nodes[0].listreceivedbyaddress(minconf=1, include_immature_coinbase=True), 217 {"address": address}, 218 {"address": address, "amount": reward}) 219 220 self.log.info("listreceivedbylabel does not include label with defaults") 221 assert_array_result(self.nodes[0].listreceivedbylabel(), 222 {"label": label}, 223 {}, True) 224 225 self.log.info("listreceivedbylabel includes label when including immature coinbase") 226 assert_array_result(self.nodes[0].listreceivedbylabel(minconf=1, include_immature_coinbase=True), 227 {"label": label}, 228 {"label": label, "amount": reward}) 229 230 self.log.info("Generate 100 more blocks") 231 self.generate(self.nodes[0], COINBASE_MATURITY) 232 233 self.log.info("getreceivedbyaddress returns reward with defaults") 234 balance = self.nodes[0].getreceivedbyaddress(address) 235 assert_equal(balance, reward) 236 237 self.log.info("getreceivedbylabel returns reward with defaults") 238 balance = self.nodes[0].getreceivedbylabel("label") 239 assert_equal(balance, reward) 240 241 self.log.info("listreceivedbyaddress includes address with defaults") 242 assert_array_result(self.nodes[0].listreceivedbyaddress(), 243 {"address": address}, 244 {"address": address, "amount": reward}) 245 246 self.log.info("listreceivedbylabel includes label with defaults") 247 assert_array_result(self.nodes[0].listreceivedbylabel(), 248 {"label": label}, 249 {"label": label, "amount": reward}) 250 251 self.log.info("Invalidate block that paid to address") 252 self.nodes[0].invalidateblock(hash) 253 254 self.log.info("getreceivedbyaddress does not include invalidated block when minconf is 0 when including immature coinbase") 255 balance = self.nodes[0].getreceivedbyaddress(address=address, minconf=0, include_immature_coinbase=True) 256 assert_equal(balance, 0) 257 258 self.log.info("getreceivedbylabel does not include invalidated block when minconf is 0 when including immature coinbase") 259 balance = self.nodes[0].getreceivedbylabel(label="label", minconf=0, include_immature_coinbase=True) 260 assert_equal(balance, 0) 261 262 self.log.info("listreceivedbyaddress does not include invalidated block when minconf is 0 when including immature coinbase") 263 assert_array_result(self.nodes[0].listreceivedbyaddress(minconf=0, include_immature_coinbase=True), 264 {"address": address}, 265 {}, True) 266 267 self.log.info("listreceivedbylabel does not include invalidated block when minconf is 0 when including immature coinbase") 268 assert_array_result(self.nodes[0].listreceivedbylabel(minconf=0, include_immature_coinbase=True), 269 {"label": label}, 270 {}, True) 271 272 273 if __name__ == '__main__': 274 ReceivedByTest(__file__).main()