/ test / functional / wallet_listreceivedby.py
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()