Skip to content

Commit 4f0e11b

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 c39de5f commit 4f0e11b

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

@@ -27,9 +25,6 @@ struct WalletContext;
2725

2826
static const DatabaseFormat DATABASE_FORMATS[] = {
2927
DatabaseFormat::SQLITE,
30-
#ifdef USE_BDB
31-
DatabaseFormat::BERKELEY,
32-
#endif
3328
};
3429

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

src/wallet/wallet.cpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -3034,7 +3034,11 @@ std::shared_ptr<CWallet> CWallet::Create(WalletContext& context, const std::stri
30343034
error = strprintf(_("Unexpected legacy entry in descriptor wallet found. Loading wallet %s\n\n"
30353035
"The wallet might have been tampered with or created with malicious intent.\n"), walletFile);
30363036
return nullptr;
3037-
} else {
3037+
} else if (nLoadWalletRet == DBErrors::LEGACY_WALLET) {
3038+
error = strprintf(_("Error loading %s: Wallet is a legacy wallet. Please migrate to a descriptor wallet using the migration tool (migratewallet RPC)."), walletFile);
3039+
return nullptr;
3040+
}
3041+
else {
30383042
error = strprintf(_("Error loading %s"), walletFile);
30393043
return nullptr;
30403044
}

src/wallet/walletdb.cpp

+14-17
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,11 @@ static DBErrors LoadWalletFlags(CWallet* pwallet, DatabaseBatch& batch) EXCLUSIV
480480
pwallet->WalletLogPrintf("Error reading wallet database: Unknown non-tolerable wallet flags found\n");
481481
return DBErrors::TOO_NEW;
482482
}
483+
// All wallets must be descriptor wallets unless opened with a bdb_ro db
484+
// bdb_ro is only used for legacy to descriptor migration.
485+
if (pwallet->GetDatabase().Format() != "bdb_ro" && !pwallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
486+
return DBErrors::LEGACY_WALLET;
487+
}
483488
}
484489
return DBErrors::LOAD_OK;
485490
}
@@ -1389,7 +1394,7 @@ std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const Databas
13891394
std::optional<DatabaseFormat> format;
13901395
if (exists) {
13911396
if (IsBDBFile(BDBDataFile(path))) {
1392-
format = DatabaseFormat::BERKELEY;
1397+
format = DatabaseFormat::BERKELEY_RO;
13931398
}
13941399
if (IsSQLiteFile(SQLiteDataFile(path))) {
13951400
if (format) {
@@ -1417,9 +1422,11 @@ std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const Databas
14171422
return nullptr;
14181423
}
14191424

1420-
// If BERKELEY was the format, then change the format from BERKELEY to BERKELEY_RO
1421-
if (format && options.require_format && format == DatabaseFormat::BERKELEY && options.require_format == DatabaseFormat::BERKELEY_RO) {
1422-
format = DatabaseFormat::BERKELEY_RO;
1425+
// BERKELEY_RO can only be opened if require_format was set, which only occurs in migration.
1426+
if (format && format == DatabaseFormat::BERKELEY_RO && (!options.require_format || options.require_format != DatabaseFormat::BERKELEY_RO)) {
1427+
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)));
1428+
status = DatabaseStatus::FAILED_BAD_FORMAT;
1429+
return nullptr;
14231430
}
14241431

14251432
// A db already exists so format is set, but options also specifies the format, so make sure they agree
@@ -1435,9 +1442,6 @@ std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const Databas
14351442
// If the format is not specified or detected, choose the default format based on what is available. We prefer BDB over SQLite for now.
14361443
if (!format) {
14371444
format = DatabaseFormat::SQLITE;
1438-
#ifdef USE_BDB
1439-
format = DatabaseFormat::BERKELEY;
1440-
#endif
14411445
}
14421446

14431447
if (format == DatabaseFormat::SQLITE) {
@@ -1448,15 +1452,8 @@ std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const Databas
14481452
return MakeBerkeleyRODatabase(path, options, status, error);
14491453
}
14501454

1451-
#ifdef USE_BDB
1452-
if constexpr (true) {
1453-
return MakeBerkeleyDatabase(path, options, status, error);
1454-
} else
1455-
#endif
1456-
{
1457-
error = Untranslated(strprintf("Failed to open database path '%s'. Build does not support Berkeley DB database format.", fs::PathToString(path)));
1458-
status = DatabaseStatus::FAILED_BAD_FORMAT;
1459-
return nullptr;
1460-
}
1455+
error = Untranslated(STR_INTERNAL_BUG("Could not determine wallet format"));
1456+
status = DatabaseStatus::FAILED_BAD_FORMAT;
1457+
return nullptr;
14611458
}
14621459
} // 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
@@ -304,5 +304,41 @@ def run_test(self):
304304
info = wallet_res.getaddressinfo(address)
305305
assert_equal(info, addr_info)
306306

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

0 commit comments

Comments
 (0)