Merge #892: Drop watchonly wallet migration for old Windows datadir

6d2833fc1857daf140f7efc8d0b81c662076edd4 Drop watchonly wallet migration for old Windows datadir (Antoine Poinsot)

Pull request description:

  It was introduced as a temporary hack in v2 (released in August 2023) for migrating datadirs created on Windows using Liana v1 (May 2023).

  Presumably Windows users wouldn't have used the beta versions which preceded v1 release with any real funds. This removal would go in v5, released around end of January / early February. Presumably any Windows user who created a mainnet datadir within the 3 months period where the bug was present would have opened its Liana at least once in the following 6 months after the migration was released.

  In the unlikely case a user on Windows created a mainnet wallet on the very first release of Liana, funded it, didn't touch it for more than 6 months and tried to open it later using the latest version of Liana available they are instructed to first run Liana v4 (so the migration is performed automatically at startup) before running the latest version of Liana.

  Nits on the wording welcome!

ACKs for top commit:
  jp1ac4:
    ACK 6d2833fc18.

Tree-SHA512: cd9369e3305dde4bcc572d004f4b5f430df79ef174507f473c9b76552155dcda17be46689b1602de1dfdb87680456e3e9a3b4115b352319e9b43005c2c9f8594
This commit is contained in:
Antoine Poinsot 2023-12-20 15:30:28 +01:00
commit 5b93e1f76c
No known key found for this signature in database
GPG Key ID: E13FC145CD3F4304
2 changed files with 17 additions and 103 deletions

View File

@ -94,6 +94,8 @@ pub enum StartupError {
Bitcoind(BitcoindError),
#[cfg(unix)]
Daemonization(&'static str),
#[cfg(windows)]
NoWatchonlyInDatadir,
}
impl fmt::Display for StartupError {
@ -116,6 +118,17 @@ impl fmt::Display for StartupError {
Self::Bitcoind(e) => write!(f, "Error setting up bitcoind interface: '{}'.", e),
#[cfg(unix)]
Self::Daemonization(e) => write!(f, "Error when daemonizing: '{}'.", e),
#[cfg(windows)]
Self::NoWatchonlyInDatadir => {
write!(
f,
"A data directory exists with no watchonly wallet. Really old versions of Liana used to not \
store the bitcoind watchonly wallet under their own datadir on Windows. A migration will be \
necessary to be able to use such an old datadir with recent versions of Liana. The migration \
is automatically performed by Liana version 4 and older. If you want to salvage this datadir \
first run Liana v4 before running more recent Liana versions."
)
}
}
}
}
@ -188,70 +201,6 @@ fn setup_sqlite(
Ok(sqlite)
}
// Try to copy the watchonly wallet from its former location on Windows to its new location.
fn copy_watchonly_wallet(
bitcoind_cookie_path: &path::Path,
bitcoin_net: miniscript::bitcoin::Network,
wallet_name: &str,
new_wallet_path: &path::Path,
) -> bool {
// For the main network both the wallet and the cookie file are stored at the root of the
// datadir. For test networks the wallet is in "<datadir>/<network>/wallets/<wallet_name>/" and
// the cookie file in "<datadir>/<network>/".
let parent_dir = match bitcoind_cookie_path.parent() {
Some(d) => d,
None => {
log::error!("Could not find the parent directory of the bitcoind cookie file.");
return false;
}
};
let wallet_path = match bitcoin_net {
miniscript::bitcoin::Network::Bitcoin => parent_dir.join(wallet_name),
miniscript::bitcoin::Network::Testnet
| miniscript::bitcoin::Network::Signet
| miniscript::bitcoin::Network::Regtest => parent_dir
.join("wallets")
.join(wallet_name)
.join("wallet.dat"),
net => panic!(
"Unsupported network '{}', unknown at the time of writing.",
net
),
};
if wallet_path.exists() {
log::info!(
"Found the watchonly wallet file at the former location: '{}'. Copying it to our own datadir.",
wallet_path.as_path().to_string_lossy()
);
if let Err(e) = fs::create_dir(new_wallet_path) {
log::error!(
"Error while creating the watchonly wallet directory at {}: {}",
wallet_path.to_string_lossy(),
e
);
return false;
}
let new_wallet_dat_path = new_wallet_path.join("wallet.dat");
if let Err(e) = fs::copy(wallet_path, new_wallet_dat_path) {
log::error!(
"Error while copying the watchonly wallet to our own datadir: {}",
e
);
false
} else {
log::info!("Successfully copied the watchonly wallet file.");
true
}
} else {
log::error!(
"No watchonly wallet found at '{}'.",
wallet_path.as_path().to_string_lossy()
);
false
}
}
// Connect to bitcoind. Setup the watchonly wallet, and do some sanity checks.
// If all went well, returns the interface to bitcoind.
fn setup_bitcoind(
@ -285,23 +234,10 @@ fn setup_bitcoind(
log::info!("Creating a new watchonly wallet on bitcoind.");
bitcoind.create_watchonly_wallet(&config.main_descriptor)?;
log::info!("Watchonly wallet created.");
} else if !wo_path.exists() && !cfg!(test) {
// TODO: remove this hack.
// NOTE: this is Windows-specific but we don't gate it upon a windows target to be able to
// test this codepath in a functional test.
log::info!(
"A data directory exists with no watchonly wallet. This is most likely due to \
having been created to an older version of Liana on Windows, where the watchonly \
wallet would live under bitcoind's datadir. Trying to find the older wallet and copy it in our own datadir."
);
let wo_name = "lianad_watchonly_wallet";
if !copy_watchonly_wallet(
&bitcoind_config.cookie_path,
config.bitcoin_config.network,
wo_name,
wo_path.as_path(),
) {
panic!("Cannot continue without a watchonly wallet. Please contact support.");
} else {
#[cfg(windows)]
if !cfg!(test) && !wo_path.exists() {
return Err(StartupError::NoWatchonlyInDatadir);
}
}
log::info!("Loading our watchonly wallet on bitcoind.");

View File

@ -349,25 +349,3 @@ def test_retry_on_workqueue_exceeded(lianad, bitcoind, executor):
# We should have retried the request to bitcoind, which should now succeed along with the call.
# This just checks the response we get is sane, nothing particular with this field.
assert "block_height" in f_liana.result(TIMEOUT)
def test_wo_wallet_copy_from_bitcoind_datadir(lianad, bitcoind):
"""Simulate an old install on Windows and make sure the watchonly wallet gets migrated."""
wo_name = "lianad_watchonly_wallet"
old_wo_path = os.path.join(bitcoind.bitcoin_dir, "regtest", "wallets", wo_name)
new_wo_path = os.path.join(lianad.datadir, "regtest", wo_name)
# Start lianad. It'll have created the watchonly within our datadir. Move it where it would
# have been created by Liana v1 on Windows.
lianad.stop()
shutil.copytree(new_wo_path, old_wo_path)
shutil.rmtree(new_wo_path)
assert not os.path.isdir(new_wo_path)
# Now restart lianad. It should detect it within the bitcoind datadir and copy it to its own.
lianad.start()
assert os.path.isdir(new_wo_path)
assert lianad.is_in_log(
"A data directory exists with no watchonly wallet. This is most likely due to.*"
)
assert lianad.is_in_log("Successfully copied the watchonly wallet file.")