mirror of
https://github.com/dogecoin/dogecoin.git
synced 2026-03-17 17:02:28 +00:00
Add optional height to importprivkey RPC
This allows users to avoid rescanning the entire chain when importing a new private key, if they provide the height of the block from which to start. Note that any transactions to or from the corresponding wallet will only be indexed if they occur at or after the given height. The height argument is `height`, consistent with the `height` argument to `rescan`.
This commit is contained in:
parent
f447c0c0de
commit
05d20afccd
@ -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()
|
||||
|
||||
@ -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" },
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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"} },
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user