]> Git Repo - VerusCoin.git/blame - qa/rpc-tests/addressindex.py
Merge pull request #97 from miketout/dev
[VerusCoin.git] / qa / rpc-tests / addressindex.py
CommitLineData
68e174e2
LR
1#!/usr/bin/env python
2# Copyright (c) 2019 The Zcash developers
8b78a819
T
3# Distributed under the MIT software license, see the accompanying
4# file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
88d014d0 6# TODO: change addres formats to include in Verus tests
7
68e174e2
LR
8#
9# Test addressindex generation and fetching for insightexplorer
10#
11# RPCs tested here:
8b78a819 12#
68e174e2
LR
13# getaddresstxids
14# getaddressbalance
15# getaddressdeltas
16# getaddressutxos
17# getaddressmempool
8b78a819
T
18#
19
68e174e2
LR
20import sys; assert sys.version_info < (3,), ur"This script does not run under Python 3. Please use Python 2.7.x."
21
8b78a819 22from test_framework.test_framework import BitcoinTestFramework
68e174e2
LR
23
24
25from test_framework.util import (
26 assert_equal,
27 initialize_chain_clean,
28 start_nodes,
29 stop_nodes,
30 connect_nodes,
31)
32
33from test_framework.util import wait_bitcoinds
34
35from test_framework.script import (
36 CScript,
37 OP_HASH160,
38 OP_EQUAL,
39 OP_DUP,
40 OP_DROP,
41)
42
43from test_framework.mininode import COIN, CTransaction
44from test_framework.mininode import CTxIn, CTxOut, COutPoint
45
46from binascii import hexlify
47
8b78a819
T
48
49class AddressIndexTest(BitcoinTestFramework):
50
51 def setup_chain(self):
52 print("Initializing test directory "+self.options.tmpdir)
68e174e2 53 initialize_chain_clean(self.options.tmpdir, 3)
8b78a819
T
54
55 def setup_network(self):
68e174e2
LR
56 # -insightexplorer causes addressindex to be enabled (fAddressIndex = true)
57 args = ('-debug', '-txindex', '-experimentalfeatures', '-insightexplorer')
58 self.nodes = start_nodes(3, self.options.tmpdir, [args] * 3)
8b78a819
T
59 connect_nodes(self.nodes[0], 1)
60 connect_nodes(self.nodes[0], 2)
8b78a819
T
61
62 self.is_network_split = False
63 self.sync_all()
64
65 def run_test(self):
8b78a819 66
68e174e2
LR
67 # helper functions
68 def getaddresstxids(node_index, addresses, start, end):
69 return self.nodes[node_index].getaddresstxids({
70 'addresses': addresses,
71 'start': start,
72 'end': end
73 })
74
75 def getaddressdeltas(node_index, addresses, start, end, chainInfo=None):
76 params = {
77 'addresses': addresses,
78 'start': start,
79 'end': end,
80 }
81 if chainInfo is not None:
82 params.update({'chainInfo': chainInfo})
83 return self.nodes[node_index].getaddressdeltas(params)
84
85 # default received value is the balance value
86 def check_balance(node_index, address, expected_balance, expected_received=None):
87 if isinstance(address, list):
88 bal = self.nodes[node_index].getaddressbalance({'addresses': address})
89 else:
90 bal = self.nodes[node_index].getaddressbalance(address)
91 assert_equal(bal['balance'], expected_balance)
92 if expected_received is None:
93 expected_received = expected_balance
94 assert_equal(bal['received'], expected_received)
95
96 # begin test
8b78a819 97
68e174e2 98 self.nodes[0].generate(105)
8b78a819 99 self.sync_all()
68e174e2
LR
100 assert_equal(self.nodes[0].getbalance(), 5 * 10)
101 assert_equal(self.nodes[1].getblockcount(), 105)
102 assert_equal(self.nodes[1].getbalance(), 0)
8b78a819 103
68e174e2
LR
104 # only the oldest 5; subsequent are not yet mature
105 unspent_txids = [ u['txid'] for u in self.nodes[0].listunspent() ]
106
107 # Currently our only unspents are coinbase transactions, choose any one
108 tx = self.nodes[0].getrawtransaction(unspent_txids[0], 1)
109
110 # It just so happens that the first output is the mining reward,
111 # which has type pay-to-public-key-hash, and the second output
112 # is the founders' reward, which has type pay-to-script-hash.
113 addr_p2pkh = tx['vout'][0]['scriptPubKey']['addresses'][0]
114 addr_p2sh = tx['vout'][1]['scriptPubKey']['addresses'][0]
115
116 # Check that balances from mining are correct (105 blocks mined); in
117 # regtest, all mining rewards from a single call to generate() are sent
118 # to the same pair of addresses.
119 check_balance(1, addr_p2pkh, 105 * 10 * COIN)
120 check_balance(1, addr_p2sh, 105 * 2.5 * COIN)
121
122 # Multiple address arguments, results are the sum
123 check_balance(1, [addr_p2sh, addr_p2pkh], 105 * 12.5 * COIN)
124
125 assert_equal(len(self.nodes[1].getaddresstxids(addr_p2pkh)), 105)
126 assert_equal(len(self.nodes[1].getaddresstxids(addr_p2sh)), 105)
127
128 # only the oldest 5 transactions are in the unspent list,
129 # dup addresses are ignored
130 height_txids = getaddresstxids(1, [addr_p2pkh, addr_p2pkh], 1, 5)
131 assert_equal(sorted(height_txids), sorted(unspent_txids))
132
133 height_txids = getaddresstxids(1, [addr_p2sh], 1, 5)
134 assert_equal(sorted(height_txids), sorted(unspent_txids))
135
136 # each txid should appear only once
137 height_txids = getaddresstxids(1, [addr_p2pkh, addr_p2sh], 1, 5)
138 assert_equal(sorted(height_txids), sorted(unspent_txids))
139
140 # do some transfers, make sure balances are good
141 txids_a1 = []
142 addr1 = self.nodes[1].getnewaddress()
143 expected = 0
144 expected_deltas = [] # for checking getaddressdeltas (below)
145 for i in range(5):
146 # first transaction happens at height 105, mined in block 106
147 txid = self.nodes[0].sendtoaddress(addr1, i + 1)
148 txids_a1.append(txid)
149 self.nodes[0].generate(1)
150 self.sync_all()
151 expected += i + 1
152 expected_deltas.append({
153 'height': 106 + i,
154 'satoshis': (i + 1) * COIN,
155 'txid': txid,
156 })
157 check_balance(1, addr1, expected * COIN)
158 assert_equal(sorted(self.nodes[0].getaddresstxids(addr1)), sorted(txids_a1))
159 assert_equal(sorted(self.nodes[1].getaddresstxids(addr1)), sorted(txids_a1))
160
161 # Restart all nodes to ensure indices are saved to disk and recovered
162 stop_nodes(self.nodes)
163 wait_bitcoinds()
164 self.setup_network()
165
166 bal = self.nodes[1].getaddressbalance(addr1)
167 assert_equal(bal['balance'], expected * COIN)
168 assert_equal(bal['received'], expected * COIN)
169 assert_equal(sorted(self.nodes[0].getaddresstxids(addr1)), sorted(txids_a1))
170 assert_equal(sorted(self.nodes[1].getaddresstxids(addr1)), sorted(txids_a1))
171
172 # Send 3 from addr1, but -- subtlety alert! -- addr1 at this
173 # time has 4 UTXOs, with values 1, 2, 3, 4. Sending value 3 requires
174 # using up the value 4 UTXO, because of the tx fee
175 # (the 3 UTXO isn't quite large enough).
176 #
177 # The txid from sending *from* addr1 is also added to the list of
178 # txids associated with that address (test will verify below).
179
180 addr2 = self.nodes[2].getnewaddress()
181 txid = self.nodes[1].sendtoaddress(addr2, 3)
8b78a819
T
182 self.sync_all()
183
68e174e2
LR
184 # the one tx in the mempool refers to addresses addr1 and addr2,
185 # check that duplicate addresses are processed correctly
186 mempool = self.nodes[0].getaddressmempool({'addresses': [addr2, addr1, addr2]})
187 assert_equal(len(mempool), 3)
8b78a819 188
68e174e2
LR
189 # addr2 (first arg)
190 assert_equal(mempool[0]['address'], addr2)
191 assert_equal(mempool[0]['satoshis'], 3 * COIN)
192 assert_equal(mempool[0]['txid'], txid)
193
194 # addr1 (second arg)
195 assert_equal(mempool[1]['address'], addr1)
196 assert_equal(mempool[1]['satoshis'], (-4) * COIN)
197 assert_equal(mempool[1]['txid'], txid)
198
199 # addr2 (third arg)
200 assert_equal(mempool[2]['address'], addr2)
201 assert_equal(mempool[2]['satoshis'], 3 * COIN)
202 assert_equal(mempool[2]['txid'], txid)
203
204 # a single address can be specified as a string (not json object)
205 assert_equal([mempool[1]], self.nodes[0].getaddressmempool(addr1))
206
86b23f37
LR
207 tx = self.nodes[0].getrawtransaction(txid, 1)
208 assert_equal(tx['vin'][0]['address'], addr1)
209 assert_equal(tx['vin'][0]['value'], 4)
210 assert_equal(tx['vin'][0]['valueSat'], 4 * COIN)
211
68e174e2
LR
212 txids_a1.append(txid)
213 expected_deltas.append({
214 'height': 111,
215 'satoshis': (-4) * COIN,
216 'txid': txid,
217 })
218 self.sync_all() # ensure transaction is included in the next block
8b78a819
T
219 self.nodes[0].generate(1)
220 self.sync_all()
221
68e174e2
LR
222 # the send to addr2 tx is now in a mined block, no longer in the mempool
223 mempool = self.nodes[0].getaddressmempool({'addresses': [addr2, addr1]})
224 assert_equal(len(mempool), 0)
8b78a819 225
68e174e2
LR
226 # Test DisconnectBlock() by invalidating the most recent mined block
227 tip = self.nodes[1].getchaintips()[0]
228 for i in range(3):
229 node = self.nodes[i]
230 # the value 4 UTXO is no longer in our balance
231 check_balance(i, addr1, (expected - 4) * COIN, expected * COIN)
232 check_balance(i, addr2, 3 * COIN)
8b78a819 233
68e174e2
LR
234 assert_equal(node.getblockcount(), 111)
235 node.invalidateblock(tip['hash'])
236 assert_equal(node.getblockcount(), 110)
8b78a819 237
68e174e2
LR
238 mempool = node.getaddressmempool({'addresses': [addr2, addr1]})
239 assert_equal(len(mempool), 2)
8b78a819 240
68e174e2
LR
241 check_balance(i, addr1, expected * COIN)
242 check_balance(i, addr2, 0)
8b78a819 243
68e174e2 244 # now re-mine the addr1 to addr2 send
8b78a819
T
245 self.nodes[0].generate(1)
246 self.sync_all()
68e174e2
LR
247 for node in self.nodes:
248 assert_equal(node.getblockcount(), 111)
249
250 mempool = self.nodes[0].getaddressmempool({'addresses': [addr2, addr1]})
251 assert_equal(len(mempool), 0)
252
253 # the value 4 UTXO is no longer in our balance
254 check_balance(2, addr1, (expected - 4) * COIN, expected * COIN)
255
256 # Ensure the change from that transaction appears
257 tx = self.nodes[0].getrawtransaction(txid, 1)
258 change_vout = filter(lambda v: v['valueZat'] != 3 * COIN, tx['vout'])
259 change = change_vout[0]['scriptPubKey']['addresses'][0]
260 bal = self.nodes[2].getaddressbalance(change)
261 assert(bal['received'] > 0)
262 # the inequality is due to randomness in the tx fee
263 assert(bal['received'] < (4 - 3) * COIN)
264 assert_equal(bal['received'], bal['balance'])
265 assert_equal(self.nodes[2].getaddresstxids(change), [txid])
266
267 # Further checks that limiting by height works
268
269 # various ranges
270 for i in range(5):
271 height_txids = getaddresstxids(1, [addr1], 106, 106 + i)
272 assert_equal(height_txids, txids_a1[0:i+1])
273
274 height_txids = getaddresstxids(1, [addr1], 1, 108)
275 assert_equal(height_txids, txids_a1[0:3])
276
277 # Further check specifying multiple addresses
278 txids_all = list(txids_a1)
279 txids_all += self.nodes[1].getaddresstxids(addr_p2pkh)
280 txids_all += self.nodes[1].getaddresstxids(addr_p2sh)
281 multitxids = self.nodes[1].getaddresstxids({
282 'addresses': [addr1, addr_p2sh, addr_p2pkh]
283 })
284 # No dups in return list from getaddresstxids
285 assert_equal(len(multitxids), len(set(multitxids)))
286
287 # set(txids_all) removes its (expected) duplicates
288 assert_equal(set(multitxids), set(txids_all))
289
290 deltas = self.nodes[1].getaddressdeltas({'addresses': [addr1]})
291 assert_equal(len(deltas), len(expected_deltas))
292 for i in range(len(deltas)):
293 assert_equal(deltas[i]['address'], addr1)
294 assert_equal(deltas[i]['height'], expected_deltas[i]['height'])
295 assert_equal(deltas[i]['satoshis'], expected_deltas[i]['satoshis'])
296 assert_equal(deltas[i]['txid'], expected_deltas[i]['txid'])
297
298 # 106-111 is the full range (also the default)
299 deltas_limited = getaddressdeltas(1, [addr1], 106, 111)
300 assert_equal(deltas_limited, deltas)
301
302 # only the first element missing
303 deltas_limited = getaddressdeltas(1, [addr1], 107, 111)
304 assert_equal(deltas_limited, deltas[1:])
305
306 deltas_limited = getaddressdeltas(1, [addr1], 109, 109)
307 assert_equal(deltas_limited, deltas[3:4])
308
309 # the full range (also the default)
310 deltas_info = getaddressdeltas(1, [addr1], 106, 111, chainInfo=True)
311 assert_equal(deltas_info['deltas'], deltas)
312
313 # check the additional items returned by chainInfo
314 assert_equal(deltas_info['start']['height'], 106)
315 block_hash = self.nodes[1].getblockhash(106)
316 assert_equal(deltas_info['start']['hash'], block_hash)
317
318 assert_equal(deltas_info['end']['height'], 111)
319 block_hash = self.nodes[1].getblockhash(111)
320 assert_equal(deltas_info['end']['hash'], block_hash)
321
322 # Test getaddressutxos by comparing results with deltas
323 utxos = self.nodes[1].getaddressutxos(addr1)
324
325 # The value 4 note was spent, so won't show up in the utxo list,
326 # so for comparison, remove the 4 (and -4 for output) from the
327 # deltas list
328 deltas = self.nodes[1].getaddressdeltas({'addresses': [addr1]})
329 deltas = filter(lambda d: abs(d['satoshis']) != 4 * COIN, deltas)
330 assert_equal(len(utxos), len(deltas))
331 for i in range(len(utxos)):
332 assert_equal(utxos[i]['address'], addr1)
333 assert_equal(utxos[i]['height'], deltas[i]['height'])
334 assert_equal(utxos[i]['satoshis'], deltas[i]['satoshis'])
335 assert_equal(utxos[i]['txid'], deltas[i]['txid'])
336
337 # Check that outputs with the same address in the same tx return one txid
338 # (can't use createrawtransaction() as it combines duplicate addresses)
339 addr = "t2LMJ6Arw9UWBMWvfUr2QLHM4Xd9w53FftS"
340 addressHash = "97643ce74b188f4fb6bbbb285e067a969041caf2".decode('hex')
341 scriptPubKey = CScript([OP_HASH160, addressHash, OP_EQUAL])
342 # Add an unrecognized script type to vout[], a legal script that pays,
343 # but won't modify the addressindex (since the address can't be extracted).
344 # (This extra output has no effect on the rest of the test.)
345 scriptUnknown = CScript([OP_HASH160, OP_DUP, OP_DROP, addressHash, OP_EQUAL])
346 unspent = filter(lambda u: u['amount'] >= 4, self.nodes[0].listunspent())
8b78a819 347 tx = CTransaction()
68e174e2
LR
348 tx.vin = [CTxIn(COutPoint(int(unspent[0]['txid'], 16), unspent[0]['vout']))]
349 tx.vout = [
350 CTxOut(1 * COIN, scriptPubKey),
351 CTxOut(2 * COIN, scriptPubKey),
352 CTxOut(7 * COIN, scriptUnknown),
8b78a819 353 ]
68e174e2
LR
354 tx = self.nodes[0].signrawtransaction(hexlify(tx.serialize()).decode('utf-8'))
355 txid = self.nodes[0].sendrawtransaction(tx['hex'], True)
356 self.nodes[0].generate(1)
8b78a819 357 self.sync_all()
8b78a819 358
68e174e2
LR
359 assert_equal(self.nodes[1].getaddresstxids(addr), [txid])
360 check_balance(2, addr, 3 * COIN)
8b78a819
T
361
362
363if __name__ == '__main__':
68e174e2 364 AddressIndexTest().main()
This page took 0.212571 seconds and 4 git commands to generate.