2 # Copyright (c) 2014-2016 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 importmulti RPC."""
6 from test_framework
.test_framework
import BitcoinTestFramework
7 from test_framework
.util
import *
9 class ImportMultiTest (BitcoinTestFramework
):
10 def set_test_params(self
):
12 self
.setup_clean_chain
= True
14 def setup_network(self
):
18 self
.log
.info("Mining blocks...")
19 self
.nodes
[0].generate(1)
20 self
.nodes
[1].generate(1)
21 timestamp
= self
.nodes
[1].getblock(self
.nodes
[1].getbestblockhash())['mediantime']
23 node0_address1
= self
.nodes
[0].validateaddress(self
.nodes
[0].getnewaddress())
25 #Check only one address
26 assert_equal(node0_address1
['ismine'], True)
29 assert_equal(self
.nodes
[1].getblockcount(),1)
31 #Address Test - before import
32 address_info
= self
.nodes
[1].validateaddress(node0_address1
['address'])
33 assert_equal(address_info
['iswatchonly'], False)
34 assert_equal(address_info
['ismine'], False)
37 # RPC importmulti -----------------------------------------------
40 self
.log
.info("Should import an address")
41 address
= self
.nodes
[0].validateaddress(self
.nodes
[0].getnewaddress())
42 result
= self
.nodes
[1].importmulti([{
44 "address": address
['address']
48 assert_equal(result
[0]['success'], True)
49 address_assert
= self
.nodes
[1].validateaddress(address
['address'])
50 assert_equal(address_assert
['iswatchonly'], True)
51 assert_equal(address_assert
['ismine'], False)
52 assert_equal(address_assert
['timestamp'], timestamp
)
53 watchonly_address
= address
['address']
54 watchonly_timestamp
= timestamp
56 self
.log
.info("Should not import an invalid address")
57 result
= self
.nodes
[1].importmulti([{
59 "address": "not valid address",
63 assert_equal(result
[0]['success'], False)
64 assert_equal(result
[0]['error']['code'], -5)
65 assert_equal(result
[0]['error']['message'], 'Invalid address')
67 # ScriptPubKey + internal
68 self
.log
.info("Should import a scriptPubKey with internal flag")
69 address
= self
.nodes
[0].validateaddress(self
.nodes
[0].getnewaddress())
70 result
= self
.nodes
[1].importmulti([{
71 "scriptPubKey": address
['scriptPubKey'],
75 assert_equal(result
[0]['success'], True)
76 address_assert
= self
.nodes
[1].validateaddress(address
['address'])
77 assert_equal(address_assert
['iswatchonly'], True)
78 assert_equal(address_assert
['ismine'], False)
79 assert_equal(address_assert
['timestamp'], timestamp
)
81 # ScriptPubKey + !internal
82 self
.log
.info("Should not import a scriptPubKey without internal flag")
83 address
= self
.nodes
[0].validateaddress(self
.nodes
[0].getnewaddress())
84 result
= self
.nodes
[1].importmulti([{
85 "scriptPubKey": address
['scriptPubKey'],
88 assert_equal(result
[0]['success'], False)
89 assert_equal(result
[0]['error']['code'], -8)
90 assert_equal(result
[0]['error']['message'], 'Internal must be set for hex scriptPubKey')
91 address_assert
= self
.nodes
[1].validateaddress(address
['address'])
92 assert_equal(address_assert
['iswatchonly'], False)
93 assert_equal(address_assert
['ismine'], False)
94 assert_equal('timestamp' in address_assert
, False)
97 # Address + Public key + !Internal
98 self
.log
.info("Should import an address with public key")
99 address
= self
.nodes
[0].validateaddress(self
.nodes
[0].getnewaddress())
100 result
= self
.nodes
[1].importmulti([{
102 "address": address
['address']
105 "pubkeys": [ address
['pubkey'] ]
107 assert_equal(result
[0]['success'], True)
108 address_assert
= self
.nodes
[1].validateaddress(address
['address'])
109 assert_equal(address_assert
['iswatchonly'], True)
110 assert_equal(address_assert
['ismine'], False)
111 assert_equal(address_assert
['timestamp'], timestamp
)
114 # ScriptPubKey + Public key + internal
115 self
.log
.info("Should import a scriptPubKey with internal and with public key")
116 address
= self
.nodes
[0].validateaddress(self
.nodes
[0].getnewaddress())
118 "scriptPubKey": address
['scriptPubKey'],
120 "pubkeys": [ address
['pubkey'] ],
123 result
= self
.nodes
[1].importmulti(request
)
124 assert_equal(result
[0]['success'], True)
125 address_assert
= self
.nodes
[1].validateaddress(address
['address'])
126 assert_equal(address_assert
['iswatchonly'], True)
127 assert_equal(address_assert
['ismine'], False)
128 assert_equal(address_assert
['timestamp'], timestamp
)
130 # ScriptPubKey + Public key + !internal
131 self
.log
.info("Should not import a scriptPubKey without internal and with public key")
132 address
= self
.nodes
[0].validateaddress(self
.nodes
[0].getnewaddress())
134 "scriptPubKey": address
['scriptPubKey'],
136 "pubkeys": [ address
['pubkey'] ]
138 result
= self
.nodes
[1].importmulti(request
)
139 assert_equal(result
[0]['success'], False)
140 assert_equal(result
[0]['error']['code'], -8)
141 assert_equal(result
[0]['error']['message'], 'Internal must be set for hex scriptPubKey')
142 address_assert
= self
.nodes
[1].validateaddress(address
['address'])
143 assert_equal(address_assert
['iswatchonly'], False)
144 assert_equal(address_assert
['ismine'], False)
145 assert_equal('timestamp' in address_assert
, False)
147 # Address + Private key + !watchonly
148 self
.log
.info("Should import an address with private key")
149 address
= self
.nodes
[0].validateaddress(self
.nodes
[0].getnewaddress())
150 result
= self
.nodes
[1].importmulti([{
152 "address": address
['address']
155 "keys": [ self
.nodes
[0].dumpprivkey(address
['address']) ]
157 assert_equal(result
[0]['success'], True)
158 address_assert
= self
.nodes
[1].validateaddress(address
['address'])
159 assert_equal(address_assert
['iswatchonly'], False)
160 assert_equal(address_assert
['ismine'], True)
161 assert_equal(address_assert
['timestamp'], timestamp
)
163 self
.log
.info("Should not import an address with private key if is already imported")
164 result
= self
.nodes
[1].importmulti([{
166 "address": address
['address']
169 "keys": [ self
.nodes
[0].dumpprivkey(address
['address']) ]
171 assert_equal(result
[0]['success'], False)
172 assert_equal(result
[0]['error']['code'], -4)
173 assert_equal(result
[0]['error']['message'], 'The wallet already contains the private key for this address or script')
175 # Address + Private key + watchonly
176 self
.log
.info("Should not import an address with private key and with watchonly")
177 address
= self
.nodes
[0].validateaddress(self
.nodes
[0].getnewaddress())
178 result
= self
.nodes
[1].importmulti([{
180 "address": address
['address']
183 "keys": [ self
.nodes
[0].dumpprivkey(address
['address']) ],
186 assert_equal(result
[0]['success'], False)
187 assert_equal(result
[0]['error']['code'], -8)
188 assert_equal(result
[0]['error']['message'], 'Incompatibility found between watchonly and keys')
189 address_assert
= self
.nodes
[1].validateaddress(address
['address'])
190 assert_equal(address_assert
['iswatchonly'], False)
191 assert_equal(address_assert
['ismine'], False)
192 assert_equal('timestamp' in address_assert
, False)
194 # ScriptPubKey + Private key + internal
195 self
.log
.info("Should import a scriptPubKey with internal and with private key")
196 address
= self
.nodes
[0].validateaddress(self
.nodes
[0].getnewaddress())
197 result
= self
.nodes
[1].importmulti([{
198 "scriptPubKey": address
['scriptPubKey'],
200 "keys": [ self
.nodes
[0].dumpprivkey(address
['address']) ],
203 assert_equal(result
[0]['success'], True)
204 address_assert
= self
.nodes
[1].validateaddress(address
['address'])
205 assert_equal(address_assert
['iswatchonly'], False)
206 assert_equal(address_assert
['ismine'], True)
207 assert_equal(address_assert
['timestamp'], timestamp
)
209 # ScriptPubKey + Private key + !internal
210 self
.log
.info("Should not import a scriptPubKey without internal and with private key")
211 address
= self
.nodes
[0].validateaddress(self
.nodes
[0].getnewaddress())
212 result
= self
.nodes
[1].importmulti([{
213 "scriptPubKey": address
['scriptPubKey'],
215 "keys": [ self
.nodes
[0].dumpprivkey(address
['address']) ]
217 assert_equal(result
[0]['success'], False)
218 assert_equal(result
[0]['error']['code'], -8)
219 assert_equal(result
[0]['error']['message'], 'Internal must be set for hex scriptPubKey')
220 address_assert
= self
.nodes
[1].validateaddress(address
['address'])
221 assert_equal(address_assert
['iswatchonly'], False)
222 assert_equal(address_assert
['ismine'], False)
223 assert_equal('timestamp' in address_assert
, False)
227 sig_address_1
= self
.nodes
[0].validateaddress(self
.nodes
[0].getnewaddress())
228 sig_address_2
= self
.nodes
[0].validateaddress(self
.nodes
[0].getnewaddress())
229 sig_address_3
= self
.nodes
[0].validateaddress(self
.nodes
[0].getnewaddress())
230 multi_sig_script
= self
.nodes
[0].createmultisig(2, [sig_address_1
['address'], sig_address_2
['address'], sig_address_3
['pubkey']])
231 self
.nodes
[1].generate(100)
232 transactionid
= self
.nodes
[1].sendtoaddress(multi_sig_script
['address'], 10.00)
233 self
.nodes
[1].generate(1)
234 timestamp
= self
.nodes
[1].getblock(self
.nodes
[1].getbestblockhash())['mediantime']
236 self
.log
.info("Should import a p2sh")
237 result
= self
.nodes
[1].importmulti([{
239 "address": multi_sig_script
['address']
243 assert_equal(result
[0]['success'], True)
244 address_assert
= self
.nodes
[1].validateaddress(multi_sig_script
['address'])
245 assert_equal(address_assert
['isscript'], True)
246 assert_equal(address_assert
['iswatchonly'], True)
247 assert_equal(address_assert
['timestamp'], timestamp
)
248 p2shunspent
= self
.nodes
[1].listunspent(0,999999, [multi_sig_script
['address']])[0]
249 assert_equal(p2shunspent
['spendable'], False)
250 assert_equal(p2shunspent
['solvable'], False)
253 # P2SH + Redeem script
254 sig_address_1
= self
.nodes
[0].validateaddress(self
.nodes
[0].getnewaddress())
255 sig_address_2
= self
.nodes
[0].validateaddress(self
.nodes
[0].getnewaddress())
256 sig_address_3
= self
.nodes
[0].validateaddress(self
.nodes
[0].getnewaddress())
257 multi_sig_script
= self
.nodes
[0].createmultisig(2, [sig_address_1
['address'], sig_address_2
['address'], sig_address_3
['pubkey']])
258 self
.nodes
[1].generate(100)
259 transactionid
= self
.nodes
[1].sendtoaddress(multi_sig_script
['address'], 10.00)
260 self
.nodes
[1].generate(1)
261 timestamp
= self
.nodes
[1].getblock(self
.nodes
[1].getbestblockhash())['mediantime']
263 self
.log
.info("Should import a p2sh with respective redeem script")
264 result
= self
.nodes
[1].importmulti([{
266 "address": multi_sig_script
['address']
269 "redeemscript": multi_sig_script
['redeemScript']
271 assert_equal(result
[0]['success'], True)
272 address_assert
= self
.nodes
[1].validateaddress(multi_sig_script
['address'])
273 assert_equal(address_assert
['timestamp'], timestamp
)
275 p2shunspent
= self
.nodes
[1].listunspent(0,999999, [multi_sig_script
['address']])[0]
276 assert_equal(p2shunspent
['spendable'], False)
277 assert_equal(p2shunspent
['solvable'], True)
280 # P2SH + Redeem script + Private Keys + !Watchonly
281 sig_address_1
= self
.nodes
[0].validateaddress(self
.nodes
[0].getnewaddress())
282 sig_address_2
= self
.nodes
[0].validateaddress(self
.nodes
[0].getnewaddress())
283 sig_address_3
= self
.nodes
[0].validateaddress(self
.nodes
[0].getnewaddress())
284 multi_sig_script
= self
.nodes
[0].createmultisig(2, [sig_address_1
['address'], sig_address_2
['address'], sig_address_3
['pubkey']])
285 self
.nodes
[1].generate(100)
286 transactionid
= self
.nodes
[1].sendtoaddress(multi_sig_script
['address'], 10.00)
287 self
.nodes
[1].generate(1)
288 timestamp
= self
.nodes
[1].getblock(self
.nodes
[1].getbestblockhash())['mediantime']
290 self
.log
.info("Should import a p2sh with respective redeem script and private keys")
291 result
= self
.nodes
[1].importmulti([{
293 "address": multi_sig_script
['address']
296 "redeemscript": multi_sig_script
['redeemScript'],
297 "keys": [ self
.nodes
[0].dumpprivkey(sig_address_1
['address']), self
.nodes
[0].dumpprivkey(sig_address_2
['address'])]
299 assert_equal(result
[0]['success'], True)
300 address_assert
= self
.nodes
[1].validateaddress(multi_sig_script
['address'])
301 assert_equal(address_assert
['timestamp'], timestamp
)
303 p2shunspent
= self
.nodes
[1].listunspent(0,999999, [multi_sig_script
['address']])[0]
304 assert_equal(p2shunspent
['spendable'], False)
305 assert_equal(p2shunspent
['solvable'], True)
307 # P2SH + Redeem script + Private Keys + Watchonly
308 sig_address_1
= self
.nodes
[0].validateaddress(self
.nodes
[0].getnewaddress())
309 sig_address_2
= self
.nodes
[0].validateaddress(self
.nodes
[0].getnewaddress())
310 sig_address_3
= self
.nodes
[0].validateaddress(self
.nodes
[0].getnewaddress())
311 multi_sig_script
= self
.nodes
[0].createmultisig(2, [sig_address_1
['address'], sig_address_2
['address'], sig_address_3
['pubkey']])
312 self
.nodes
[1].generate(100)
313 transactionid
= self
.nodes
[1].sendtoaddress(multi_sig_script
['address'], 10.00)
314 self
.nodes
[1].generate(1)
315 timestamp
= self
.nodes
[1].getblock(self
.nodes
[1].getbestblockhash())['mediantime']
317 self
.log
.info("Should import a p2sh with respective redeem script and private keys")
318 result
= self
.nodes
[1].importmulti([{
320 "address": multi_sig_script
['address']
323 "redeemscript": multi_sig_script
['redeemScript'],
324 "keys": [ self
.nodes
[0].dumpprivkey(sig_address_1
['address']), self
.nodes
[0].dumpprivkey(sig_address_2
['address'])],
327 assert_equal(result
[0]['success'], False)
328 assert_equal(result
[0]['error']['code'], -8)
329 assert_equal(result
[0]['error']['message'], 'Incompatibility found between watchonly and keys')
332 # Address + Public key + !Internal + Wrong pubkey
333 self
.log
.info("Should not import an address with a wrong public key")
334 address
= self
.nodes
[0].validateaddress(self
.nodes
[0].getnewaddress())
335 address2
= self
.nodes
[0].validateaddress(self
.nodes
[0].getnewaddress())
336 result
= self
.nodes
[1].importmulti([{
338 "address": address
['address']
341 "pubkeys": [ address2
['pubkey'] ]
343 assert_equal(result
[0]['success'], False)
344 assert_equal(result
[0]['error']['code'], -5)
345 assert_equal(result
[0]['error']['message'], 'Consistency check failed')
346 address_assert
= self
.nodes
[1].validateaddress(address
['address'])
347 assert_equal(address_assert
['iswatchonly'], False)
348 assert_equal(address_assert
['ismine'], False)
349 assert_equal('timestamp' in address_assert
, False)
352 # ScriptPubKey + Public key + internal + Wrong pubkey
353 self
.log
.info("Should not import a scriptPubKey with internal and with a wrong public key")
354 address
= self
.nodes
[0].validateaddress(self
.nodes
[0].getnewaddress())
355 address2
= self
.nodes
[0].validateaddress(self
.nodes
[0].getnewaddress())
357 "scriptPubKey": address
['scriptPubKey'],
359 "pubkeys": [ address2
['pubkey'] ],
362 result
= self
.nodes
[1].importmulti(request
)
363 assert_equal(result
[0]['success'], False)
364 assert_equal(result
[0]['error']['code'], -5)
365 assert_equal(result
[0]['error']['message'], 'Consistency check failed')
366 address_assert
= self
.nodes
[1].validateaddress(address
['address'])
367 assert_equal(address_assert
['iswatchonly'], False)
368 assert_equal(address_assert
['ismine'], False)
369 assert_equal('timestamp' in address_assert
, False)
372 # Address + Private key + !watchonly + Wrong private key
373 self
.log
.info("Should not import an address with a wrong private key")
374 address
= self
.nodes
[0].validateaddress(self
.nodes
[0].getnewaddress())
375 address2
= self
.nodes
[0].validateaddress(self
.nodes
[0].getnewaddress())
376 result
= self
.nodes
[1].importmulti([{
378 "address": address
['address']
381 "keys": [ self
.nodes
[0].dumpprivkey(address2
['address']) ]
383 assert_equal(result
[0]['success'], False)
384 assert_equal(result
[0]['error']['code'], -5)
385 assert_equal(result
[0]['error']['message'], 'Consistency check failed')
386 address_assert
= self
.nodes
[1].validateaddress(address
['address'])
387 assert_equal(address_assert
['iswatchonly'], False)
388 assert_equal(address_assert
['ismine'], False)
389 assert_equal('timestamp' in address_assert
, False)
392 # ScriptPubKey + Private key + internal + Wrong private key
393 self
.log
.info("Should not import a scriptPubKey with internal and with a wrong private key")
394 address
= self
.nodes
[0].validateaddress(self
.nodes
[0].getnewaddress())
395 address2
= self
.nodes
[0].validateaddress(self
.nodes
[0].getnewaddress())
396 result
= self
.nodes
[1].importmulti([{
397 "scriptPubKey": address
['scriptPubKey'],
399 "keys": [ self
.nodes
[0].dumpprivkey(address2
['address']) ],
402 assert_equal(result
[0]['success'], False)
403 assert_equal(result
[0]['error']['code'], -5)
404 assert_equal(result
[0]['error']['message'], 'Consistency check failed')
405 address_assert
= self
.nodes
[1].validateaddress(address
['address'])
406 assert_equal(address_assert
['iswatchonly'], False)
407 assert_equal(address_assert
['ismine'], False)
408 assert_equal('timestamp' in address_assert
, False)
411 # Importing existing watch only address with new timestamp should replace saved timestamp.
412 assert_greater_than(timestamp
, watchonly_timestamp
)
413 self
.log
.info("Should replace previously saved watch only timestamp.")
414 result
= self
.nodes
[1].importmulti([{
416 "address": watchonly_address
,
420 assert_equal(result
[0]['success'], True)
421 address_assert
= self
.nodes
[1].validateaddress(watchonly_address
)
422 assert_equal(address_assert
['iswatchonly'], True)
423 assert_equal(address_assert
['ismine'], False)
424 assert_equal(address_assert
['timestamp'], timestamp
)
425 watchonly_timestamp
= timestamp
428 # restart nodes to check for proper serialization/deserialization of watch only address
431 address_assert
= self
.nodes
[1].validateaddress(watchonly_address
)
432 assert_equal(address_assert
['iswatchonly'], True)
433 assert_equal(address_assert
['ismine'], False)
434 assert_equal(address_assert
['timestamp'], watchonly_timestamp
)
436 # Bad or missing timestamps
437 self
.log
.info("Should throw on invalid or missing timestamp values")
438 assert_raises_rpc_error(-3, 'Missing required timestamp field for key',
439 self
.nodes
[1].importmulti
, [{
440 "scriptPubKey": address
['scriptPubKey'],
442 assert_raises_rpc_error(-3, 'Expected number or "now" timestamp value for key. got type string',
443 self
.nodes
[1].importmulti
, [{
444 "scriptPubKey": address
['scriptPubKey'],
449 if __name__
== '__main__':
450 ImportMultiTest ().main ()