aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/wallet/wallet.cpp56
-rw-r--r--src/wallet/wallet.h12
2 files changed, 60 insertions, 8 deletions
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 57dc6c3b70..26eb7198f2 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -3326,6 +3326,11 @@ bool CWallet::NewKeyPool()
}
setExternalKeyPool.clear();
+ for (int64_t nIndex : set_pre_split_keypool) {
+ batch.ErasePool(nIndex);
+ }
+ set_pre_split_keypool.clear();
+
m_pool_key_to_index.clear();
if (!TopUpKeyPool()) {
@@ -3339,13 +3344,15 @@ bool CWallet::NewKeyPool()
size_t CWallet::KeypoolCountExternalKeys()
{
AssertLockHeld(cs_wallet); // setExternalKeyPool
- return setExternalKeyPool.size();
+ return setExternalKeyPool.size() + set_pre_split_keypool.size();
}
void CWallet::LoadKeyPool(int64_t nIndex, const CKeyPool &keypool)
{
AssertLockHeld(cs_wallet);
- if (keypool.fInternal) {
+ if (keypool.m_pre_split) {
+ set_pre_split_keypool.insert(nIndex);
+ } else if (keypool.fInternal) {
setInternalKeyPool.insert(nIndex);
} else {
setExternalKeyPool.insert(nIndex);
@@ -3410,7 +3417,7 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize)
m_pool_key_to_index[pubkey.GetID()] = index;
}
if (missingInternal + missingExternal > 0) {
- LogPrintf("keypool added %d keys (%d internal), size=%u (%u internal)\n", missingInternal + missingExternal, missingInternal, setInternalKeyPool.size() + setExternalKeyPool.size(), setInternalKeyPool.size());
+ LogPrintf("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());
}
}
return true;
@@ -3427,7 +3434,7 @@ void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool fRe
TopUpKeyPool();
bool fReturningInternal = IsHDEnabled() && CanSupportFeature(FEATURE_HD_SPLIT) && fRequestedInternal;
- std::set<int64_t>& setKeyPool = fReturningInternal ? setInternalKeyPool : setExternalKeyPool;
+ std::set<int64_t>& setKeyPool = set_pre_split_keypool.empty() ? (fReturningInternal ? setInternalKeyPool : setExternalKeyPool) : set_pre_split_keypool;
// Get the oldest key
if(setKeyPool.empty())
@@ -3444,7 +3451,8 @@ void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool fRe
if (!HaveKey(keypool.vchPubKey.GetID())) {
throw std::runtime_error(std::string(__func__) + ": unknown key in key pool");
}
- if (keypool.fInternal != fReturningInternal) {
+ // If the key was pre-split keypool, we don't care about what type it is
+ if (set_pre_split_keypool.size() == 0 && keypool.fInternal != fReturningInternal) {
throw std::runtime_error(std::string(__func__) + ": keypool entry misclassified");
}
@@ -3469,6 +3477,8 @@ void CWallet::ReturnKey(int64_t nIndex, bool fInternal, const CPubKey& pubkey)
LOCK(cs_wallet);
if (fInternal) {
setInternalKeyPool.insert(nIndex);
+ } else if (!set_pre_split_keypool.empty()) {
+ set_pre_split_keypool.insert(nIndex);
} else {
setExternalKeyPool.insert(nIndex);
}
@@ -3521,6 +3531,9 @@ int64_t CWallet::GetOldestKeyPoolTime()
int64_t oldestKey = GetOldestKeyTimeInPool(setExternalKeyPool, batch);
if (IsHDEnabled() && CanSupportFeature(FEATURE_HD_SPLIT)) {
oldestKey = std::max(GetOldestKeyTimeInPool(setInternalKeyPool, batch), oldestKey);
+ if (!set_pre_split_keypool.empty()) {
+ oldestKey = std::max(GetOldestKeyTimeInPool(set_pre_split_keypool, batch), oldestKey);
+ }
}
return oldestKey;
@@ -3718,8 +3731,8 @@ void CWallet::MarkReserveKeysAsUsed(int64_t keypool_id)
{
AssertLockHeld(cs_wallet);
bool internal = setInternalKeyPool.count(keypool_id);
- if (!internal) assert(setExternalKeyPool.count(keypool_id));
- std::set<int64_t> *setKeyPool = internal ? &setInternalKeyPool : &setExternalKeyPool;
+ if (!internal) assert(setExternalKeyPool.count(keypool_id) || set_pre_split_keypool.count(keypool_id));
+ std::set<int64_t> *setKeyPool = internal ? &setInternalKeyPool : (set_pre_split_keypool.empty() ? &setExternalKeyPool : &set_pre_split_keypool);
auto it = setKeyPool->begin();
WalletBatch batch(*database);
@@ -3955,6 +3968,24 @@ std::vector<std::string> CWallet::GetDestValues(const std::string& prefix) const
return values;
}
+void CWallet::MarkPreSplitKeys()
+{
+ WalletBatch batch(*database);
+ for (auto it = setExternalKeyPool.begin(); it != setExternalKeyPool.end();) {
+ int64_t index = *it;
+ CKeyPool keypool;
+ if (!batch.ReadPool(index, keypool)) {
+ throw std::runtime_error(std::string(__func__) + ": read keypool entry failed");
+ }
+ keypool.m_pre_split = true;
+ if (!batch.WritePool(index, keypool)) {
+ throw std::runtime_error(std::string(__func__) + ": writing modified keypool entry failed");
+ }
+ set_pre_split_keypool.insert(index);
+ it = setExternalKeyPool.erase(it);
+ }
+}
+
CWallet* CWallet::CreateWalletFromFile(const std::string& name, const fs::path& path)
{
const std::string& walletFile = name;
@@ -4006,6 +4037,7 @@ CWallet* CWallet::CreateWalletFromFile(const std::string& name, const fs::path&
}
}
+ int prev_version = walletInstance->nWalletVersion;
if (gArgs.GetBoolArg("-upgradewallet", fFirstRun))
{
int nMaxVersion = gArgs.GetArg("-upgradewallet", 0);
@@ -4029,6 +4061,7 @@ CWallet* CWallet::CreateWalletFromFile(const std::string& name, const fs::path&
if (gArgs.GetBoolArg("-upgradewallet", false)) {
LOCK(walletInstance->cs_wallet);
bool hd_upgrade = false;
+ bool split_upgrade = false;
if (walletInstance->CanSupportFeature(FEATURE_HD) && !walletInstance->IsHDEnabled()) {
LogPrintf("Upgrading wallet to HD\n");
walletInstance->SetMinVersion(FEATURE_HD);
@@ -4044,10 +4077,15 @@ CWallet* CWallet::CreateWalletFromFile(const std::string& name, const fs::path&
if (walletInstance->CanSupportFeature(FEATURE_HD_SPLIT)) {
LogPrintf("Upgrading wallet to use HD chain split\n");
walletInstance->SetMinVersion(FEATURE_HD_SPLIT);
+ split_upgrade = FEATURE_HD_SPLIT > prev_version;
+ }
+ // Mark all keys currently in the keypool as pre-split
+ if (split_upgrade) {
+ walletInstance->MarkPreSplitKeys();
}
// Regenerate the keypool if upgraded to HD
if (hd_upgrade) {
- if (!walletInstance->NewKeyPool()) {
+ if (!walletInstance->TopUpKeyPool()) {
InitError(_("Unable to generate keys") += "\n");
return nullptr;
}
@@ -4275,6 +4313,7 @@ CKeyPool::CKeyPool()
{
nTime = GetTime();
fInternal = false;
+ m_pre_split = false;
}
CKeyPool::CKeyPool(const CPubKey& vchPubKeyIn, bool internalIn)
@@ -4282,6 +4321,7 @@ CKeyPool::CKeyPool(const CPubKey& vchPubKeyIn, bool internalIn)
nTime = GetTime();
vchPubKey = vchPubKeyIn;
fInternal = internalIn;
+ m_pre_split = false;
}
CWalletKey::CWalletKey(int64_t nExpires)
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 215145a62b..d81f3ef206 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -119,6 +119,7 @@ public:
int64_t nTime;
CPubKey vchPubKey;
bool fInternal; // for change outputs
+ bool m_pre_split; // For keys generated before keypool split upgrade
CKeyPool();
CKeyPool(const CPubKey& vchPubKeyIn, bool internalIn);
@@ -141,9 +142,18 @@ public:
(this will be the case for any wallet before the HD chain split version) */
fInternal = false;
}
+ try {
+ READWRITE(m_pre_split);
+ }
+ catch (std::ios_base::failure&) {
+ /* flag as postsplit address if we can't read the m_pre_split boolean
+ (this will be the case for any wallet that upgrades to HD chain split)*/
+ m_pre_split = false;
+ }
}
else {
READWRITE(fInternal);
+ READWRITE(m_pre_split);
}
}
};
@@ -708,6 +718,7 @@ private:
std::set<int64_t> setInternalKeyPool;
std::set<int64_t> setExternalKeyPool;
+ std::set<int64_t> set_pre_split_keypool;
int64_t m_max_keypool_index = 0;
std::map<CKeyID, int64_t> m_pool_key_to_index;
@@ -774,6 +785,7 @@ public:
const std::string& GetName() const { return m_name; }
void LoadKeyPool(int64_t nIndex, const CKeyPool &keypool);
+ void MarkPreSplitKeys();
// Map from Key ID to key metadata.
std::map<CKeyID, CKeyMetadata> mapKeyMetadata;