Skip to content

Commit

Permalink
Add removeaddress RPC command
Browse files Browse the repository at this point in the history
This removes watch-only addresses and scripts such that their transactions no
longer appear in the wallet or the address book. This takes some care to ensure
that you do not remove a non-watch-only address or script.
  • Loading branch information
chromatic committed Mar 10, 2024
1 parent 5a23f00 commit 7b01b0b
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 0 deletions.
27 changes: 27 additions & 0 deletions qa/rpc-tests/listtransactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,33 @@ def run_test(self):
{"category":"receive","amount":Decimal("1")},
{"txid":txid, "account" : "watchonly"} )

# now remove watchonly address
from_node = self.nodes[1]
to_node = self.nodes[0]
new_address = to_node.getnewaddress()

txid = from_node.sendtoaddress(new_address, 128)
from_node.generate(1)
from_node.importaddress(new_address, "remove-watch")
oldacc = from_node.listaccounts(1, True)
self.sync_all()

new_tx = from_node.listtransactions("*", 100, 0, True)
assert(new_tx[-2]["txid"] == txid)

from_node.removeaddress(new_address)
new_tx = from_node.listtransactions("*", 100, 0, True)
newacc = from_node.listaccounts(1, True)

assert(new_tx[-1]["txid"] != txid)
assert(len(oldacc) == len(newacc) + 1)

# now fail to remove a non-watchonly address
try:
to_node.removeaddress(new_address)
except JSONRPCException as exp:
assert_equal(exp.error["message"], "Address is not watch-only")

self.run_rbf_opt_in_test()

# Check that the opt-in-rbf flag works properly, for sent and received
Expand Down
49 changes: 49 additions & 0 deletions src/wallet/rpcdump.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,55 @@ UniValue importaddress(const JSONRPCRequest& request)
return NullUniValue;
}

UniValue removeaddress(const JSONRPCRequest& request)
{
if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;

if (request.fHelp || request.params.size() != 1)
throw runtime_error(
"removeaddress \"address\"\n"
"\nRemoves a watch-only script (in hex) or address. Will not remove an actual wallet address.\n"
"\nArguments:\n"
"1. \"script\" (string, required) The hex-encoded script (or address)\n"
"\nExamples:\n"
+ HelpExampleCli("removeaddress", "\"myscript\"")
+ HelpExampleRpc("removeaddress", "\"myscript\"")
);

LOCK2(cs_main, pwalletMain->cs_wallet);
pwalletMain->MarkDirty();
std::string arg = request.params[0].get_str();

CBitcoinAddress address(arg);
CTxDestination destination;

if (address.IsValid()) {
destination = address.Get();
} else if (IsHex(arg)) {
std::vector<unsigned char> data(ParseHex(request.params[0].get_str()));
const CScript script = CScript(data.begin(), data.end());

if (!ExtractDestination(script, destination)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Dogecoin address or script");
}
} else {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Dogecoin address or script");
}

CScript script = GetScriptForDestination(destination);

if (!pwalletMain->HaveWatchOnly(script))
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Address is not watch-only");

if (!pwalletMain->RemoveWatchOnly(script))
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Address could not be removed");
if (!pwalletMain->DelAddressBook(destination))
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Could not remove watch-only address");

return NullUniValue;
}

UniValue importprunedfunds(const JSONRPCRequest& request)
{
if (!EnsureWalletIsAvailable(request.fHelp))
Expand Down
2 changes: 2 additions & 0 deletions src/wallet/rpcwallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3218,6 +3218,7 @@ extern UniValue importwallet(const JSONRPCRequest& request);
extern UniValue importprunedfunds(const JSONRPCRequest& request);
extern UniValue removeprunedfunds(const JSONRPCRequest& request);
extern UniValue importmulti(const JSONRPCRequest& request);
extern UniValue removeaddress(const JSONRPCRequest& request);

static const CRPCCommand commands[] =
{ // category name actor (function) okSafeMode
Expand Down Expand Up @@ -3261,6 +3262,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", "removeaddress", &removeaddress, false, {"address"} },
{ "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"} },
Expand Down

0 comments on commit 7b01b0b

Please sign in to comment.