Skip to content

Commit 32a522f

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 373afc5 commit 32a522f

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
@@ -3052,7 +3052,11 @@ 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 {
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;
3058+
}
3059+
else {
30563060
error = strprintf(_("Error loading %s"), walletFile);
30573061
return nullptr;
30583062
}

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
}
@@ -1417,7 +1422,7 @@ std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const Databas
14171422
std::optional<DatabaseFormat> format;
14181423
if (exists) {
14191424
if (IsBDBFile(BDBDataFile(path))) {
1420-
format = DatabaseFormat::BERKELEY;
1425+
format = DatabaseFormat::BERKELEY_RO;
14211426
}
14221427
if (IsSQLiteFile(SQLiteDataFile(path))) {
14231428
if (format) {
@@ -1445,9 +1450,11 @@ std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const Databas
14451450
return nullptr;
14461451
}
14471452

1448-
// If BERKELEY was the format, then change the format from BERKELEY to BERKELEY_RO
1449-
if (format && options.require_format && format == DatabaseFormat::BERKELEY && options.require_format == DatabaseFormat::BERKELEY_RO) {
1450-
format = DatabaseFormat::BERKELEY_RO;
1453+
// BERKELEY_RO can only be opened if require_format was set, which only occurs in migration.
1454+
if (format && format == DatabaseFormat::BERKELEY_RO && (!options.require_format || options.require_format != DatabaseFormat::BERKELEY_RO)) {
1455+
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)));
1456+
status = DatabaseStatus::FAILED_BAD_FORMAT;
1457+
return nullptr;
14511458
}
14521459

14531460
// A db already exists so format is set, but options also specifies the format, so make sure they agree
@@ -1463,9 +1470,6 @@ std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const Databas
14631470
// If the format is not specified or detected, choose the default format based on what is available. We prefer BDB over SQLite for now.
14641471
if (!format) {
14651472
format = DatabaseFormat::SQLITE;
1466-
#ifdef USE_BDB
1467-
format = DatabaseFormat::BERKELEY;
1468-
#endif
14691473
}
14701474

14711475
if (format == DatabaseFormat::SQLITE) {
@@ -1476,15 +1480,8 @@ std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const Databas
14761480
return MakeBerkeleyRODatabase(path, options, status, error);
14771481
}
14781482

1479-
#ifdef USE_BDB
1480-
if constexpr (true) {
1481-
return MakeBerkeleyDatabase(path, options, status, error);
1482-
} else
1483-
#endif
1484-
{
1485-
error = Untranslated(strprintf("Failed to open database path '%s'. Build does not support Berkeley DB database format.", fs::PathToString(path)));
1486-
status = DatabaseStatus::FAILED_BAD_FORMAT;
1487-
return nullptr;
1488-
}
1483+
error = Untranslated(STR_INTERNAL_BUG("Could not determine wallet format"));
1484+
status = DatabaseStatus::FAILED_BAD_FORMAT;
1485+
return nullptr;
14891486
}
14901487
} // 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)