From 083ab1c0969fa3d41381637c914eb56f869161d9 Mon Sep 17 00:00:00 2001 From: chromatic Date: Sat, 11 Mar 2023 19:36:22 -0800 Subject: [PATCH] Add optional `height` to `importaddress` This follows the same pattern as other import RPC calls and uses the same codepath. --- qa/rpc-tests/import-rescan.py | 36 +++++++++++++++++++++++++++++++++-- src/rpc/client.cpp | 1 + src/wallet/rpcdump.cpp | 16 +++++++++------- 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/qa/rpc-tests/import-rescan.py b/qa/rpc-tests/import-rescan.py index 5b1dc982a..8f32c7d12 100755 --- a/qa/rpc-tests/import-rescan.py +++ b/qa/rpc-tests/import-rescan.py @@ -137,7 +137,8 @@ class ImportRescanTest(BitcoinTestFramework): def run_test(self): self.test_argument_validation() self.test_import_types() - self.test_rescan_from_height() + self.test_rescan_from_height_importpubkey() + self.test_rescan_from_height_importaddress() def test_import_types(self): # Create one transaction on node 0 with a unique amount and label for @@ -228,7 +229,7 @@ class ImportRescanTest(BitcoinTestFramework): except JSONRPCException as e: assert("Block height out of range" in e.error["message"]) - def test_rescan_from_height(self): + def test_rescan_from_height_importpubkey(self): # this height is before sending anything to the new address orig_height = self.nodes[0].getblockcount() @@ -259,6 +260,37 @@ class ImportRescanTest(BitcoinTestFramework): balance = self.nodes[3].getbalance("newpubkey", 0, True) assert_equal(balance, Decimal("100")) + def test_rescan_from_height_importaddress(self): + # this height is before sending anything to the new address + orig_height = self.nodes[0].getblockcount() + + address = self.nodes[0].getnewaddress() + pubkey = self.nodes[0].validateaddress(address)["pubkey"] + self.nodes[0].sendtoaddress(address, 100) + + # generate two blocks + # the first contains the tx that sends these koinu + # the second is after it + self.nodes[0].generate(2) + new_height = self.nodes[0].getblockcount() + + self.sync_recipient_nodes() + + # no rescan, no funds seen for this pubkey + self.nodes[1].importaddress(address, "newaddress", False) + balance = self.nodes[1].getbalance("newaddress", 0, True) + assert_equal(balance, Decimal("0")) + + # rescan at the block *after* the tx, no funds seen for this pubkey + self.nodes[2].importaddress(address, "newaddress", True, False, new_height) + balance = self.nodes[2].getbalance("newaddress", 0, True) + assert_equal(balance, Decimal("0")) + + # rescan at the block *before* the tx, funds seen for this pubkey + self.nodes[3].importaddress(address, "newaddress", True, False, orig_height) + balance = self.nodes[3].getbalance("newaddress", 0, True) + assert_equal(balance, Decimal("100")) + def try_rpc(func, *args, **kwargs): try: return func(*args, **kwargs), None diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index bdb29c2d0..7c4a0913b 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -106,6 +106,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "importprivkey", 3, "height" }, { "importaddress", 2, "rescan" }, { "importaddress", 3, "p2sh" }, + { "importaddress", 4, "height" }, { "importpubkey", 2, "rescan" }, { "importpubkey", 3, "height" }, { "importmulti", 0, "requests" }, diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 7ea0a0f91..aa0ebd365 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -225,16 +225,17 @@ UniValue importaddress(const JSONRPCRequest& request) { if (!EnsureWalletIsAvailable(request.fHelp)) return NullUniValue; - - if (request.fHelp || request.params.size() < 1 || request.params.size() > 4) + + if (request.fHelp || request.params.size() < 1 || request.params.size() > 5) throw runtime_error( - "importaddress \"address\" ( \"label\" rescan p2sh )\n" + "importaddress \"address\" ( \"label\" rescan p2sh height )\n" "\nAdds a script (in hex) or address that can be watched as if it were in your wallet but cannot be used to spend.\n" "\nArguments:\n" "1. \"script\" (string, required) The hex-encoded script (or address)\n" "2. \"label\" (string, optional, default=\"\") An optional label\n" "3. rescan (boolean, optional, default=true) Rescan the wallet for transactions\n" "4. p2sh (boolean, optional, default=false) Add the P2SH version of the script as well\n" + "5. 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" "If you have the full public key, you should call importpubkey instead of this.\n" "\nNote: If you import a non-standard raw script in hex form, outputs sending to it will be treated\n" @@ -244,6 +245,8 @@ UniValue importaddress(const JSONRPCRequest& request) + HelpExampleCli("importaddress", "\"myscript\"") + "\nImport using a label without rescan\n" + HelpExampleCli("importaddress", "\"myscript\" \"testing\" false") + + "\nImport a script with rescan from a specific height\n" + + HelpExampleCli("importaddress", "\"myscript\" \"testing\" true false 32768") + "\nAs a JSON-RPC call\n" + HelpExampleRpc("importaddress", "\"myscript\", \"testing\", false") ); @@ -280,10 +283,9 @@ UniValue importaddress(const JSONRPCRequest& request) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Dogecoin address or script"); } - if (fRescan) - { - pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true); - pwalletMain->ReacceptWalletTransactions(); + if (fRescan) { + const uint32_t nHeight = getHeightParamFromRequest(request, 4); + attemptRescanFromHeight(nHeight); } return NullUniValue;