Skip to content

Commit b849415

Browse files
committed
wallet: Disallow 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 189eb8c commit b849415

File tree

7 files changed

+57
-30
lines changed

7 files changed

+57
-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

+5-1
Original file line numberDiff line numberDiff line change
@@ -3046,7 +3046,11 @@ std::shared_ptr<CWallet> CWallet::Create(WalletContext& context, const std::stri
30463046
error = strprintf(_("Unexpected legacy entry in descriptor wallet found. Loading wallet %s\n\n"
30473047
"The wallet might have been tampered with or created with malicious intent.\n"), walletFile);
30483048
return nullptr;
3049-
} else {
3049+
} else if (nLoadWalletRet == DBErrors::LEGACY_WALLET) {
3050+
error = strprintf(_("Error loading %s: Wallet is a legacy wallet. Please migrate to a descriptor wallet using the migration tool (migratewallet RPC)."), walletFile);
3051+
return nullptr;
3052+
}
3053+
else {
30503054
error = strprintf(_("Error loading %s"), walletFile);
30513055
return nullptr;
30523056
}

src/wallet/walletdb.cpp

+14-17
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
}
@@ -1409,7 +1414,7 @@ std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const Databas
14091414
std::optional<DatabaseFormat> format;
14101415
if (exists) {
14111416
if (IsBDBFile(BDBDataFile(path))) {
1412-
format = DatabaseFormat::BERKELEY;
1417+
format = DatabaseFormat::BERKELEY_RO;
14131418
}
14141419
if (IsSQLiteFile(SQLiteDataFile(path))) {
14151420
if (format) {
@@ -1437,9 +1442,11 @@ std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const Databas
14371442
return nullptr;
14381443
}
14391444

1440-
// If BERKELEY was the format, then change the format from BERKELEY to BERKELEY_RO
1441-
if (format && options.require_format && format == DatabaseFormat::BERKELEY && options.require_format == DatabaseFormat::BERKELEY_RO) {
1442-
format = DatabaseFormat::BERKELEY_RO;
1445+
// BERKELEY_RO can only be opened if require_format was set, which only occurs in migration.
1446+
if (format && format == DatabaseFormat::BERKELEY_RO && (!options.require_format || options.require_format != DatabaseFormat::BERKELEY_RO)) {
1447+
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)));
1448+
status = DatabaseStatus::FAILED_BAD_FORMAT;
1449+
return nullptr;
14431450
}
14441451

14451452
// A db already exists so format is set, but options also specifies the format, so make sure they agree
@@ -1455,9 +1462,6 @@ std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const Databas
14551462
// If the format is not specified or detected, choose the default format based on what is available. We prefer BDB over SQLite for now.
14561463
if (!format) {
14571464
format = DatabaseFormat::SQLITE;
1458-
#ifdef USE_BDB
1459-
format = DatabaseFormat::BERKELEY;
1460-
#endif
14611465
}
14621466

14631467
if (format == DatabaseFormat::SQLITE) {
@@ -1468,15 +1472,8 @@ std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const Databas
14681472
return MakeBerkeleyRODatabase(path, options, status, error);
14691473
}
14701474

1471-
#ifdef USE_BDB
1472-
if constexpr (true) {
1473-
return MakeBerkeleyDatabase(path, options, status, error);
1474-
} else
1475-
#endif
1476-
{
1477-
error = Untranslated(strprintf("Failed to open database path '%s'. Build does not support Berkeley DB database format.", fs::PathToString(path)));
1478-
status = DatabaseStatus::FAILED_BAD_FORMAT;
1479-
return nullptr;
1480-
}
1475+
error = Untranslated(STR_INTERNAL_BUG("Could not determine wallet format"));
1476+
status = DatabaseStatus::FAILED_BAD_FORMAT;
1477+
return nullptr;
14811478
}
14821479
} // 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

+36
Original file line numberDiff line numberDiff line change
@@ -305,5 +305,41 @@ def run_test(self):
305305
info = wallet_res.getaddressinfo(address)
306306
assert_equal(info, addr_info)
307307

308+
self.log.info("Test that a wallet from a legacy only node must be migrated, from:")
309+
for node in legacy_nodes:
310+
self.log.info(f"- {node.version}")
311+
wallet_name = f"legacy_up_{node.version}"
312+
if self.major_version_less_than(node, 17):
313+
# createwallet is only available in 0.17+
314+
self.restart_node(node.index, extra_args=[f"-wallet={wallet_name}"])
315+
wallet_prev = node.get_wallet_rpc(wallet_name)
316+
address = wallet_prev.getnewaddress('', "bech32")
317+
addr_info = wallet_prev.validateaddress(address)
318+
else:
319+
if self.major_version_at_least(node, 21):
320+
node.rpc.createwallet(wallet_name=wallet_name, descriptors=False)
321+
else:
322+
node.rpc.createwallet(wallet_name=wallet_name)
323+
wallet_prev = node.get_wallet_rpc(wallet_name)
324+
address = wallet_prev.getnewaddress('', "bech32")
325+
addr_info = wallet_prev.getaddressinfo(address)
326+
327+
hdkeypath = addr_info["hdkeypath"].replace("'", "h")
328+
pubkey = addr_info["pubkey"]
329+
330+
# Make a backup of the wallet file
331+
backup_path = os.path.join(self.options.tmpdir, f"{wallet_name}.dat")
332+
wallet_prev.backupwallet(backup_path)
333+
334+
# Remove the wallet from old node
335+
if self.major_version_at_least(node, 17):
336+
wallet_prev.unloadwallet()
337+
else:
338+
self.stop_node(node.index)
339+
340+
# Restore the wallet to master
341+
# Legacy wallets are no longer supported. Trying to load these should result in an error
342+
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)
343+
308344
if __name__ == '__main__':
309345
BackwardsCompatibilityTest(__file__).main()

0 commit comments

Comments
 (0)