aboutsummaryrefslogtreecommitdiff
path: root/src/wallet/walletdb.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet/walletdb.cpp')
-rw-r--r--src/wallet/walletdb.cpp108
1 files changed, 92 insertions, 16 deletions
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 79e0a330b7..6a8f0d2481 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -59,6 +59,7 @@ const std::string WALLETDESCRIPTORCKEY{"walletdescriptorckey"};
const std::string WALLETDESCRIPTORKEY{"walletdescriptorkey"};
const std::string WATCHMETA{"watchmeta"};
const std::string WATCHS{"watchs"};
+const std::unordered_set<std::string> LEGACY_TYPES{CRYPTED_KEY, CSCRIPT, DEFAULTKEY, HDCHAIN, KEYMETA, KEY, OLD_KEY, POOL, WATCHMETA, WATCHS};
} // namespace DBKeys
//
@@ -313,6 +314,7 @@ public:
std::map<std::pair<uint256, CKeyID>, std::pair<CPubKey, std::vector<unsigned char>>> m_descriptor_crypt_keys;
std::map<uint160, CHDChain> m_hd_chains;
bool tx_corrupt{false};
+ bool descriptor_unknown{false};
CWalletScanState() = default;
};
@@ -626,7 +628,13 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
uint256 id;
ssKey >> id;
WalletDescriptor desc;
- ssValue >> desc;
+ try {
+ ssValue >> desc;
+ } catch (const std::ios_base::failure& e) {
+ strErr = e.what();
+ wss.descriptor_unknown = true;
+ return false;
+ }
if (wss.m_descriptor_caches.count(id) == 0) {
wss.m_descriptor_caches[id] = DescriptorCache();
}
@@ -766,6 +774,12 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
DBErrors result = DBErrors::LOAD_OK;
LOCK(pwallet->cs_wallet);
+
+ // Last client version to open this wallet
+ int last_client = CLIENT_VERSION;
+ bool has_last_client = m_batch->Read(DBKeys::VERSION, last_client);
+ pwallet->WalletLogPrintf("Wallet file version = %d, last client version = %d\n", pwallet->GetVersion(), last_client);
+
try {
int nMinVersion = 0;
if (m_batch->Read(DBKeys::MINVERSION, nMinVersion)) {
@@ -831,6 +845,13 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
// Set tx_corrupt back to false so that the error is only printed once (per corrupt tx)
wss.tx_corrupt = false;
result = DBErrors::CORRUPT;
+ } else if (wss.descriptor_unknown) {
+ strErr = strprintf("Error: Unrecognized descriptor found in wallet %s. ", pwallet->GetName());
+ strErr += (last_client > CLIENT_VERSION) ? "The wallet might had been created on a newer version. " :
+ "The database might be corrupted or the software version is not compatible with one of your wallet descriptors. ";
+ strErr += "Please try running the latest software version";
+ pwallet->WalletLogPrintf("%s\n", strErr);
+ return DBErrors::UNKNOWN_DESCRIPTOR;
} else {
// Leave other errors alone, if we try to fix them we might make things worse.
fNoncriticalErrors = true; // ... but do warn the user there is something wrong.
@@ -856,18 +877,18 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
}
// Set the descriptor caches
- for (auto desc_cache_pair : wss.m_descriptor_caches) {
+ for (const auto& desc_cache_pair : wss.m_descriptor_caches) {
auto spk_man = pwallet->GetScriptPubKeyMan(desc_cache_pair.first);
assert(spk_man);
((DescriptorScriptPubKeyMan*)spk_man)->SetCache(desc_cache_pair.second);
}
// Set the descriptor keys
- for (auto desc_key_pair : wss.m_descriptor_keys) {
+ for (const auto& desc_key_pair : wss.m_descriptor_keys) {
auto spk_man = pwallet->GetScriptPubKeyMan(desc_key_pair.first.first);
((DescriptorScriptPubKeyMan*)spk_man)->AddKey(desc_key_pair.first.second, desc_key_pair.second);
}
- for (auto desc_key_pair : wss.m_descriptor_crypt_keys) {
+ for (const auto& desc_key_pair : wss.m_descriptor_crypt_keys) {
auto spk_man = pwallet->GetScriptPubKeyMan(desc_key_pair.first.first);
((DescriptorScriptPubKeyMan*)spk_man)->AddCryptedKey(desc_key_pair.first.second, desc_key_pair.second.first, desc_key_pair.second.second);
}
@@ -883,13 +904,6 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
if (result != DBErrors::LOAD_OK)
return result;
- // Last client version to open this wallet, was previously the file version number
- int last_client = CLIENT_VERSION;
- m_batch->Read(DBKeys::VERSION, last_client);
-
- int wallet_version = pwallet->GetVersion();
- pwallet->WalletLogPrintf("Wallet File Version = %d\n", wallet_version > 0 ? wallet_version : last_client);
-
pwallet->WalletLogPrintf("Keys: %u plaintext, %u encrypted, %u w/ metadata, %u total. Unknown wallet records: %u\n",
wss.nKeys, wss.nCKeys, wss.nKeyMeta, wss.nKeys + wss.nCKeys, wss.m_unknown_records);
@@ -909,7 +923,7 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
if (wss.fIsEncrypted && (last_client == 40000 || last_client == 50000))
return DBErrors::NEED_REWRITE;
- if (last_client < CLIENT_VERSION) // Update
+ if (!has_last_client || last_client != CLIENT_VERSION) // Update
m_batch->Write(DBKeys::VERSION, CLIENT_VERSION);
if (wss.fAnyUnordered)
@@ -1085,6 +1099,45 @@ bool WalletBatch::WriteWalletFlags(const uint64_t flags)
return WriteIC(DBKeys::FLAGS, flags);
}
+bool WalletBatch::EraseRecords(const std::unordered_set<std::string>& types)
+{
+ // Get cursor
+ if (!m_batch->StartCursor())
+ {
+ return false;
+ }
+
+ // Iterate the DB and look for any records that have the type prefixes
+ while (true)
+ {
+ // Read next record
+ CDataStream key(SER_DISK, CLIENT_VERSION);
+ CDataStream value(SER_DISK, CLIENT_VERSION);
+ bool complete;
+ bool ret = m_batch->ReadAtCursor(key, value, complete);
+ if (complete) {
+ break;
+ }
+ else if (!ret)
+ {
+ m_batch->CloseCursor();
+ return false;
+ }
+
+ // Make a copy of key to avoid data being deleted by the following read of the type
+ Span<const unsigned char> key_data = MakeUCharSpan(key);
+
+ std::string type;
+ key >> type;
+
+ if (types.count(type) > 0) {
+ m_batch->Erase(key_data);
+ }
+ }
+ m_batch->CloseCursor();
+ return true;
+}
+
bool WalletBatch::TxnBegin()
{
return m_batch->TxnBegin();
@@ -1186,13 +1239,36 @@ std::unique_ptr<WalletDatabase> CreateDummyWalletDatabase()
}
/** Return object for accessing temporary in-memory database. */
-std::unique_ptr<WalletDatabase> CreateMockWalletDatabase()
+std::unique_ptr<WalletDatabase> CreateMockWalletDatabase(DatabaseOptions& options)
{
- DatabaseOptions options;
+
+ std::optional<DatabaseFormat> format;
+ if (options.require_format) format = options.require_format;
+ if (!format) {
+#ifdef USE_BDB
+ format = DatabaseFormat::BERKELEY;
+#endif
+#ifdef USE_SQLITE
+ format = DatabaseFormat::SQLITE;
+#endif
+ }
+
+ if (format == DatabaseFormat::SQLITE) {
#ifdef USE_SQLITE
- return std::make_unique<SQLiteDatabase>("", "", options, true);
-#elif USE_BDB
+ return std::make_unique<SQLiteDatabase>(":memory:", "", options, true);
+#endif
+ assert(false);
+ }
+
+#ifdef USE_BDB
return std::make_unique<BerkeleyDatabase>(std::make_shared<BerkeleyEnvironment>(), "", options);
#endif
+ assert(false);
+}
+
+std::unique_ptr<WalletDatabase> CreateMockWalletDatabase()
+{
+ DatabaseOptions options;
+ return CreateMockWalletDatabase(options);
}
} // namespace wallet