Merge pull request #3084 from chromatic/rescan-from-specific-height-squashed

Add optional height to importprivkey RPC
This commit is contained in:
Old Dip Tracker 2022-08-02 18:06:16 -04:00 committed by GitHub
commit 4850eccec4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 46 additions and 9 deletions

View File

@ -1,17 +1,18 @@
#!/usr/bin/env python3
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Copyright (c) 2022 The Dogecoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test rescan behavior of importaddress, importpubkey, importprivkey, and
importmulti RPCs with different types of keys and rescan options.
In the first part of the test, node 1 creates an address for each type of
import RPC call and node 0 sends BTC to it. Then other nodes import the
import RPC call and node 0 sends Doge to it. Then other nodes import the
addresses, and the test makes listtransactions and getbalance calls to confirm
that the importing node either did or did not execute rescans picking up the
send transactions.
In the second part of the test, node 0 sends more BTC to each address, and the
In the second part of the test, node 0 sends more Doge to each address, and the
test makes more listtransactions and getbalance calls to confirm that the
importing nodes pick up the new transactions regardless of whether rescans
happened previously.
@ -114,6 +115,9 @@ class ImportRescanTest(BitcoinTestFramework):
super().__init__()
self.num_nodes = 2 + len(IMPORT_NODES)
def first_node(self):
return self.nodes[0]
def setup_network(self):
extra_args = [["-debug=1"] for _ in range(self.num_nodes)]
for i, import_node in enumerate(IMPORT_NODES, 2):
@ -125,8 +129,11 @@ class ImportRescanTest(BitcoinTestFramework):
connect_nodes(self.nodes[i], 0)
def run_test(self):
self.test_argument_validation()
# Create one transaction on node 0 with a unique amount and label for
# each possible type of wallet import RPC.
for i, variant in enumerate(IMPORT_VARIANTS):
variant.label = "label {} {}".format(i, variant)
variant.address = self.nodes[1].validateaddress(self.nodes[1].getnewaddress(variant.label))
@ -179,6 +186,21 @@ class ImportRescanTest(BitcoinTestFramework):
else:
variant.check()
def test_argument_validation(self):
node = self.first_node()
try:
node.importprivkey("")
except JSONRPCException as e:
assert("Invalid private key encoding" in e.error["message"])
address = node.validateaddress(node.getnewaddress("some label"))
privkey = node.dumpprivkey(address["address"])
try:
node.importprivkey(privkey, "", True, str(node.getblockcount() + 1))
except JSONRPCException as e:
assert("Block height out of range" in e.error["message"])
def try_rpc(func, *args, **kwargs):
try:
@ -186,6 +208,5 @@ def try_rpc(func, *args, **kwargs):
except JSONRPCException as e:
return None, e.error
if __name__ == "__main__":
ImportRescanTest().main()

View File

@ -103,6 +103,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "lockunspent", 0, "unlock" },
{ "lockunspent", 1, "transactions" },
{ "importprivkey", 2, "rescan" },
{ "importprivkey", 3, "height" },
{ "importaddress", 2, "rescan" },
{ "importaddress", 3, "p2sh" },
{ "importpubkey", 2, "rescan" },

View File

@ -83,8 +83,8 @@ UniValue importprivkey(const JSONRPCRequest& request)
{
if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
if (request.fHelp || request.params.size() < 1 || request.params.size() > 3)
if (request.fHelp || request.params.size() < 1 || request.params.size() > 4)
throw runtime_error(
"importprivkey \"dogecoinprivkey\" ( \"label\" ) ( rescan )\n"
"\nAdds a private key (as returned by dumpprivkey) to your wallet.\n"
@ -92,6 +92,7 @@ UniValue importprivkey(const JSONRPCRequest& request)
"1. \"dogecoinprivkey\" (string, required) The private key (see dumpprivkey)\n"
"2. \"label\" (string, optional, default=\"\") An optional label\n"
"3. rescan (boolean, optional, default=true) Rescan the wallet for transactions\n"
"4. height (numeric, optional, default=1) If rescanning, the block height from which to start\n"
"\nNote: This call can take minutes to complete if rescan is true.\n"
"\nExamples:\n"
"\nDump a private key\n"
@ -102,6 +103,8 @@ UniValue importprivkey(const JSONRPCRequest& request)
+ HelpExampleCli("importprivkey", "\"mykey\" \"testing\" false") +
"\nImport using default blank label and without rescan\n"
+ HelpExampleCli("importprivkey", "\"mykey\" \"\" false") +
"\nImport using default blank label, with rescan, from a specific block height\n"
+ HelpExampleCli("importprivkey", "\"mykey\" \"\" true 3760036") +
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("importprivkey", "\"mykey\", \"testing\", false")
);
@ -148,11 +151,23 @@ UniValue importprivkey(const JSONRPCRequest& request)
if (!pwalletMain->AddKeyPubKey(key, pubkey))
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
// whenever a key is imported, we need to scan the whole chain
pwalletMain->UpdateTimeFirstKey(1);
if (fRescan) {
pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true);
CBlockIndex* pblockindex = chainActive.Genesis();
if (request.params.size() > 3) {
int nHeight = request.params[3].get_int();
if (nHeight < 0 || nHeight > chainActive.Height())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
pblockindex = chainActive[nHeight];
} else {
// we have no implicit first height for a key, so we need to scan the whole chain
pwalletMain->UpdateTimeFirstKey(1);
}
pwalletMain->ScanForWalletTransactions(pblockindex, true);
}
}

View File

@ -3244,7 +3244,7 @@ static const CRPCCommand commands[] =
{ "wallet", "getunconfirmedbalance", &getunconfirmedbalance, false, {} },
{ "wallet", "getwalletinfo", &getwalletinfo, false, {} },
{ "wallet", "importmulti", &importmulti, true, {"requests","options"} },
{ "wallet", "importprivkey", &importprivkey, true, {"privkey","label","rescan"} },
{ "wallet", "importprivkey", &importprivkey, true, {"privkey","label","rescan", "height"} },
{ "wallet", "importwallet", &importwallet, true, {"filename"} },
{ "wallet", "importaddress", &importaddress, true, {"address","label","rescan","p2sh"} },
{ "wallet", "importprunedfunds", &importprunedfunds, true, {"rawtransaction","txoutproof"} },