0
0
Fork 0
mirror of https://github.com/bitcoin/bitcoin.git synced 2025-02-02 09:46:52 -05:00

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).
This commit is contained in:
Andrew Chow 2021-10-18 15:27:27 -04:00
parent 70134eb34f
commit 8077862c5e
3 changed files with 69 additions and 56 deletions

View file

@ -321,8 +321,6 @@ bool LegacyScriptPubKeyMan::TopUpInactiveHDChain(const CKeyID seed_id, int64_t i
{
LOCK(cs_KeyStore);
if (m_storage.IsLocked()) return false;
auto it = m_inactive_hd_chains.find(seed_id);
if (it == m_inactive_hd_chains.end()) {
return false;
@ -330,27 +328,14 @@ bool LegacyScriptPubKeyMan::TopUpInactiveHDChain(const CKeyID seed_id, int64_t i
CHDChain& chain = it->second;
// Top up key pool
int64_t target_size = std::max(gArgs.GetIntArg("-keypool", DEFAULT_KEYPOOL_SIZE), (int64_t) 1);
// "size" of the keypools. Not really the size, actually the difference between index and the chain counter
// Since chain counter is 1 based and index is 0 based, one of them needs to be offset by 1.
int64_t kp_size = (internal ? chain.nInternalChainCounter : chain.nExternalChainCounter) - (index + 1);
// make sure the keypool fits the user-selected target (-keypool)
int64_t missing = std::max(target_size - kp_size, (int64_t) 0);
if (missing > 0) {
WalletBatch batch(m_storage.GetDatabase());
for (int64_t i = missing; i > 0; --i) {
GenerateNewKey(batch, chain, internal);
}
if (internal) {
WalletLogPrintf("inactive seed with id %s added %d internal keys\n", HexStr(seed_id), missing);
} else {
WalletLogPrintf("inactive seed with id %s added %d keys\n", HexStr(seed_id), missing);
}
if (internal) {
chain.m_next_internal_index = std::max(chain.m_next_internal_index, index + 1);
} else {
chain.m_next_external_index = std::max(chain.m_next_external_index, index + 1);
}
TopUpChain(chain, 0);
return true;
}
@ -1273,47 +1258,72 @@ bool LegacyScriptPubKeyMan::TopUp(unsigned int kpSize)
if (!CanGenerateKeys()) {
return false;
}
{
LOCK(cs_KeyStore);
if (m_storage.IsLocked()) return false;
// Top up key pool
unsigned int nTargetSize;
if (kpSize > 0)
nTargetSize = kpSize;
else
nTargetSize = std::max(gArgs.GetIntArg("-keypool", DEFAULT_KEYPOOL_SIZE), (int64_t) 0);
// count amount of available keys (internal, external)
// make sure the keypool of external and internal keys fits the user selected target (-keypool)
int64_t missingExternal = std::max(std::max((int64_t) nTargetSize, (int64_t) 1) - (int64_t)setExternalKeyPool.size(), (int64_t) 0);
int64_t missingInternal = std::max(std::max((int64_t) nTargetSize, (int64_t) 1) - (int64_t)setInternalKeyPool.size(), (int64_t) 0);
if (!IsHDEnabled() || !m_storage.CanSupportFeature(FEATURE_HD_SPLIT))
{
// don't create extra internal keys
missingInternal = 0;
}
bool internal = false;
WalletBatch batch(m_storage.GetDatabase());
for (int64_t i = missingInternal + missingExternal; i--;)
{
if (i < missingInternal) {
internal = true;
}
CPubKey pubkey(GenerateNewKey(batch, m_hd_chain, internal));
AddKeypoolPubkeyWithDB(pubkey, internal, batch);
}
if (missingInternal + missingExternal > 0) {
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());
if (!TopUpChain(m_hd_chain, kpSize)) {
return false;
}
for (auto& [chain_id, chain] : m_inactive_hd_chains) {
if (!TopUpChain(chain, kpSize)) {
return false;
}
}
NotifyCanGetAddressesChanged();
return true;
}
bool LegacyScriptPubKeyMan::TopUpChain(CHDChain& chain, unsigned int kpSize)
{
LOCK(cs_KeyStore);
if (m_storage.IsLocked()) return false;
// Top up key pool
unsigned int nTargetSize;
if (kpSize > 0) {
nTargetSize = kpSize;
} else {
nTargetSize = std::max(gArgs.GetIntArg("-keypool", DEFAULT_KEYPOOL_SIZE), int64_t{0});
}
int64_t target = std::max((int64_t) nTargetSize, int64_t{1});
// count amount of available keys (internal, external)
// make sure the keypool of external and internal keys fits the user selected target (-keypool)
int64_t missingExternal;
int64_t missingInternal;
if (chain == m_hd_chain) {
missingExternal = std::max(target - (int64_t)setExternalKeyPool.size(), int64_t{0});
missingInternal = std::max(target - (int64_t)setInternalKeyPool.size(), int64_t{0});
} else {
missingExternal = std::max(target - (chain.nExternalChainCounter - chain.m_next_external_index), int64_t{0});
missingInternal = std::max(target - (chain.nInternalChainCounter - chain.m_next_internal_index), int64_t{0});
}
if (!IsHDEnabled() || !m_storage.CanSupportFeature(FEATURE_HD_SPLIT)) {
// don't create extra internal keys
missingInternal = 0;
}
bool internal = false;
WalletBatch batch(m_storage.GetDatabase());
for (int64_t i = missingInternal + missingExternal; i--;) {
if (i < missingInternal) {
internal = true;
}
CPubKey pubkey(GenerateNewKey(batch, chain, internal));
if (chain == m_hd_chain) {
AddKeypoolPubkeyWithDB(pubkey, internal, batch);
}
}
if (missingInternal + missingExternal > 0) {
if (chain == m_hd_chain) {
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());
} else {
WalletLogPrintf("inactive seed with id %s added %d external keys, %d internal keys\n", HexStr(chain.seed_id), missingExternal, missingInternal);
}
}
return true;
}
void LegacyScriptPubKeyMan::AddKeypoolPubkeyWithDB(const CPubKey& pubkey, const bool internal, WalletBatch& batch)
{
LOCK(cs_KeyStore);

View file

@ -354,6 +354,7 @@ private:
*/
bool TopUpInactiveHDChain(const CKeyID seed_id, int64_t index, bool internal);
bool TopUpChain(CHDChain& chain, unsigned int size);
public:
using ScriptPubKeyMan::ScriptPubKeyMan;

View file

@ -90,6 +90,8 @@ public:
uint32_t nExternalChainCounter;
uint32_t nInternalChainCounter;
CKeyID seed_id; //!< seed hash160
int64_t m_next_external_index{0}; // Next index in the keypool to be used. Memory only.
int64_t m_next_internal_index{0}; // Next index in the keypool to be used. Memory only.
static const int VERSION_HD_BASE = 1;
static const int VERSION_HD_CHAIN_SPLIT = 2;