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