|
12 | 12 | #include <util/translation.h>
|
13 | 13 | #include <wallet/scriptpubkeyman.h>
|
14 | 14 |
|
| 15 | +//! 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. |
| 16 | +const uint32_t BIP32_HARDENED_KEY_LIMIT = 0x80000000; |
| 17 | + |
15 | 18 | bool LegacyScriptPubKeyMan::GetNewDestination(const OutputType type, CTxDestination& dest, std::string& error)
|
16 | 19 | {
|
17 | 20 | LOCK(cs_KeyStore);
|
@@ -290,20 +293,72 @@ bool LegacyScriptPubKeyMan::GetReservedDestination(const OutputType type, bool i
|
290 | 293 | return true;
|
291 | 294 | }
|
292 | 295 |
|
| 296 | +bool LegacyScriptPubKeyMan::TopUpInactiveHDChain(const CKeyID seed_id, int64_t index, bool internal) |
| 297 | +{ |
| 298 | + LOCK(cs_KeyStore); |
| 299 | + |
| 300 | + if (m_storage.IsLocked()) return false; |
| 301 | + |
| 302 | + auto it = m_inactive_hd_chains.find(seed_id); |
| 303 | + if (it == m_inactive_hd_chains.end()) { |
| 304 | + return false; |
| 305 | + } |
| 306 | + |
| 307 | + CHDChain& chain = it->second; |
| 308 | + |
| 309 | + // Top up key pool |
| 310 | + int64_t target_size = std::max(gArgs.GetArg("-keypool", DEFAULT_KEYPOOL_SIZE), (int64_t) 1); |
| 311 | + |
| 312 | + // "size" of the keypools. Not really the size, actually the difference between index and the chain counter |
| 313 | + // Since chain counter is 1 based and index is 0 based, one of them needs to be offset by 1. |
| 314 | + int64_t kp_size = (internal ? chain.nInternalChainCounter : chain.nExternalChainCounter) - (index + 1); |
| 315 | + |
| 316 | + // make sure the keypool fits the user-selected target (-keypool) |
| 317 | + int64_t missing = std::max(target_size - kp_size, (int64_t) 0); |
| 318 | + |
| 319 | + if (missing > 0) { |
| 320 | + WalletBatch batch(m_storage.GetDatabase()); |
| 321 | + for (int64_t i = missing; i > 0; --i) { |
| 322 | + GenerateNewKey(batch, chain, internal); |
| 323 | + } |
| 324 | + if (internal) { |
| 325 | + WalletLogPrintf("inactive seed with id %s added %d internal keys\n", HexStr(seed_id), missing); |
| 326 | + } else { |
| 327 | + WalletLogPrintf("inactive seed with id %s added %d keys\n", HexStr(seed_id), missing); |
| 328 | + } |
| 329 | + } |
| 330 | + return true; |
| 331 | +} |
| 332 | + |
293 | 333 | void LegacyScriptPubKeyMan::MarkUnusedAddresses(const CScript& script)
|
294 | 334 | {
|
295 | 335 | LOCK(cs_KeyStore);
|
296 | 336 | // extract addresses and check if they match with an unused keypool key
|
297 | 337 | for (const auto& keyid : GetAffectedKeys(script, *this)) {
|
298 | 338 | std::map<CKeyID, int64_t>::const_iterator mi = m_pool_key_to_index.find(keyid);
|
299 | 339 | if (mi != m_pool_key_to_index.end()) {
|
300 |
| - WalletLogPrintf("%s: Detected a used keypool key, mark all keypool key up to this key as used\n", __func__); |
| 340 | + WalletLogPrintf("%s: Detected a used keypool key, mark all keypool keys up to this key as used\n", __func__); |
301 | 341 | MarkReserveKeysAsUsed(mi->second);
|
302 | 342 |
|
303 | 343 | if (!TopUp()) {
|
304 | 344 | WalletLogPrintf("%s: Topping up keypool failed (locked wallet)\n", __func__);
|
305 | 345 | }
|
306 | 346 | }
|
| 347 | + |
| 348 | + // 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. |
| 349 | + // If so, TopUp the inactive hd chain |
| 350 | + auto it = mapKeyMetadata.find(keyid); |
| 351 | + if (it != mapKeyMetadata.end()){ |
| 352 | + CKeyMetadata meta = it->second; |
| 353 | + if (!meta.hd_seed_id.IsNull() && meta.hd_seed_id != m_hd_chain.seed_id) { |
| 354 | + bool internal = (meta.key_origin.path[1] & ~BIP32_HARDENED_KEY_LIMIT) != 0; |
| 355 | + int64_t index = meta.key_origin.path[2] & ~BIP32_HARDENED_KEY_LIMIT; |
| 356 | + |
| 357 | + if (!TopUpInactiveHDChain(meta.hd_seed_id, index, internal)) { |
| 358 | + WalletLogPrintf("%s: Adding inactive seed keys failed\n", __func__); |
| 359 | + } |
| 360 | + } |
| 361 | + } |
307 | 362 | }
|
308 | 363 | }
|
309 | 364 |
|
@@ -975,8 +1030,6 @@ CPubKey LegacyScriptPubKeyMan::GenerateNewKey(WalletBatch &batch, CHDChain& hd_c
|
975 | 1030 | return pubkey;
|
976 | 1031 | }
|
977 | 1032 |
|
978 |
| -const uint32_t BIP32_HARDENED_KEY_LIMIT = 0x80000000; |
979 |
| - |
980 | 1033 | void LegacyScriptPubKeyMan::DeriveNewChildKey(WalletBatch &batch, CKeyMetadata& metadata, CKey& secret, CHDChain& hd_chain, bool internal)
|
981 | 1034 | {
|
982 | 1035 | // for now we use a fixed keypath scheme of m/0'/0'/k
|
|
0 commit comments