Skip to content

Commit 8077862

Browse files
committed
wallet: Refactor TopUp to be able to top up inactive chains too
Refactors TopUp so that it also tops up inactive chains. The bulk of TopUp is moved to TopUpChain. CHDChain also has 2 new in memory variables to track its highest used indexes. This is used only for inactive hd chains so that they can be topped up later in the same session (e.g. if the wallet is encrypted and not unlocked at the time of MarkUnusedAddresses).
1 parent 70134eb commit 8077862

File tree

3 files changed

+61
-48
lines changed

3 files changed

+61
-48
lines changed

src/wallet/scriptpubkeyman.cpp

Lines changed: 58 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -321,36 +321,21 @@ bool LegacyScriptPubKeyMan::TopUpInactiveHDChain(const CKeyID seed_id, int64_t i
321321
{
322322
LOCK(cs_KeyStore);
323323

324-
if (m_storage.IsLocked()) return false;
325-
326324
auto it = m_inactive_hd_chains.find(seed_id);
327325
if (it == m_inactive_hd_chains.end()) {
328326
return false;
329327
}
330328

331329
CHDChain& chain = it->second;
332330

333-
// Top up key pool
334-
int64_t target_size = std::max(gArgs.GetIntArg("-keypool", DEFAULT_KEYPOOL_SIZE), (int64_t) 1);
335-
336-
// "size" of the keypools. Not really the size, actually the difference between index and the chain counter
337-
// Since chain counter is 1 based and index is 0 based, one of them needs to be offset by 1.
338-
int64_t kp_size = (internal ? chain.nInternalChainCounter : chain.nExternalChainCounter) - (index + 1);
331+
if (internal) {
332+
chain.m_next_internal_index = std::max(chain.m_next_internal_index, index + 1);
333+
} else {
334+
chain.m_next_external_index = std::max(chain.m_next_external_index, index + 1);
335+
}
339336

340-
// make sure the keypool fits the user-selected target (-keypool)
341-
int64_t missing = std::max(target_size - kp_size, (int64_t) 0);
337+
TopUpChain(chain, 0);
342338

343-
if (missing > 0) {
344-
WalletBatch batch(m_storage.GetDatabase());
345-
for (int64_t i = missing; i > 0; --i) {
346-
GenerateNewKey(batch, chain, internal);
347-
}
348-
if (internal) {
349-
WalletLogPrintf("inactive seed with id %s added %d internal keys\n", HexStr(seed_id), missing);
350-
} else {
351-
WalletLogPrintf("inactive seed with id %s added %d keys\n", HexStr(seed_id), missing);
352-
}
353-
}
354339
return true;
355340
}
356341

@@ -1273,44 +1258,69 @@ bool LegacyScriptPubKeyMan::TopUp(unsigned int kpSize)
12731258
if (!CanGenerateKeys()) {
12741259
return false;
12751260
}
1276-
{
1277-
LOCK(cs_KeyStore);
12781261

1279-
if (m_storage.IsLocked()) return false;
1262+
if (!TopUpChain(m_hd_chain, kpSize)) {
1263+
return false;
1264+
}
1265+
for (auto& [chain_id, chain] : m_inactive_hd_chains) {
1266+
if (!TopUpChain(chain, kpSize)) {
1267+
return false;
1268+
}
1269+
}
1270+
NotifyCanGetAddressesChanged();
1271+
return true;
1272+
}
12801273

1281-
// Top up key pool
1282-
unsigned int nTargetSize;
1283-
if (kpSize > 0)
1284-
nTargetSize = kpSize;
1285-
else
1286-
nTargetSize = std::max(gArgs.GetIntArg("-keypool", DEFAULT_KEYPOOL_SIZE), (int64_t) 0);
1274+
bool LegacyScriptPubKeyMan::TopUpChain(CHDChain& chain, unsigned int kpSize)
1275+
{
1276+
LOCK(cs_KeyStore);
12871277

1288-
// count amount of available keys (internal, external)
1289-
// make sure the keypool of external and internal keys fits the user selected target (-keypool)
1290-
int64_t missingExternal = std::max(std::max((int64_t) nTargetSize, (int64_t) 1) - (int64_t)setExternalKeyPool.size(), (int64_t) 0);
1291-
int64_t missingInternal = std::max(std::max((int64_t) nTargetSize, (int64_t) 1) - (int64_t)setInternalKeyPool.size(), (int64_t) 0);
1278+
if (m_storage.IsLocked()) return false;
12921279

1293-
if (!IsHDEnabled() || !m_storage.CanSupportFeature(FEATURE_HD_SPLIT))
1294-
{
1295-
// don't create extra internal keys
1296-
missingInternal = 0;
1280+
// Top up key pool
1281+
unsigned int nTargetSize;
1282+
if (kpSize > 0) {
1283+
nTargetSize = kpSize;
1284+
} else {
1285+
nTargetSize = std::max(gArgs.GetIntArg("-keypool", DEFAULT_KEYPOOL_SIZE), int64_t{0});
1286+
}
1287+
int64_t target = std::max((int64_t) nTargetSize, int64_t{1});
1288+
1289+
// count amount of available keys (internal, external)
1290+
// make sure the keypool of external and internal keys fits the user selected target (-keypool)
1291+
int64_t missingExternal;
1292+
int64_t missingInternal;
1293+
if (chain == m_hd_chain) {
1294+
missingExternal = std::max(target - (int64_t)setExternalKeyPool.size(), int64_t{0});
1295+
missingInternal = std::max(target - (int64_t)setInternalKeyPool.size(), int64_t{0});
1296+
} else {
1297+
missingExternal = std::max(target - (chain.nExternalChainCounter - chain.m_next_external_index), int64_t{0});
1298+
missingInternal = std::max(target - (chain.nInternalChainCounter - chain.m_next_internal_index), int64_t{0});
1299+
}
1300+
1301+
if (!IsHDEnabled() || !m_storage.CanSupportFeature(FEATURE_HD_SPLIT)) {
1302+
// don't create extra internal keys
1303+
missingInternal = 0;
1304+
}
1305+
bool internal = false;
1306+
WalletBatch batch(m_storage.GetDatabase());
1307+
for (int64_t i = missingInternal + missingExternal; i--;) {
1308+
if (i < missingInternal) {
1309+
internal = true;
12971310
}
1298-
bool internal = false;
1299-
WalletBatch batch(m_storage.GetDatabase());
1300-
for (int64_t i = missingInternal + missingExternal; i--;)
1301-
{
1302-
if (i < missingInternal) {
1303-
internal = true;
1304-
}
13051311

1306-
CPubKey pubkey(GenerateNewKey(batch, m_hd_chain, internal));
1312+
CPubKey pubkey(GenerateNewKey(batch, chain, internal));
1313+
if (chain == m_hd_chain) {
13071314
AddKeypoolPubkeyWithDB(pubkey, internal, batch);
13081315
}
1309-
if (missingInternal + missingExternal > 0) {
1316+
}
1317+
if (missingInternal + missingExternal > 0) {
1318+
if (chain == m_hd_chain) {
13101319
WalletLogPrintf("keypool added %d keys (%d internal), size=%u (%u internal)\n", missingInternal + missingExternal, missingInternal, setInternalKeyPool.size() + setExternalKeyPool.size() + set_pre_split_keypool.size(), setInternalKeyPool.size());
1320+
} else {
1321+
WalletLogPrintf("inactive seed with id %s added %d external keys, %d internal keys\n", HexStr(chain.seed_id), missingExternal, missingInternal);
13111322
}
13121323
}
1313-
NotifyCanGetAddressesChanged();
13141324
return true;
13151325
}
13161326

src/wallet/scriptpubkeyman.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@ class LegacyScriptPubKeyMan : public ScriptPubKeyMan, public FillableSigningProv
354354
*/
355355
bool TopUpInactiveHDChain(const CKeyID seed_id, int64_t index, bool internal);
356356

357+
bool TopUpChain(CHDChain& chain, unsigned int size);
357358
public:
358359
using ScriptPubKeyMan::ScriptPubKeyMan;
359360

src/wallet/walletdb.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ class CHDChain
9090
uint32_t nExternalChainCounter;
9191
uint32_t nInternalChainCounter;
9292
CKeyID seed_id; //!< seed hash160
93+
int64_t m_next_external_index{0}; // Next index in the keypool to be used. Memory only.
94+
int64_t m_next_internal_index{0}; // Next index in the keypool to be used. Memory only.
9395

9496
static const int VERSION_HD_BASE = 1;
9597
static const int VERSION_HD_CHAIN_SPLIT = 2;

0 commit comments

Comments
 (0)