Skip to content

Commit 910f4c0

Browse files
laanwjknst
authored andcommitted
Merge bitcoin#23093: Add ability to flush keypool and always flush when upgrading non-HD to HD
6531599 test: Add check that newkeypool flushes change addresses too (Samuel Dobson) 84fa19c Add release notes for keypool flush changes (Samuel Dobson) f9603ee Add test for flushing keypool with newkeypool (Samuel Dobson) 6f6f7bb Make legacy wallet upgrades from non-HD to HD always flush the keypool (Samuel Dobson) 2434b10 Fix outdated keypool size default (Samuel Dobson) 22cc797 Add newkeypool RPC to flush the keypool (Samuel Dobson) Pull request description: This PR makes two main changes: 1) Adds a new RPC `newkeypool` which will entirely flush and refill the keypool. 2) When upgradewallet is called on old, non-HD wallets upgrading them to HD, we now always flush the keypool and generate a new one, to immediately start using the HD generated keys. This PR is motivated by a number of users with old, pre-compressed-key wallets upgrading them and being confused about why they still can't generate p2sh-segwit or bech32 addresses -- this is due to uncompressed keys remaining in the keypool post-upgrade and being illegal in these newer address formats. There is currently no easy way to flush the keypool other than to call `getnewaddress` a hundred/thousand times or an ugly hack of using a `sethdseed` call. ACKs for top commit: laanwj: re-ACK 6531599 meshcollider: Added new commit 6531599 to avoid invalidating previous ACKs. instagibbs: ACK bitcoin@6531599 Tree-SHA512: 50c79c5d42dd27ab0ecdbfdc4071fdaa1b2dbb2f9195ed325b007106ff19226419ce57fe5b1539c0c24101b12f5e034bbcfb7bbb0451b766cb1071295383d774
1 parent cf6e969 commit 910f4c0

File tree

3 files changed

+51
-1
lines changed

3 files changed

+51
-1
lines changed

doc/release-notes-23093.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Notable changes
2+
===============
3+
4+
Updated RPCs
5+
------------
6+
7+
- a new RPC `newkeypool` has been added, which will flush (entirely
8+
clear and refill) the keypool.

src/wallet/rpcwallet.cpp

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1747,7 +1747,7 @@ static RPCHelpMan keypoolrefill()
17471747
"\nFills the keypool."+
17481748
HELP_REQUIRING_PASSPHRASE,
17491749
{
1750-
{"newsize", RPCArg::Type::NUM, RPCArg::Default{int{DEFAULT_KEYPOOL_SIZE}}, "The new keypool size"},
1750+
{"newsize", RPCArg::Type::NUM, RPCArg::DefaultHint{strprintf("%u, or as set by -keypool", DEFAULT_KEYPOOL_SIZE)}, "The new keypool size"},
17511751
},
17521752
RPCResult{RPCResult::Type::NONE, "", ""},
17531753
RPCExamples{
@@ -1786,6 +1786,33 @@ static RPCHelpMan keypoolrefill()
17861786
}
17871787

17881788

1789+
static RPCHelpMan newkeypool()
1790+
{
1791+
return RPCHelpMan{"newkeypool",
1792+
"\nEntirely clears and refills the keypool."+
1793+
HELP_REQUIRING_PASSPHRASE,
1794+
{},
1795+
RPCResult{RPCResult::Type::NONE, "", ""},
1796+
RPCExamples{
1797+
HelpExampleCli("newkeypool", "")
1798+
+ HelpExampleRpc("newkeypool", "")
1799+
},
1800+
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1801+
{
1802+
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
1803+
if (!pwallet) return NullUniValue;
1804+
1805+
LOCK(pwallet->cs_wallet);
1806+
1807+
LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*pwallet, true);
1808+
spk_man.NewKeyPool();
1809+
1810+
return NullUniValue;
1811+
},
1812+
};
1813+
}
1814+
1815+
17891816
static RPCHelpMan walletpassphrase()
17901817
{
17911818
return RPCHelpMan{"walletpassphrase",
@@ -4642,6 +4669,7 @@ static const CRPCCommand commands[] =
46424669
{ "wallet", &listwallets, },
46434670
{ "wallet", &loadwallet, },
46444671
{ "wallet", &lockunspent, },
4672+
{ "wallet", &newkeypool, },
46454673
{ "wallet", &removeprunedfunds, },
46464674
{ "wallet", &rescanblockchain, },
46474675
{ "wallet", &send, },

test/functional/wallet_keypool_hd.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,20 @@ def run_test(self):
161161
assert_equal(wi['keypoolsize_hd_internal'], 100)
162162
assert_equal(wi['keypoolsize'], 100)
163163

164+
if not self.options.descriptors:
165+
# Check that newkeypool entirely flushes the keypool
166+
start_keypath = nodes[0].getaddressinfo(nodes[0].getnewaddress())['hdkeypath']
167+
start_change_keypath = nodes[0].getaddressinfo(nodes[0].getrawchangeaddress())['hdkeypath']
168+
# flush keypool and get new addresses
169+
nodes[0].newkeypool()
170+
end_keypath = nodes[0].getaddressinfo(nodes[0].getnewaddress())['hdkeypath']
171+
end_change_keypath = nodes[0].getaddressinfo(nodes[0].getrawchangeaddress())['hdkeypath']
172+
# The new keypath index should be 100 more than the old one
173+
new_index = int(start_keypath.rsplit('/', 1)[1]) + 100
174+
new_change_index = int(start_change_keypath.rsplit('/', 1)[1]) + 100
175+
assert_equal(end_keypath, "m/44'/1'/0'/0/" + str(new_index))
176+
assert_equal(end_change_keypath, "m/44'/1'/0'/1/" + str(new_change_index))
177+
164178
# create a blank wallet
165179
nodes[0].createwallet(wallet_name='w2', blank=True, disable_private_keys=True)
166180
w2 = nodes[0].get_wallet_rpc('w2')

0 commit comments

Comments
 (0)