diff --git a/liana-gui/src/app/wallet.rs b/liana-gui/src/app/wallet.rs index 6aae66f9..a87a8360 100644 --- a/liana-gui/src/app/wallet.rs +++ b/liana-gui/src/app/wallet.rs @@ -80,6 +80,11 @@ impl Wallet { } } + pub fn with_pinned_at(mut self, pinned_at: Option) -> Self { + self.pinned_at = pinned_at; + self + } + pub fn with_key_aliases(mut self, aliases: HashMap) -> Self { self.keys_aliases = aliases; self @@ -125,6 +130,7 @@ impl Wallet { .with_key_aliases(wallet_settings.keys_aliases()) .with_provider_keys(wallet_settings.provider_keys()) .with_name(wallet_settings.name) + .with_pinned_at(wallet_settings.pinned_at) .with_hardware_wallets(wallet_settings.hardware_wallets)) } } diff --git a/liana-gui/src/backup.rs b/liana-gui/src/backup.rs index cb6664d5..ba721f2a 100644 --- a/liana-gui/src/backup.rs +++ b/liana-gui/src/backup.rs @@ -132,29 +132,26 @@ impl Backup { let mut proprietary = serde_json::Map::new(); proprietary.insert(LIANA_VERSION_KEY.to_string(), liana_version().into()); - let config = extract_daemon_config(&ctx).map_err(|e| Error::Daemon(e.to_string()))?; + let settings = match &ctx.remote_backend { + // This append while user is importing a wallet already created on Liana-Connect. + RemoteBackend::WithWallet(backend) => extract_remote_gui_settings(&ctx, backend).await, + // Other cases are about wallet creation, the ctx contains all the keys aliases and + // descriptor registration hmacs. + _ => extract_local_gui_settings(&ctx), + }; + + let config = + extract_daemon_config(&ctx, &settings).map_err(|e| Error::Daemon(e.to_string()))?; if let Ok(config) = serde_json::to_value(config) { proprietary.insert(CONFIG_KEY.to_string(), config); } - let settings = if ctx.bitcoin_backend.is_some() { - Some(extract_local_gui_settings(&ctx)) - } else { - match &ctx.remote_backend { - RemoteBackend::WithWallet(backend) => { - Some(extract_remote_gui_settings(&ctx, backend).await) - } - _ => None, - } - }; - let name = if let Some(settings) = settings { + let name = { let name = settings.name.clone(); if let Ok(settings) = serde_json::to_value(settings) { proprietary.insert(SETTINGS_KEY.to_string(), settings); } Some(name) - } else { - None }; ctx.keys.iter().for_each(|(k, s)| { diff --git a/liana-gui/src/dir.rs b/liana-gui/src/dir.rs index 5b498704..9ced7df7 100644 --- a/liana-gui/src/dir.rs +++ b/liana-gui/src/dir.rs @@ -1,4 +1,6 @@ +use crate::app::settings::WalletSettings; use liana::miniscript::bitcoin::Network; +use lianad::datadir::DataDirectory; use std::path::{Path, PathBuf}; #[derive(Clone, Debug, PartialEq)] @@ -78,11 +80,20 @@ impl NetworkDirectory { self.0.as_path().exists() } pub fn init(&self) -> Result<(), Box> { - create_directory(self.0.as_path()) + create_directory(self.0.as_path())?; + create_directory(&self.0.as_path().join("data")) } pub fn path(&self) -> &Path { self.0.as_path() } + pub fn lianad_data_directory(&self, settings: &WalletSettings) -> DataDirectory { + let mut path = self.0.clone(); + if let Some(t) = settings.pinned_at { + path.push("data"); + path.push(format!("{}-{}", settings.descriptor_checksum, t)) + } + DataDirectory::new(path) + } } #[derive(Clone, Debug)] diff --git a/liana-gui/src/installer/mod.rs b/liana-gui/src/installer/mod.rs index 959791ab..b67d6cca 100644 --- a/liana-gui/src/installer/mod.rs +++ b/liana-gui/src/installer/mod.rs @@ -17,7 +17,7 @@ use std::ops::Deref; use tracing::{error, info, warn}; use std::io::Write; -use std::path::PathBuf; +use std::path::Path; use std::sync::{Arc, Mutex}; use crate::{ @@ -28,7 +28,7 @@ use crate::{ }, backup, daemon::DaemonError, - dir::{LianaDirectory, NetworkDirectory}, + dir::LianaDirectory, hw::{HardwareWalletConfig, HardwareWallets}, services::{ self, @@ -370,7 +370,8 @@ pub async fn install_local_wallet( .init() .map_err(|e| Error::Unexpected(format!("Failed to create datadir path: {}", e)))?; - let cfg: lianad::config::Config = extract_daemon_config(&ctx)?; + let wallet_settings = extract_local_gui_settings(&ctx); + let cfg: lianad::config::Config = extract_daemon_config(&ctx, &wallet_settings)?; daemon_check(cfg.clone())?; @@ -381,9 +382,11 @@ pub async fn install_local_wallet( .map_err(|e| Error::Unexpected(format!("Failed to serialize daemon config: {}", e)))?; // create lianad configuration file - let _daemon_config_path = create_and_write_file( - &network_datadir, - "daemon.toml", + create_and_write_file( + &network_datadir + .lianad_data_directory(&wallet_settings) + .path() + .join("daemon.toml"), daemon_config.to_string().as_bytes(), )?; @@ -412,21 +415,24 @@ pub async fn install_local_wallet( } // create liana GUI configuration file - let _gui_config_path = create_and_write_file( - &network_datadir, - gui_config::DEFAULT_FILE_NAME, - toml::to_string(&gui_config::Config::new( - // Installer started a bitcoind, it is expected that gui will start it on startup - ctx.internal_bitcoind.is_some(), - )) - .map_err(|e| Error::Unexpected(format!("Failed to serialize gui config: {}", e)))? - .as_bytes(), - )?; - - info!("Gui configuration file created"); + let gui_config_path = network_datadir + .path() + .join(gui_config::DEFAULT_FILE_NAME) + .to_path_buf(); + if !gui_config_path.exists() { + create_and_write_file( + &gui_config_path, + toml::to_string(&gui_config::Config::new( + // Installer started a bitcoind, it is expected that gui will start it on startup + ctx.internal_bitcoind.is_some(), + )) + .map_err(|e| Error::Unexpected(format!("Failed to serialize gui config: {}", e)))? + .as_bytes(), + )?; + info!("Gui configuration file created"); + } // create liana GUI settings file - let wallet_settings = extract_local_gui_settings(&ctx); update_settings_file(&network_datadir, |mut settings| { settings.wallets.push(wallet_settings.clone()); settings @@ -476,19 +482,19 @@ pub async fn create_remote_wallet( } // create liana GUI configuration file - let _gui_config_path = create_and_write_file( - &network_datadir, - gui_config::DEFAULT_FILE_NAME, - toml::to_string(&gui_config::Config { - log_level: Some("info".to_string()), - debug: Some(false), - start_internal_bitcoind: false, - }) - .map_err(|e| Error::Unexpected(format!("Failed to serialize gui config: {}", e)))? - .as_bytes(), - )?; - - info!("Gui configuration file created"); + let gui_config_path = network_datadir + .path() + .join(gui_config::DEFAULT_FILE_NAME) + .to_path_buf(); + if !gui_config_path.exists() { + create_and_write_file( + &gui_config_path, + toml::to_string(&gui_config::Config::new(false)) + .map_err(|e| Error::Unexpected(format!("Failed to serialize gui config: {}", e)))? + .as_bytes(), + )?; + info!("Gui configuration file created"); + } let pks: Vec<_> = ctx .keys @@ -599,19 +605,19 @@ pub async fn import_remote_wallet( info!("Settings file created"); // create liana GUI configuration file - let _gui_config_path = create_and_write_file( - &network_datadir, - gui_config::DEFAULT_FILE_NAME, - toml::to_string(&gui_config::Config { - log_level: Some("info".to_string()), - debug: Some(false), - start_internal_bitcoind: false, - }) - .map_err(|e| Error::Unexpected(format!("Failed to serialize gui config: {}", e)))? - .as_bytes(), - )?; - - info!("Gui configuration file created"); + let gui_config_path = network_datadir + .path() + .join(gui_config::DEFAULT_FILE_NAME) + .to_path_buf(); + if !gui_config_path.exists() { + create_and_write_file( + &gui_config_path, + toml::to_string(&gui_config::Config::new(false)) + .map_err(|e| Error::Unexpected(format!("Failed to serialize gui config: {}", e)))? + .as_bytes(), + )?; + info!("Gui configuration file created"); + } let backend = backend.inner_client(); if let Err(e) = update_connect_cache( @@ -632,18 +638,12 @@ pub async fn import_remote_wallet( Ok(wallet_settings) } -pub fn create_and_write_file( - network_datadir: &NetworkDirectory, - file_name: &str, - data: &[u8], -) -> Result { - let mut path = network_datadir.path().to_path_buf(); - path.push(file_name); +pub fn create_and_write_file(path: &Path, data: &[u8]) -> Result<(), Error> { let mut file = - std::fs::File::create(&path).map_err(|e| Error::CannotCreateFile(e.to_string()))?; + std::fs::File::create(path).map_err(|e| Error::CannotCreateFile(e.to_string()))?; file.write_all(data) .map_err(|e| Error::CannotWriteToFile(e.to_string()))?; - Ok(path) + Ok(()) } // if the wallet is using the remote backend, then the hardware wallet settings and @@ -711,10 +711,16 @@ pub fn extract_local_gui_settings(ctx: &Context) -> WalletSettings { } } -pub fn extract_daemon_config(ctx: &Context) -> Result { +pub fn extract_daemon_config(ctx: &Context, settings: &WalletSettings) -> Result { let data_directory = ctx .liana_directory .network_directory(ctx.bitcoin_config.network) + .lianad_data_directory(settings); + data_directory + .init() + .map_err(|e| Error::CannotCreateDatadir(e.to_string()))?; + + let data_directory = data_directory .path() .to_path_buf() .canonicalize() diff --git a/liana-gui/src/loader.rs b/liana-gui/src/loader.rs index b595f955..604d2b2a 100644 --- a/liana-gui/src/loader.rs +++ b/liana-gui/src/loader.rs @@ -121,7 +121,10 @@ impl Loader { backup: Option, wallet_settings: WalletSettings, ) -> (Self, Task) { - let path = socket_path(&datadir_path, network); + let socket_path = datadir_path + .network_directory(network) + .lianad_data_directory(&wallet_settings) + .lianad_rpc_socket_path(); ( Loader { network, @@ -134,7 +137,7 @@ impl Loader { wallet_settings, backup, }, - Task::perform(connect(path), Message::Loaded), + Task::perform(connect(socket_path), Message::Loaded), ) } @@ -204,6 +207,7 @@ impl Loader { self.datadir_path.clone(), self.start_bitcoind(), self.network, + self.wallet_settings.clone(), ), Message::Started, ); @@ -551,9 +555,11 @@ pub async fn start_bitcoind_and_daemon( liana_datadir_path: LianaDirectory, start_internal_bitcoind: bool, network: bitcoin::Network, + settings: WalletSettings, ) -> StartedResult { let mut config_path = liana_datadir_path .network_directory(network) + .lianad_data_directory(&settings) .path() .to_path_buf(); config_path.push("daemon.toml"); @@ -629,10 +635,3 @@ impl From for Error { Error::Daemon(error) } } - -/// default lianad socket path is .liana/bitcoin/lianad_rpc -fn socket_path(datadir: &LianaDirectory, network: bitcoin::Network) -> PathBuf { - let mut path = datadir.network_directory(network).path().to_path_buf(); - path.push("lianad_rpc"); - path -}