Skip to content

Commit f999c37

Browse files
committed
Merge bitcoin/bitcoin#32449: wallet: init, don't error out when loading legacy wallets
86e1111 test: verify node skips loading legacy wallets during startup (furszy) 9f94de5 wallet: init, don't error out when loading legacy wallets (furszy) Pull request description: Instead of failing during initialization and shutting down the app when encountering a legacy wallet, skip loading the wallet and notify the user accordingly. This allows users to access migration functionalities without needing to manually remove the wallet from settings.json or resort to using the bitcoin-wallet utility. This means that GUI users will be able to use the migration button, and bitcoin-cli users will be able to call the migratewallet RPC directly after init. ACKs for top commit: achow101: ACK 86e1111 w0xlt: ACK bitcoin/bitcoin@86e1111 Tree-SHA512: 85d594a503ee7a833a23754b71b6ba4869ca34ed802c9ac0cd7b2fa56978f5fcad84ee4bd3acdcc61cf8e7f08f0789336febc5d76beae1eebf7bd51462512b78
2 parents 1c66023 + 86e1111 commit f999c37

File tree

5 files changed

+50
-5
lines changed

5 files changed

+50
-5
lines changed

src/wallet/db.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ enum class DatabaseStatus {
184184
SUCCESS,
185185
FAILED_BAD_PATH,
186186
FAILED_BAD_FORMAT,
187+
FAILED_LEGACY_DISABLED,
187188
FAILED_ALREADY_LOADED,
188189
FAILED_ALREADY_EXISTS,
189190
FAILED_NOT_FOUND,

src/wallet/load.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ bool VerifyWallets(WalletContext& context)
9999
if (!MakeWalletDatabase(wallet_file, options, status, error_string)) {
100100
if (status == DatabaseStatus::FAILED_NOT_FOUND) {
101101
chain.initWarning(Untranslated(strprintf("Skipping -wallet path that doesn't exist. %s", error_string.original)));
102+
} else if (status == DatabaseStatus::FAILED_LEGACY_DISABLED) {
103+
// Skipping legacy wallets as they will not be loaded.
104+
// This will be properly communicated to the user during the loading process.
105+
continue;
102106
} else {
103107
chain.initError(error_string);
104108
return false;
@@ -132,8 +136,13 @@ bool LoadWallets(WalletContext& context)
132136
bilingual_str error;
133137
std::vector<bilingual_str> warnings;
134138
std::unique_ptr<WalletDatabase> database = MakeWalletDatabase(name, options, status, error);
135-
if (!database && status == DatabaseStatus::FAILED_NOT_FOUND) {
136-
continue;
139+
if (!database) {
140+
if (status == DatabaseStatus::FAILED_NOT_FOUND) continue;
141+
if (status == DatabaseStatus::FAILED_LEGACY_DISABLED) {
142+
// Inform user that legacy wallet is not loaded and suggest upgrade options
143+
chain.initWarning(error);
144+
continue;
145+
}
137146
}
138147
chain.initMessage(_("Loading wallet…"));
139148
std::shared_ptr<CWallet> pwallet = database ? CWallet::Create(context, name, std::move(database), options.create_flags, error, warnings) : nullptr;

src/wallet/rpc/util.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ void HandleWalletError(const std::shared_ptr<CWallet> wallet, DatabaseStatus& st
123123
switch (status) {
124124
case DatabaseStatus::FAILED_NOT_FOUND:
125125
case DatabaseStatus::FAILED_BAD_FORMAT:
126+
case DatabaseStatus::FAILED_LEGACY_DISABLED:
126127
code = RPC_WALLET_NOT_FOUND;
127128
break;
128129
case DatabaseStatus::FAILED_ALREADY_LOADED:

src/wallet/walletdb.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1390,8 +1390,8 @@ std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const Databas
13901390

13911391
// BERKELEY_RO can only be opened if require_format was set, which only occurs in migration.
13921392
if (format && format == DatabaseFormat::BERKELEY_RO && (!options.require_format || options.require_format != DatabaseFormat::BERKELEY_RO)) {
1393-
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)));
1394-
status = DatabaseStatus::FAILED_BAD_FORMAT;
1393+
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 or the GUI option).", fs::PathToString(path)));
1394+
status = DatabaseStatus::FAILED_LEGACY_DISABLED;
13951395
return nullptr;
13961396
}
13971397

test/functional/wallet_backwards_compatibility.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
needs an older patch version.
1515
"""
1616

17+
import json
1718
import os
1819
import shutil
1920

@@ -161,6 +162,38 @@ def test_v22_inactivehdchain_path(self):
161162
except ImportError:
162163
self.log.warning("sqlite3 module not available, skipping lack of keymeta records check")
163164

165+
def test_ignore_legacy_during_startup(self, legacy_nodes, node_master):
166+
self.log.info("Test that legacy wallets are ignored during startup on v29+")
167+
168+
legacy_node = legacy_nodes[0]
169+
wallet_name = f"legacy_up_{legacy_node.version}"
170+
legacy_node.loadwallet(wallet_name)
171+
legacy_wallet = legacy_node.get_wallet_rpc(wallet_name)
172+
173+
# Move legacy wallet to latest node
174+
wallet_path = node_master.wallets_path / wallet_name
175+
wallet_path.mkdir()
176+
legacy_wallet.backupwallet(wallet_path / "wallet.dat")
177+
legacy_wallet.unloadwallet()
178+
179+
# Write wallet so it is automatically loaded during init
180+
settings_path = node_master.chain_path / "settings.json"
181+
with settings_path.open("w") as fp:
182+
json.dump({"wallet": [wallet_name]}, fp)
183+
184+
# Restart latest node and verify that the legacy wallet load is skipped without exiting early during init.
185+
self.restart_node(node_master.index, extra_args=[])
186+
# Ensure we receive the warning message and clear the stderr pipe.
187+
node_master.stderr.seek(0)
188+
warning_msg = node_master.stderr.read().decode('utf-8').strip()
189+
assert "The wallet appears to be a Legacy wallet, please use the wallet migration tool (migratewallet RPC or the GUI option)" in warning_msg
190+
node_master.stderr.truncate(0), node_master.stderr.seek(0) # reset buffer
191+
192+
# Verify the node is still running (no shutdown occurred during startup)
193+
node_master.getblockcount()
194+
# Reset settings for any subsequent test
195+
os.remove(settings_path)
196+
164197
def run_test(self):
165198
node_miner = self.nodes[0]
166199
node_master = self.nodes[1]
@@ -378,9 +411,10 @@ def run_test(self):
378411

379412
# Restore the wallet to master
380413
# Legacy wallets are no longer supported. Trying to load these should result in an error
381-
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)
414+
assert_raises_rpc_error(-18, "The wallet appears to be a Legacy wallet, please use the wallet migration tool (migratewallet RPC or the GUI option)", node_master.restorewallet, wallet_name, backup_path)
382415

383416
self.test_v22_inactivehdchain_path()
417+
self.test_ignore_legacy_during_startup(legacy_nodes, node_master)
384418

385419
if __name__ == '__main__':
386420
BackwardsCompatibilityTest(__file__).main()

0 commit comments

Comments
 (0)