|
12 | 12 | #include "consensus/consensus.h"
|
13 | 13 | #include "consensus/validation.h"
|
14 | 14 | #include "fs.h"
|
| 15 | +#include "init.h" |
15 | 16 | #include "key.h"
|
16 | 17 | #include "keystore.h"
|
17 | 18 | #include "validation.h"
|
@@ -1053,6 +1054,30 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const CBlockI
|
1053 | 1054 | if (fExisted && !fUpdate) return false;
|
1054 | 1055 | if (fExisted || IsMine(tx) || IsFromMe(tx))
|
1055 | 1056 | {
|
| 1057 | + /* Check if any keys in the wallet keypool that were supposed to be unused |
| 1058 | + * have appeared in a new transaction. If so, remove those keys from the keypool. |
| 1059 | + * This can happen when restoring an old wallet backup that does not contain |
| 1060 | + * the mostly recently created transactions from newer versions of the wallet. |
| 1061 | + */ |
| 1062 | + |
| 1063 | + // loop though all outputs |
| 1064 | + for (const CTxOut& txout: tx.vout) { |
| 1065 | + // extract addresses and check if they match with an unused keypool key |
| 1066 | + std::vector<CKeyID> vAffected; |
| 1067 | + CAffectedKeysVisitor(*this, vAffected).Process(txout.scriptPubKey); |
| 1068 | + for (const CKeyID &keyid : vAffected) { |
| 1069 | + std::map<CKeyID, int64_t>::const_iterator mi = m_pool_key_to_index.find(keyid); |
| 1070 | + if (mi != m_pool_key_to_index.end()) { |
| 1071 | + LogPrintf("%s: Detected a used keypool key, mark all keypool key up to this key as used\n", __func__); |
| 1072 | + MarkReserveKeysAsUsed(mi->second); |
| 1073 | + |
| 1074 | + if (!TopUpKeyPool()) { |
| 1075 | + LogPrintf("%s: Topping up keypool failed (locked wallet)\n", __func__); |
| 1076 | + } |
| 1077 | + } |
| 1078 | + } |
| 1079 | + } |
| 1080 | + |
1056 | 1081 | CWalletTx wtx(this, ptx);
|
1057 | 1082 |
|
1058 | 1083 | // Get merkle branch if transaction was found in a block
|
@@ -3611,6 +3636,28 @@ void CReserveKey::ReturnKey()
|
3611 | 3636 | vchPubKey = CPubKey();
|
3612 | 3637 | }
|
3613 | 3638 |
|
| 3639 | +void CWallet::MarkReserveKeysAsUsed(int64_t keypool_id) |
| 3640 | +{ |
| 3641 | + AssertLockHeld(cs_wallet); |
| 3642 | + bool internal = setInternalKeyPool.count(keypool_id); |
| 3643 | + if (!internal) assert(setExternalKeyPool.count(keypool_id)); |
| 3644 | + std::set<int64_t> *setKeyPool = internal ? &setInternalKeyPool : &setExternalKeyPool; |
| 3645 | + auto it = setKeyPool->begin(); |
| 3646 | + |
| 3647 | + CWalletDB walletdb(*dbw); |
| 3648 | + while (it != std::end(*setKeyPool)) { |
| 3649 | + const int64_t& index = *(it); |
| 3650 | + if (index > keypool_id) break; // set*KeyPool is ordered |
| 3651 | + |
| 3652 | + CKeyPool keypool; |
| 3653 | + if (walletdb.ReadPool(index, keypool)) { //TODO: This should be unnecessary |
| 3654 | + m_pool_key_to_index.erase(keypool.vchPubKey.GetID()); |
| 3655 | + } |
| 3656 | + walletdb.ErasePool(index); |
| 3657 | + it = setKeyPool->erase(it); |
| 3658 | + } |
| 3659 | +} |
| 3660 | + |
3614 | 3661 | bool CWallet::HasUnusedKeys(int min_keys) const
|
3615 | 3662 | {
|
3616 | 3663 | return setExternalKeyPool.size() >= min_keys && (setInternalKeyPool.size() >= min_keys || !CanSupportFeature(FEATURE_HD_SPLIT));
|
@@ -3989,6 +4036,9 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
|
3989 | 4036 |
|
3990 | 4037 | RegisterValidationInterface(walletInstance);
|
3991 | 4038 |
|
| 4039 | + // Try to top up keypool. No-op if the wallet is locked. |
| 4040 | + walletInstance->TopUpKeyPool(); |
| 4041 | + |
3992 | 4042 | CBlockIndex *pindexRescan = chainActive.Genesis();
|
3993 | 4043 | if (!GetBoolArg("-rescan", false))
|
3994 | 4044 | {
|
|
0 commit comments