mirror of
https://github.com/dogecoin/dogecoin.git
synced 2026-01-31 18:40:58 +00:00
Add rescan RPC command
This commit is contained in:
parent
b38a23cdfe
commit
f74e27da05
@ -169,6 +169,7 @@ testScripts = [
|
||||
'listsinceblock.py',
|
||||
'p2p-leaktests.py',
|
||||
'replace-by-fee.py',
|
||||
'rescan.py',
|
||||
'wallet_create_tx.py',
|
||||
'liststucktransactions.py',
|
||||
'addnode.py',
|
||||
|
||||
127
qa/rpc-tests/rescan.py
Normal file
127
qa/rpc-tests/rescan.py
Normal file
@ -0,0 +1,127 @@
|
||||
#!/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.
|
||||
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import *
|
||||
|
||||
|
||||
class RescanTest(BitcoinTestFramework):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.setup_clean_chain = True
|
||||
self.num_nodes = 3
|
||||
|
||||
# only sync the first two nodes; use the third for prune testing
|
||||
def sync_all(self):
|
||||
syncable = self.nodes[:2]
|
||||
sync_blocks(syncable)
|
||||
sync_mempools(syncable)
|
||||
|
||||
def setup_network(self, split=False):
|
||||
self.nodes = start_nodes(self.num_nodes - 1, self.options.tmpdir, [['-spendzeroconfchange=0'], None])
|
||||
self.nodes.append(start_node(2, self.options.tmpdir, ["-prune=1"]))
|
||||
connect_nodes_bi(self.nodes,0,1)
|
||||
self.is_network_split=False
|
||||
self.sync_all()
|
||||
|
||||
def run_test(self):
|
||||
print("Mining blocks...")
|
||||
self.nodes[0].generate(101)
|
||||
|
||||
self.sync_all()
|
||||
|
||||
# address
|
||||
address1 = self.nodes[0].getnewaddress()
|
||||
# pubkey
|
||||
address2 = self.nodes[0].getnewaddress()
|
||||
address2_pubkey = self.nodes[0].validateaddress(address2)['pubkey'] # Using pubkey
|
||||
# privkey
|
||||
address3 = self.nodes[0].getnewaddress()
|
||||
address3_privkey = self.nodes[0].dumpprivkey(address3) # Using privkey
|
||||
|
||||
self.sync_all()
|
||||
|
||||
# Node 1 sync test
|
||||
assert_equal(self.nodes[1].getblockcount(), 101)
|
||||
|
||||
# Send funds to self
|
||||
txnid1 = self.nodes[0].sendtoaddress(address1, 10)
|
||||
rawtxn1 = self.nodes[0].gettransaction(txnid1)['hex']
|
||||
|
||||
txnid2 = self.nodes[0].sendtoaddress(address2, 5)
|
||||
rawtxn2 = self.nodes[0].gettransaction(txnid2)['hex']
|
||||
|
||||
txnid3 = self.nodes[0].sendtoaddress(address3, 2.5)
|
||||
rawtxn3 = self.nodes[0].gettransaction(txnid3)['hex']
|
||||
|
||||
self.nodes[0].generate(1)
|
||||
|
||||
# Import with affiliated address with no rescan
|
||||
self.nodes[1].importaddress(address2, "add2", False)
|
||||
balance2 = self.nodes[1].getbalance("add2", 0, True)
|
||||
assert_equal(balance2, Decimal('0'))
|
||||
|
||||
self.nodes[1].rescan()
|
||||
balance2 = self.nodes[1].getbalance("add2", 0, True)
|
||||
assert_equal(balance2, Decimal('5'))
|
||||
|
||||
# Import with private key with no rescan
|
||||
self.nodes[1].importprivkey(address3_privkey, "add3", False)
|
||||
|
||||
# add more blocks
|
||||
self.nodes[1].generate(102)
|
||||
balance4 = self.nodes[1].getbalance("add3", 0, False)
|
||||
assert_equal(balance4, Decimal('0'))
|
||||
self.nodes[1].rescan(200)
|
||||
balance4 = self.nodes[1].getbalance("add3", 0, False)
|
||||
assert_equal(balance4, Decimal('0'))
|
||||
result = self.nodes[1].rescan(2)
|
||||
balance4 = self.nodes[1].getbalance("add3", 0, True)
|
||||
assert_equal(balance4, Decimal('2.5'))
|
||||
|
||||
assert_equal(result["before"], {
|
||||
"balance": Decimal('21000000'),
|
||||
"txcount": 103
|
||||
})
|
||||
|
||||
assert_equal(result["after"], {
|
||||
"balance": Decimal('21000002.5'),
|
||||
"txcount": 104
|
||||
})
|
||||
|
||||
assert_equal(result["blocks_scanned"], 202)
|
||||
assert("time_elapsed" in result)
|
||||
|
||||
# 2100000 from mining, 7.5 otherwise
|
||||
# note that 5 are from a watch-only address
|
||||
balance4 = self.nodes[1].getbalance("*", 0, True)
|
||||
assert_equal(balance4, Decimal('21000007.5'))
|
||||
|
||||
try:
|
||||
self.nodes[1].rescan(-100)
|
||||
raise AssertionError("rescan should throw JSON exception given a negative block height")
|
||||
except JSONRPCException as e:
|
||||
assert("Block height out of range" in e.error["message"])
|
||||
|
||||
try:
|
||||
currentheight = self.nodes[1].getblockcount()
|
||||
self.nodes[1].rescan(currentheight + 1 )
|
||||
raise AssertionError("rescan should throw JSON exception given a block height too high")
|
||||
except JSONRPCException as e:
|
||||
assert("Block height out of range" in e.error["message"])
|
||||
|
||||
try:
|
||||
pruned_node = self.nodes[2]
|
||||
pruned_node.rescan(1)
|
||||
raise AssertionError("rescan should throw JSON error when used on a pruned node")
|
||||
except JSONRPCException as e:
|
||||
assert("Currently works only on non-pruned nodes" in e.error["message"])
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
RescanTest().main()
|
||||
@ -125,6 +125,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
||||
{ "getmempooldescendants", 1, "verbose" },
|
||||
{ "bumpfee", 1, "options" },
|
||||
{ "setmaxconnections", 0, "maxconnectioncount" },
|
||||
{ "rescan", 0, "height" },
|
||||
// Echo with conversion (For testing only)
|
||||
{ "echojson", 0, "arg0" },
|
||||
{ "echojson", 1, "arg1" },
|
||||
|
||||
@ -807,6 +807,83 @@ UniValue movecmd(const JSONRPCRequest& request)
|
||||
return true;
|
||||
}
|
||||
|
||||
UniValue rescan(const JSONRPCRequest& request)
|
||||
{
|
||||
if (!EnsureWalletIsAvailable(request.fHelp))
|
||||
return NullUniValue;
|
||||
|
||||
const int nParams = request.params.size();
|
||||
|
||||
if (request.fHelp || nParams > 1 || fPruneMode)
|
||||
throw runtime_error(
|
||||
"rescan ( \"height\" )\n"
|
||||
"\nRescan the wallet for transactions\n"
|
||||
"\nWARNING: this operation may take a long time!\n"
|
||||
"\nCurrently works only on non-pruned nodes\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"height\" (number, optional) The block height from which to start rescanning\n"
|
||||
"2. \"label\" (string, optional, default=\"\") An optional label\n"
|
||||
"3. rescan (boolean, optional, default=true) Rescan the wallet for transactions\n"
|
||||
"\nResult:\n"
|
||||
"{\n"
|
||||
" \"before\":\n"
|
||||
" {\n"
|
||||
" \"balance\" : (numeric) The total amount in " + CURRENCY_UNIT + " received by the address before the rescan\n"
|
||||
" \"txcount\" : (numeric) The number of transactions received by addresses in the wallet before the rescan\n"
|
||||
" },\n"
|
||||
" \"after\":\n"
|
||||
" {\n"
|
||||
" \"balance\" : (numeric) The total amount in " + CURRENCY_UNIT + " received by the address after the rescan\n"
|
||||
" \"txcount\" : (numeric) The number of transactions received by addresses in the wallet after the rescan\n"
|
||||
" },\n"
|
||||
" \"blocks_scanned\" : (numeric) The number of blocks scanned during the rescan\n"
|
||||
" \"time_elapsed\" : (numeric) The number of seconds it took to rescan the blocks (may be zero)\n"
|
||||
"}\n"
|
||||
"\nNote: This call can take minutes to complete.\n"
|
||||
"\nExamples:\n"
|
||||
"\nRescan from block height 122345\n"
|
||||
+ HelpExampleCli("rescan", "122345") +
|
||||
"\nRescan from the first block\n"
|
||||
+ HelpExampleCli("rescan", "") +
|
||||
"\nAs a JSON-RPC call\n"
|
||||
+ HelpExampleRpc("rescan", "122345")
|
||||
);
|
||||
|
||||
|
||||
CBlockIndex* pblockindex = chainActive.Genesis();
|
||||
int64_t nHeight = 0;
|
||||
|
||||
if (nParams == 1) {
|
||||
nHeight = request.params[0].get_int();
|
||||
|
||||
if (nHeight < 0 || nHeight > chainActive.Height())
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
|
||||
|
||||
pblockindex = chainActive[nHeight];
|
||||
}
|
||||
|
||||
UniValue beforeObj(UniValue::VOBJ);
|
||||
beforeObj.pushKV("balance", ValueFromAmount(pwalletMain->GetBalance()));
|
||||
beforeObj.pushKV("txcount", (int)pwalletMain->mapWallet.size());
|
||||
|
||||
int64_t beforeTime = GetTime();
|
||||
|
||||
pwalletMain->ScanForWalletTransactions(pblockindex, true);
|
||||
|
||||
UniValue afterObj(UniValue::VOBJ);
|
||||
afterObj.pushKV("balance", ValueFromAmount(pwalletMain->GetBalance()));
|
||||
afterObj.pushKV("txcount", (int)pwalletMain->mapWallet.size());
|
||||
|
||||
UniValue ret(UniValue::VOBJ);
|
||||
ret.pushKV("before", beforeObj);
|
||||
ret.pushKV("after", afterObj);
|
||||
|
||||
ret.pushKV("blocks_scanned", chainActive.Height() - nHeight);
|
||||
ret.pushKV("time_elapsed", GetTime() - beforeTime);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
UniValue sendfrom(const JSONRPCRequest& request)
|
||||
{
|
||||
@ -3183,6 +3260,7 @@ static const CRPCCommand commands[] =
|
||||
{ "wallet", "listunspent", &listunspent, false, {"minconf","maxconf","addresses","include_unsafe","query_options"} },
|
||||
{ "wallet", "lockunspent", &lockunspent, true, {"unlock","transactions"} },
|
||||
{ "wallet", "move", &movecmd, false, {"fromaccount","toaccount","amount","minconf","comment"} },
|
||||
{ "wallet", "rescan", &rescan, false, {"height"} },
|
||||
{ "wallet", "sendfrom", &sendfrom, false, {"fromaccount","toaddress","amount","minconf","comment","comment_to"} },
|
||||
{ "wallet", "sendmany", &sendmany, false, {"fromaccount","amounts","minconf","comment","subtractfeefrom"} },
|
||||
{ "wallet", "sendtoaddress", &sendtoaddress, false, {"address","amount","comment","comment_to","subtractfeefromamount"} },
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user