Skip to content

Commit 17bb63f

Browse files
committed
wallet: Disallow loading legacy wallets
Legacy wallets do not have the descriptors flag set. Don't load wallets without the descriptors flag. At the same time, we will no longer load BDB databases since they are only used for legacy wallets.
1 parent 9f04e02 commit 17bb63f

File tree

7 files changed

+42
-30
lines changed

7 files changed

+42
-30
lines changed

src/wallet/db.h

-1
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,6 @@ class WalletDatabase
182182
};
183183

184184
enum class DatabaseFormat {
185-
BERKELEY,
186185
SQLITE,
187186
BERKELEY_RO,
188187
BERKELEY_SWAP,

src/wallet/init.cpp

-5
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,6 @@ void WalletInit::AddWalletOptions(ArgsManager& argsman) const
9898

9999
bool WalletInit::ParameterInteraction() const
100100
{
101-
#ifdef USE_BDB
102-
if (!BerkeleyDatabaseSanityCheck()) {
103-
return InitError(Untranslated("A version conflict was detected between the run-time BerkeleyDB library and the one used during compilation."));
104-
}
105-
#endif
106101
if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
107102
for (const std::string& wallet : gArgs.GetArgs("-wallet")) {
108103
LogPrintf("%s: parameter interaction: -disablewallet -> ignoring -wallet=%s\n", __func__, wallet);

src/wallet/test/util.h

-5
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55
#ifndef BITCOIN_WALLET_TEST_UTIL_H
66
#define BITCOIN_WALLET_TEST_UTIL_H
77

8-
#include <bitcoin-build-config.h> // IWYU pragma: keep
9-
108
#include <addresstype.h>
119
#include <wallet/db.h>
1210
#include <wallet/scriptpubkeyman.h>
@@ -28,9 +26,6 @@ struct WalletContext;
2826

2927
static const DatabaseFormat DATABASE_FORMATS[] = {
3028
DatabaseFormat::SQLITE,
31-
#ifdef USE_BDB
32-
DatabaseFormat::BERKELEY,
33-
#endif
3429
};
3530

3631
const std::string ADDRESS_BCRT1_UNSPENDABLE = "bcrt1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3xueyj";

src/wallet/wallet.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -3052,6 +3052,9 @@ std::shared_ptr<CWallet> CWallet::Create(WalletContext& context, const std::stri
30523052
error = strprintf(_("Unexpected legacy entry in descriptor wallet found. Loading wallet %s\n\n"
30533053
"The wallet might have been tampered with or created with malicious intent.\n"), walletFile);
30543054
return nullptr;
3055+
} else if (nLoadWalletRet == DBErrors::LEGACY_WALLET) {
3056+
error = strprintf(_("Error loading %s: Wallet is a legacy wallet. Please migrate to a descriptor wallet using the migration tool (migratewallet RPC)."), walletFile);
3057+
return nullptr;
30553058
} else {
30563059
error = strprintf(_("Error loading %s"), walletFile);
30573060
return nullptr;

src/wallet/walletdb.cpp

+14-18
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,11 @@ static DBErrors LoadWalletFlags(CWallet* pwallet, DatabaseBatch& batch) EXCLUSIV
485485
pwallet->WalletLogPrintf("Error reading wallet database: Unknown non-tolerable wallet flags found\n");
486486
return DBErrors::TOO_NEW;
487487
}
488+
// All wallets must be descriptor wallets unless opened with a bdb_ro db
489+
// bdb_ro is only used for legacy to descriptor migration.
490+
if (pwallet->GetDatabase().Format() != "bdb_ro" && !pwallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
491+
return DBErrors::LEGACY_WALLET;
492+
}
488493
}
489494
return DBErrors::LOAD_OK;
490495
}
@@ -1432,7 +1437,7 @@ std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const Databas
14321437
std::optional<DatabaseFormat> format;
14331438
if (exists) {
14341439
if (IsBDBFile(BDBDataFile(path))) {
1435-
format = DatabaseFormat::BERKELEY;
1440+
format = DatabaseFormat::BERKELEY_RO;
14361441
}
14371442
if (IsSQLiteFile(SQLiteDataFile(path))) {
14381443
if (format) {
@@ -1460,9 +1465,11 @@ std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const Databas
14601465
return nullptr;
14611466
}
14621467

1463-
// If BERKELEY was the format, then change the format from BERKELEY to BERKELEY_RO
1464-
if (format && options.require_format && format == DatabaseFormat::BERKELEY && options.require_format == DatabaseFormat::BERKELEY_RO) {
1465-
format = DatabaseFormat::BERKELEY_RO;
1468+
// BERKELEY_RO can only be opened if require_format was set, which only occurs in migration.
1469+
if (format && format == DatabaseFormat::BERKELEY_RO && (!options.require_format || options.require_format != DatabaseFormat::BERKELEY_RO)) {
1470+
error = Untranslated(strprintf("Failed to open database path '%s'. The wallet appears to be a Legacy wallet, please use the wallet migration tool (migratewallet RPC).", fs::PathToString(path)));
1471+
status = DatabaseStatus::FAILED_BAD_FORMAT;
1472+
return nullptr;
14661473
}
14671474

14681475
// A db already exists so format is set, but options also specifies the format, so make sure they agree
@@ -1475,12 +1482,8 @@ std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const Databas
14751482
// Format is not set when a db doesn't already exist, so use the format specified by the options if it is set.
14761483
if (!format && options.require_format) format = options.require_format;
14771484

1478-
// If the format is not specified or detected, choose the default format based on what is available. We prefer BDB over SQLite for now.
14791485
if (!format) {
14801486
format = DatabaseFormat::SQLITE;
1481-
#ifdef USE_BDB
1482-
format = DatabaseFormat::BERKELEY;
1483-
#endif
14841487
}
14851488

14861489
if (format == DatabaseFormat::SQLITE) {
@@ -1491,15 +1494,8 @@ std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const Databas
14911494
return MakeBerkeleyRODatabase(path, options, status, error);
14921495
}
14931496

1494-
#ifdef USE_BDB
1495-
if constexpr (true) {
1496-
return MakeBerkeleyDatabase(path, options, status, error);
1497-
} else
1498-
#endif
1499-
{
1500-
error = Untranslated(strprintf("Failed to open database path '%s'. Build does not support Berkeley DB database format.", fs::PathToString(path)));
1501-
status = DatabaseStatus::FAILED_BAD_FORMAT;
1502-
return nullptr;
1503-
}
1497+
error = Untranslated(STR_INTERNAL_BUG("Could not determine wallet format"));
1498+
status = DatabaseStatus::FAILED_BAD_FORMAT;
1499+
return nullptr;
15041500
}
15051501
} // namespace wallet

src/wallet/walletdb.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ enum class DBErrors : int
5555
UNKNOWN_DESCRIPTOR = 6,
5656
LOAD_FAIL = 7,
5757
UNEXPECTED_LEGACY_ENTRY = 8,
58-
CORRUPT = 9,
58+
LEGACY_WALLET = 9,
59+
CORRUPT = 10,
5960
};
6061

6162
namespace DBKeys {

test/functional/wallet_backwards_compatibility.py

+23
Original file line numberDiff line numberDiff line change
@@ -285,5 +285,28 @@ def run_test(self):
285285
info = wallet_res.getaddressinfo(address)
286286
assert_equal(info, addr_info)
287287

288+
self.log.info("Test that a wallet from a legacy only node must be migrated, from:")
289+
for node in legacy_nodes:
290+
self.log.info(f"- {node.version}")
291+
wallet_name = f"legacy_up_{node.version}"
292+
if self.major_version_at_least(node, 21):
293+
node.rpc.createwallet(wallet_name=wallet_name, descriptors=False)
294+
else:
295+
node.rpc.createwallet(wallet_name=wallet_name)
296+
wallet_prev = node.get_wallet_rpc(wallet_name)
297+
address = wallet_prev.getnewaddress('', "bech32")
298+
addr_info = wallet_prev.getaddressinfo(address)
299+
300+
# Make a backup of the wallet file
301+
backup_path = os.path.join(self.options.tmpdir, f"{wallet_name}.dat")
302+
wallet_prev.backupwallet(backup_path)
303+
304+
# Remove the wallet from old node
305+
wallet_prev.unloadwallet()
306+
307+
# Restore the wallet to master
308+
# Legacy wallets are no longer supported. Trying to load these should result in an error
309+
assert_raises_rpc_error(-18, "The wallet appears to be a Legacy wallet, please use the wallet migration tool (migratewallet RPC)", node_master.restorewallet, wallet_name, backup_path)
310+
288311
if __name__ == '__main__':
289312
BackwardsCompatibilityTest(__file__).main()

0 commit comments

Comments
 (0)