mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-06-21 14:22:38 +02:00
Generate new keys for inactive seeds after marking used
When a key from an inactive seed is used, generate replacements to fill a keypool that would have been there.
This commit is contained in:
parent
45f2f6a0e8
commit
c93082ece4
@ -12,6 +12,9 @@
|
|||||||
#include <util/translation.h>
|
#include <util/translation.h>
|
||||||
#include <wallet/scriptpubkeyman.h>
|
#include <wallet/scriptpubkeyman.h>
|
||||||
|
|
||||||
|
//! Value for the first BIP 32 hardened derivation. Can be used as a bit mask and as a value. See BIP 32 for more details.
|
||||||
|
const uint32_t BIP32_HARDENED_KEY_LIMIT = 0x80000000;
|
||||||
|
|
||||||
bool LegacyScriptPubKeyMan::GetNewDestination(const OutputType type, CTxDestination& dest, std::string& error)
|
bool LegacyScriptPubKeyMan::GetNewDestination(const OutputType type, CTxDestination& dest, std::string& error)
|
||||||
{
|
{
|
||||||
LOCK(cs_KeyStore);
|
LOCK(cs_KeyStore);
|
||||||
@ -290,6 +293,43 @@ bool LegacyScriptPubKeyMan::GetReservedDestination(const OutputType type, bool i
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool LegacyScriptPubKeyMan::TopUpInactiveHDChain(const CKeyID seed_id, int64_t index, bool internal)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
CHDChain& chain = it->second;
|
||||||
|
|
||||||
|
// Top up key pool
|
||||||
|
int64_t target_size = std::max(gArgs.GetArg("-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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void LegacyScriptPubKeyMan::MarkUnusedAddresses(const CScript& script)
|
void LegacyScriptPubKeyMan::MarkUnusedAddresses(const CScript& script)
|
||||||
{
|
{
|
||||||
LOCK(cs_KeyStore);
|
LOCK(cs_KeyStore);
|
||||||
@ -297,13 +337,28 @@ void LegacyScriptPubKeyMan::MarkUnusedAddresses(const CScript& script)
|
|||||||
for (const auto& keyid : GetAffectedKeys(script, *this)) {
|
for (const auto& keyid : GetAffectedKeys(script, *this)) {
|
||||||
std::map<CKeyID, int64_t>::const_iterator mi = m_pool_key_to_index.find(keyid);
|
std::map<CKeyID, int64_t>::const_iterator mi = m_pool_key_to_index.find(keyid);
|
||||||
if (mi != m_pool_key_to_index.end()) {
|
if (mi != m_pool_key_to_index.end()) {
|
||||||
WalletLogPrintf("%s: Detected a used keypool key, mark all keypool key up to this key as used\n", __func__);
|
WalletLogPrintf("%s: Detected a used keypool key, mark all keypool keys up to this key as used\n", __func__);
|
||||||
MarkReserveKeysAsUsed(mi->second);
|
MarkReserveKeysAsUsed(mi->second);
|
||||||
|
|
||||||
if (!TopUp()) {
|
if (!TopUp()) {
|
||||||
WalletLogPrintf("%s: Topping up keypool failed (locked wallet)\n", __func__);
|
WalletLogPrintf("%s: Topping up keypool failed (locked wallet)\n", __func__);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find the key's metadata and check if it's seed id (if it has one) is inactive, i.e. it is not the current m_hd_chain seed id.
|
||||||
|
// If so, TopUp the inactive hd chain
|
||||||
|
auto it = mapKeyMetadata.find(keyid);
|
||||||
|
if (it != mapKeyMetadata.end()){
|
||||||
|
CKeyMetadata meta = it->second;
|
||||||
|
if (!meta.hd_seed_id.IsNull() && meta.hd_seed_id != m_hd_chain.seed_id) {
|
||||||
|
bool internal = (meta.key_origin.path[1] & ~BIP32_HARDENED_KEY_LIMIT) != 0;
|
||||||
|
int64_t index = meta.key_origin.path[2] & ~BIP32_HARDENED_KEY_LIMIT;
|
||||||
|
|
||||||
|
if (!TopUpInactiveHDChain(meta.hd_seed_id, index, internal)) {
|
||||||
|
WalletLogPrintf("%s: Adding inactive seed keys failed\n", __func__);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -975,8 +1030,6 @@ CPubKey LegacyScriptPubKeyMan::GenerateNewKey(WalletBatch &batch, CHDChain& hd_c
|
|||||||
return pubkey;
|
return pubkey;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint32_t BIP32_HARDENED_KEY_LIMIT = 0x80000000;
|
|
||||||
|
|
||||||
void LegacyScriptPubKeyMan::DeriveNewChildKey(WalletBatch &batch, CKeyMetadata& metadata, CKey& secret, CHDChain& hd_chain, bool internal)
|
void LegacyScriptPubKeyMan::DeriveNewChildKey(WalletBatch &batch, CKeyMetadata& metadata, CKey& secret, CHDChain& hd_chain, bool internal)
|
||||||
{
|
{
|
||||||
// for now we use a fixed keypath scheme of m/0'/0'/k
|
// for now we use a fixed keypath scheme of m/0'/0'/k
|
||||||
|
@ -333,6 +333,18 @@ private:
|
|||||||
*/
|
*/
|
||||||
bool ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool fRequestedInternal);
|
bool ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool fRequestedInternal);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like TopUp() but adds keys for inactive HD chains.
|
||||||
|
* Ensures that there are at least -keypool number of keys derived after the given index.
|
||||||
|
*
|
||||||
|
* @param seed_id the CKeyID for the HD seed.
|
||||||
|
* @param index the index to start generating keys from
|
||||||
|
* @param internal whether the internal chain should be used. true for internal chain, false for external chain.
|
||||||
|
*
|
||||||
|
* @return true if seed was found and keys were derived. false if unable to derive seeds
|
||||||
|
*/
|
||||||
|
bool TopUpInactiveHDChain(const CKeyID seed_id, int64_t index, bool internal);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using ScriptPubKeyMan::ScriptPubKeyMan;
|
using ScriptPubKeyMan::ScriptPubKeyMan;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user