From 215caba4ed4547d6f2a0954fa9fe1ae78f4a7c40 Mon Sep 17 00:00:00 2001 From: Pedro Branco Date: Wed, 19 Oct 2016 15:17:42 +0100 Subject: [PATCH] Add consistency check to RPC call importmulti --- qa/rpc-tests/importmulti.py | 69 ++++++++++++++++++++++++++++++++++++- src/wallet/rpcdump.cpp | 48 +++++++++++++++++++++----- 2 files changed, 108 insertions(+), 9 deletions(-) diff --git a/qa/rpc-tests/importmulti.py b/qa/rpc-tests/importmulti.py index 960cb63d7..5c536f2f4 100755 --- a/qa/rpc-tests/importmulti.py +++ b/qa/rpc-tests/importmulti.py @@ -285,9 +285,76 @@ class ImportMultiTest (BitcoinTestFramework): assert_equal(result[0]['error']['code'], -8) assert_equal(result[0]['error']['message'], 'Incompatibility found between watchonly and keys') - # TODO Consistency tests? + + # 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'] + }, + "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) + # 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'], + "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) + + + # 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'] + }, + "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) + + + # 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'], + "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) if __name__ == '__main__': ImportMultiTest ().main () diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 0297337c2..7b16b4adf 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -641,9 +641,6 @@ UniValue dumpwallet(const JSONRPCRequest& request) UniValue processImport(const UniValue& data) { - // TODO List: - // - Check consistency between pubkeys/privkeys and scriptPubKey/redeemScript. - try { bool success = false; @@ -713,8 +710,6 @@ UniValue processImport(const UniValue& data) { // P2SH if (isP2SH) { - // TODO: check consistency between private keys and p2sh redeemscript + p2sh address - // Import redeem script. std::vector vData(ParseHex(strRedeemScript)); CScript redeemScript = CScript(vData.begin(), vData.end()); @@ -795,8 +790,6 @@ UniValue processImport(const UniValue& data) { success = true; } else { - // TODO: check consistency between private/public keys and scriptPubKey / address - // Import public keys. if (pubKeys.size() && keys.size() == 0) { const string& strPubKey = pubKeys[0].get_str(); @@ -813,6 +806,25 @@ UniValue processImport(const UniValue& data) { } CBitcoinAddress pubKeyAddress = CBitcoinAddress(pubKey.GetID()); + + // Consistency check. + if (!isScript && pubKeyAddress.Get() != address.Get()) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed"); + } + + // Consistency check. + if (isScript) { + CBitcoinAddress scriptAddress; + CTxDestination destination; + + if (ExtractDestination(script, destination)) { + scriptAddress = CBitcoinAddress(destination); + if (scriptAddress.Get() != pubKeyAddress.Get()) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed"); + } + } + } + CScript pubKeyScript = GetScriptForDestination(pubKeyAddress.Get()); if (::IsMine(*pwalletMain, pubKeyScript) == ISMINE_SPENDABLE) { @@ -866,7 +878,27 @@ UniValue processImport(const UniValue& data) { CPubKey pubKey = key.GetPubKey(); assert(key.VerifyPubKey(pubKey)); - CKeyID vchAddress = pubkey.GetID(); + CBitcoinAddress pubKeyAddress = CBitcoinAddress(pubKey.GetID()); + + // Consistency check. + if (!isScript && pubKeyAddress.Get() != address.Get()) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed"); + } + + // Consistency check. + if (isScript) { + CBitcoinAddress scriptAddress; + CTxDestination destination; + + if (ExtractDestination(script, destination)) { + scriptAddress = CBitcoinAddress(destination); + if (scriptAddress.Get() != pubKeyAddress.Get()) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed"); + } + } + } + + CKeyID vchAddress = pubKey.GetID(); pwalletMain->MarkDirty(); pwalletMain->SetAddressBook(vchAddress, label, "receive");