mirror of
https://github.com/dashpay/dash.git
synced 2024-12-26 12:32:48 +01:00
43f697866e
a80f98b
Use importmulti timestamp when importing watch only keys (Russell Yanofsky)a58370e
Dedup nTimeFirstKey update logic (Russell Yanofsky)
435 lines
20 KiB
Python
Executable File
435 lines
20 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# Copyright (c) 2014-2016 The Bitcoin Core developers
|
|
# Distributed under the MIT software license, see the accompanying
|
|
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
from test_framework.test_framework import BitcoinTestFramework
|
|
from test_framework.util import *
|
|
|
|
class ImportMultiTest (BitcoinTestFramework):
|
|
def __init__(self):
|
|
super().__init__()
|
|
self.num_nodes = 2
|
|
self.setup_clean_chain = True
|
|
|
|
def setup_network(self, split=False):
|
|
self.nodes = start_nodes(2, self.options.tmpdir)
|
|
self.is_network_split=False
|
|
|
|
def run_test (self):
|
|
print ("Mining blocks...")
|
|
self.nodes[0].generate(1)
|
|
self.nodes[1].generate(1)
|
|
timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
|
|
|
|
# keyword definition
|
|
PRIV_KEY = 'privkey'
|
|
PUB_KEY = 'pubkey'
|
|
ADDRESS_KEY = 'address'
|
|
SCRIPT_KEY = 'script'
|
|
|
|
|
|
node0_address1 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
|
node0_address2 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
|
node0_address3 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
|
|
|
#Check only one address
|
|
assert_equal(node0_address1['ismine'], True)
|
|
|
|
#Node 1 sync test
|
|
assert_equal(self.nodes[1].getblockcount(),1)
|
|
|
|
#Address Test - before import
|
|
address_info = self.nodes[1].validateaddress(node0_address1['address'])
|
|
assert_equal(address_info['iswatchonly'], False)
|
|
assert_equal(address_info['ismine'], False)
|
|
|
|
|
|
# RPC importmulti -----------------------------------------------
|
|
|
|
# Bitcoin Address
|
|
print("Should import an address")
|
|
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
|
result = self.nodes[1].importmulti([{
|
|
"scriptPubKey": {
|
|
"address": address['address']
|
|
},
|
|
"timestamp": "now",
|
|
}])
|
|
assert_equal(result[0]['success'], True)
|
|
address_assert = self.nodes[1].validateaddress(address['address'])
|
|
assert_equal(address_assert['iswatchonly'], True)
|
|
assert_equal(address_assert['ismine'], False)
|
|
assert_equal(address_assert['timestamp'], timestamp)
|
|
watchonly_address = address['address']
|
|
watchonly_timestamp = timestamp
|
|
|
|
print("Should not import an invalid address")
|
|
result = self.nodes[1].importmulti([{
|
|
"scriptPubKey": {
|
|
"address": "not valid address",
|
|
},
|
|
"timestamp": "now",
|
|
}])
|
|
assert_equal(result[0]['success'], False)
|
|
assert_equal(result[0]['error']['code'], -5)
|
|
assert_equal(result[0]['error']['message'], 'Invalid address')
|
|
|
|
# ScriptPubKey + internal
|
|
print("Should import a scriptPubKey with internal flag")
|
|
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
|
result = self.nodes[1].importmulti([{
|
|
"scriptPubKey": address['scriptPubKey'],
|
|
"timestamp": "now",
|
|
"internal": True
|
|
}])
|
|
assert_equal(result[0]['success'], True)
|
|
address_assert = self.nodes[1].validateaddress(address['address'])
|
|
assert_equal(address_assert['iswatchonly'], True)
|
|
assert_equal(address_assert['ismine'], False)
|
|
assert_equal(address_assert['timestamp'], timestamp)
|
|
|
|
# ScriptPubKey + !internal
|
|
print("Should not import a scriptPubKey without internal flag")
|
|
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
|
result = self.nodes[1].importmulti([{
|
|
"scriptPubKey": address['scriptPubKey'],
|
|
"timestamp": "now",
|
|
}])
|
|
assert_equal(result[0]['success'], False)
|
|
assert_equal(result[0]['error']['code'], -8)
|
|
assert_equal(result[0]['error']['message'], 'Internal must be set for hex scriptPubKey')
|
|
address_assert = self.nodes[1].validateaddress(address['address'])
|
|
assert_equal(address_assert['iswatchonly'], False)
|
|
assert_equal(address_assert['ismine'], False)
|
|
assert_equal('timestamp' in address_assert, False)
|
|
|
|
|
|
# Address + Public key + !Internal
|
|
print("Should import an address with public key")
|
|
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
|
result = self.nodes[1].importmulti([{
|
|
"scriptPubKey": {
|
|
"address": address['address']
|
|
},
|
|
"timestamp": "now",
|
|
"pubkeys": [ address['pubkey'] ]
|
|
}])
|
|
assert_equal(result[0]['success'], True)
|
|
address_assert = self.nodes[1].validateaddress(address['address'])
|
|
assert_equal(address_assert['iswatchonly'], True)
|
|
assert_equal(address_assert['ismine'], False)
|
|
assert_equal(address_assert['timestamp'], timestamp)
|
|
|
|
|
|
# ScriptPubKey + Public key + internal
|
|
print("Should import a scriptPubKey with internal and with public key")
|
|
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
|
request = [{
|
|
"scriptPubKey": address['scriptPubKey'],
|
|
"timestamp": "now",
|
|
"pubkeys": [ address['pubkey'] ],
|
|
"internal": True
|
|
}]
|
|
result = self.nodes[1].importmulti(request)
|
|
assert_equal(result[0]['success'], True)
|
|
address_assert = self.nodes[1].validateaddress(address['address'])
|
|
assert_equal(address_assert['iswatchonly'], True)
|
|
assert_equal(address_assert['ismine'], False)
|
|
assert_equal(address_assert['timestamp'], timestamp)
|
|
|
|
# ScriptPubKey + Public key + !internal
|
|
print("Should not import a scriptPubKey without internal and with public key")
|
|
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
|
request = [{
|
|
"scriptPubKey": address['scriptPubKey'],
|
|
"timestamp": "now",
|
|
"pubkeys": [ address['pubkey'] ]
|
|
}]
|
|
result = self.nodes[1].importmulti(request)
|
|
assert_equal(result[0]['success'], False)
|
|
assert_equal(result[0]['error']['code'], -8)
|
|
assert_equal(result[0]['error']['message'], 'Internal must be set for hex scriptPubKey')
|
|
address_assert = self.nodes[1].validateaddress(address['address'])
|
|
assert_equal(address_assert['iswatchonly'], False)
|
|
assert_equal(address_assert['ismine'], False)
|
|
assert_equal('timestamp' in address_assert, False)
|
|
|
|
# Address + Private key + !watchonly
|
|
print("Should import an address with private key")
|
|
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
|
result = self.nodes[1].importmulti([{
|
|
"scriptPubKey": {
|
|
"address": address['address']
|
|
},
|
|
"timestamp": "now",
|
|
"keys": [ self.nodes[0].dumpprivkey(address['address']) ]
|
|
}])
|
|
assert_equal(result[0]['success'], True)
|
|
address_assert = self.nodes[1].validateaddress(address['address'])
|
|
assert_equal(address_assert['iswatchonly'], False)
|
|
assert_equal(address_assert['ismine'], True)
|
|
assert_equal(address_assert['timestamp'], timestamp)
|
|
|
|
# Address + Private key + watchonly
|
|
print("Should not import an address with private key and with watchonly")
|
|
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
|
result = self.nodes[1].importmulti([{
|
|
"scriptPubKey": {
|
|
"address": address['address']
|
|
},
|
|
"timestamp": "now",
|
|
"keys": [ self.nodes[0].dumpprivkey(address['address']) ],
|
|
"watchonly": True
|
|
}])
|
|
assert_equal(result[0]['success'], False)
|
|
assert_equal(result[0]['error']['code'], -8)
|
|
assert_equal(result[0]['error']['message'], 'Incompatibility found between watchonly and keys')
|
|
address_assert = self.nodes[1].validateaddress(address['address'])
|
|
assert_equal(address_assert['iswatchonly'], False)
|
|
assert_equal(address_assert['ismine'], False)
|
|
assert_equal('timestamp' in address_assert, False)
|
|
|
|
# ScriptPubKey + Private key + internal
|
|
print("Should import a scriptPubKey with internal and with private key")
|
|
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
|
result = self.nodes[1].importmulti([{
|
|
"scriptPubKey": address['scriptPubKey'],
|
|
"timestamp": "now",
|
|
"keys": [ self.nodes[0].dumpprivkey(address['address']) ],
|
|
"internal": True
|
|
}])
|
|
assert_equal(result[0]['success'], True)
|
|
address_assert = self.nodes[1].validateaddress(address['address'])
|
|
assert_equal(address_assert['iswatchonly'], False)
|
|
assert_equal(address_assert['ismine'], True)
|
|
assert_equal(address_assert['timestamp'], timestamp)
|
|
|
|
# ScriptPubKey + Private key + !internal
|
|
print("Should not import a scriptPubKey without internal and with private key")
|
|
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
|
result = self.nodes[1].importmulti([{
|
|
"scriptPubKey": address['scriptPubKey'],
|
|
"timestamp": "now",
|
|
"keys": [ self.nodes[0].dumpprivkey(address['address']) ]
|
|
}])
|
|
assert_equal(result[0]['success'], False)
|
|
assert_equal(result[0]['error']['code'], -8)
|
|
assert_equal(result[0]['error']['message'], 'Internal must be set for hex scriptPubKey')
|
|
address_assert = self.nodes[1].validateaddress(address['address'])
|
|
assert_equal(address_assert['iswatchonly'], False)
|
|
assert_equal(address_assert['ismine'], False)
|
|
assert_equal('timestamp' in address_assert, False)
|
|
|
|
|
|
# P2SH address
|
|
sig_address_1 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
|
sig_address_2 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
|
sig_address_3 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
|
multi_sig_script = self.nodes[0].createmultisig(2, [sig_address_1['address'], sig_address_2['address'], sig_address_3['pubkey']])
|
|
self.nodes[1].generate(100)
|
|
transactionid = self.nodes[1].sendtoaddress(multi_sig_script['address'], 10.00)
|
|
self.nodes[1].generate(1)
|
|
timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
|
|
transaction = self.nodes[1].gettransaction(transactionid)
|
|
|
|
print("Should import a p2sh")
|
|
result = self.nodes[1].importmulti([{
|
|
"scriptPubKey": {
|
|
"address": multi_sig_script['address']
|
|
},
|
|
"timestamp": "now",
|
|
}])
|
|
assert_equal(result[0]['success'], True)
|
|
address_assert = self.nodes[1].validateaddress(multi_sig_script['address'])
|
|
assert_equal(address_assert['isscript'], True)
|
|
assert_equal(address_assert['iswatchonly'], True)
|
|
assert_equal(address_assert['timestamp'], timestamp)
|
|
p2shunspent = self.nodes[1].listunspent(0,999999, [multi_sig_script['address']])[0]
|
|
assert_equal(p2shunspent['spendable'], False)
|
|
assert_equal(p2shunspent['solvable'], False)
|
|
|
|
|
|
# P2SH + Redeem script
|
|
sig_address_1 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
|
sig_address_2 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
|
sig_address_3 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
|
multi_sig_script = self.nodes[0].createmultisig(2, [sig_address_1['address'], sig_address_2['address'], sig_address_3['pubkey']])
|
|
self.nodes[1].generate(100)
|
|
transactionid = self.nodes[1].sendtoaddress(multi_sig_script['address'], 10.00)
|
|
self.nodes[1].generate(1)
|
|
timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
|
|
transaction = self.nodes[1].gettransaction(transactionid)
|
|
|
|
print("Should import a p2sh with respective redeem script")
|
|
result = self.nodes[1].importmulti([{
|
|
"scriptPubKey": {
|
|
"address": multi_sig_script['address']
|
|
},
|
|
"timestamp": "now",
|
|
"redeemscript": multi_sig_script['redeemScript']
|
|
}])
|
|
assert_equal(result[0]['success'], True)
|
|
address_assert = self.nodes[1].validateaddress(multi_sig_script['address'])
|
|
assert_equal(address_assert['timestamp'], timestamp)
|
|
|
|
p2shunspent = self.nodes[1].listunspent(0,999999, [multi_sig_script['address']])[0]
|
|
assert_equal(p2shunspent['spendable'], False)
|
|
assert_equal(p2shunspent['solvable'], True)
|
|
|
|
|
|
# P2SH + Redeem script + Private Keys + !Watchonly
|
|
sig_address_1 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
|
sig_address_2 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
|
sig_address_3 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
|
multi_sig_script = self.nodes[0].createmultisig(2, [sig_address_1['address'], sig_address_2['address'], sig_address_3['pubkey']])
|
|
self.nodes[1].generate(100)
|
|
transactionid = self.nodes[1].sendtoaddress(multi_sig_script['address'], 10.00)
|
|
self.nodes[1].generate(1)
|
|
timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
|
|
transaction = self.nodes[1].gettransaction(transactionid)
|
|
|
|
print("Should import a p2sh with respective redeem script and private keys")
|
|
result = self.nodes[1].importmulti([{
|
|
"scriptPubKey": {
|
|
"address": multi_sig_script['address']
|
|
},
|
|
"timestamp": "now",
|
|
"redeemscript": multi_sig_script['redeemScript'],
|
|
"keys": [ self.nodes[0].dumpprivkey(sig_address_1['address']), self.nodes[0].dumpprivkey(sig_address_2['address'])]
|
|
}])
|
|
assert_equal(result[0]['success'], True)
|
|
address_assert = self.nodes[1].validateaddress(multi_sig_script['address'])
|
|
assert_equal(address_assert['timestamp'], timestamp)
|
|
|
|
p2shunspent = self.nodes[1].listunspent(0,999999, [multi_sig_script['address']])[0]
|
|
assert_equal(p2shunspent['spendable'], False)
|
|
assert_equal(p2shunspent['solvable'], True)
|
|
|
|
# P2SH + Redeem script + Private Keys + Watchonly
|
|
sig_address_1 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
|
sig_address_2 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
|
sig_address_3 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
|
multi_sig_script = self.nodes[0].createmultisig(2, [sig_address_1['address'], sig_address_2['address'], sig_address_3['pubkey']])
|
|
self.nodes[1].generate(100)
|
|
transactionid = self.nodes[1].sendtoaddress(multi_sig_script['address'], 10.00)
|
|
self.nodes[1].generate(1)
|
|
transaction = self.nodes[1].gettransaction(transactionid)
|
|
|
|
print("Should import a p2sh with respective redeem script and private keys")
|
|
result = self.nodes[1].importmulti([{
|
|
"scriptPubKey": {
|
|
"address": multi_sig_script['address']
|
|
},
|
|
"timestamp": "now",
|
|
"redeemscript": multi_sig_script['redeemScript'],
|
|
"keys": [ self.nodes[0].dumpprivkey(sig_address_1['address']), self.nodes[0].dumpprivkey(sig_address_2['address'])],
|
|
"watchonly": True
|
|
}])
|
|
assert_equal(result[0]['success'], False)
|
|
assert_equal(result[0]['error']['code'], -8)
|
|
assert_equal(result[0]['error']['message'], 'Incompatibility found between watchonly and keys')
|
|
|
|
|
|
# Address + Public key + !Internal + Wrong pubkey
|
|
print("Should not import an address with a wrong public key")
|
|
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
|
address2 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
|
result = self.nodes[1].importmulti([{
|
|
"scriptPubKey": {
|
|
"address": address['address']
|
|
},
|
|
"timestamp": "now",
|
|
"pubkeys": [ address2['pubkey'] ]
|
|
}])
|
|
assert_equal(result[0]['success'], False)
|
|
assert_equal(result[0]['error']['code'], -5)
|
|
assert_equal(result[0]['error']['message'], 'Consistency check failed')
|
|
address_assert = self.nodes[1].validateaddress(address['address'])
|
|
assert_equal(address_assert['iswatchonly'], False)
|
|
assert_equal(address_assert['ismine'], False)
|
|
assert_equal('timestamp' in address_assert, False)
|
|
|
|
|
|
# ScriptPubKey + Public key + internal + Wrong pubkey
|
|
print("Should not import a scriptPubKey with internal and with a wrong public key")
|
|
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
|
address2 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
|
request = [{
|
|
"scriptPubKey": address['scriptPubKey'],
|
|
"timestamp": "now",
|
|
"pubkeys": [ address2['pubkey'] ],
|
|
"internal": True
|
|
}]
|
|
result = self.nodes[1].importmulti(request)
|
|
assert_equal(result[0]['success'], False)
|
|
assert_equal(result[0]['error']['code'], -5)
|
|
assert_equal(result[0]['error']['message'], 'Consistency check failed')
|
|
address_assert = self.nodes[1].validateaddress(address['address'])
|
|
assert_equal(address_assert['iswatchonly'], False)
|
|
assert_equal(address_assert['ismine'], False)
|
|
assert_equal('timestamp' in address_assert, False)
|
|
|
|
|
|
# Address + Private key + !watchonly + Wrong private key
|
|
print("Should not import an address with a wrong private key")
|
|
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
|
address2 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
|
result = self.nodes[1].importmulti([{
|
|
"scriptPubKey": {
|
|
"address": address['address']
|
|
},
|
|
"timestamp": "now",
|
|
"keys": [ self.nodes[0].dumpprivkey(address2['address']) ]
|
|
}])
|
|
assert_equal(result[0]['success'], False)
|
|
assert_equal(result[0]['error']['code'], -5)
|
|
assert_equal(result[0]['error']['message'], 'Consistency check failed')
|
|
address_assert = self.nodes[1].validateaddress(address['address'])
|
|
assert_equal(address_assert['iswatchonly'], False)
|
|
assert_equal(address_assert['ismine'], False)
|
|
assert_equal('timestamp' in address_assert, False)
|
|
|
|
|
|
# ScriptPubKey + Private key + internal + Wrong private key
|
|
print("Should not import a scriptPubKey with internal and with a wrong private key")
|
|
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
|
address2 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
|
|
result = self.nodes[1].importmulti([{
|
|
"scriptPubKey": address['scriptPubKey'],
|
|
"timestamp": "now",
|
|
"keys": [ self.nodes[0].dumpprivkey(address2['address']) ],
|
|
"internal": True
|
|
}])
|
|
assert_equal(result[0]['success'], False)
|
|
assert_equal(result[0]['error']['code'], -5)
|
|
assert_equal(result[0]['error']['message'], 'Consistency check failed')
|
|
address_assert = self.nodes[1].validateaddress(address['address'])
|
|
assert_equal(address_assert['iswatchonly'], False)
|
|
assert_equal(address_assert['ismine'], False)
|
|
assert_equal('timestamp' in address_assert, False)
|
|
|
|
# restart nodes to check for proper serialization/deserialization of watch only address
|
|
stop_nodes(self.nodes)
|
|
self.nodes = start_nodes(2, self.options.tmpdir)
|
|
address_assert = self.nodes[1].validateaddress(watchonly_address)
|
|
assert_equal(address_assert['iswatchonly'], True)
|
|
assert_equal(address_assert['ismine'], False)
|
|
assert_equal(address_assert['timestamp'], watchonly_timestamp);
|
|
|
|
# Bad or missing timestamps
|
|
print("Should throw on invalid or missing timestamp values")
|
|
assert_raises_message(JSONRPCException, 'Missing required timestamp field for key',
|
|
self.nodes[1].importmulti, [{
|
|
"scriptPubKey": address['scriptPubKey'],
|
|
}])
|
|
assert_raises_message(JSONRPCException, 'Expected number or "now" timestamp value for key. got type string',
|
|
self.nodes[1].importmulti, [{
|
|
"scriptPubKey": address['scriptPubKey'],
|
|
"timestamp": "",
|
|
}])
|
|
|
|
|
|
if __name__ == '__main__':
|
|
ImportMultiTest ().main ()
|