diff --git a/gui/Cargo.lock b/gui/Cargo.lock index 4254399c6..2808c1b60 100644 --- a/gui/Cargo.lock +++ b/gui/Cargo.lock @@ -1956,7 +1956,7 @@ dependencies = [ [[package]] name = "liana" version = "1.0.0" -source = "git+https://github.com/wizardsardine/liana?branch=master#ebea147c2fd6768a8fee9aea8255721e305d568d" +source = "git+https://github.com/jp1ac4/liana?branch=make-bitcoind-public#b01029959d57668a9c01fc6b2d55f6cbcfdc1eb8" dependencies = [ "backtrace", "bip39", diff --git a/gui/Cargo.toml b/gui/Cargo.toml index 35011051c..d7aa82a47 100644 --- a/gui/Cargo.toml +++ b/gui/Cargo.toml @@ -15,7 +15,7 @@ path = "src/main.rs" [dependencies] async-hwi = "0.0.9" -liana = { git = "https://github.com/wizardsardine/liana", branch = "master", default-features = false } +liana = { git = "https://github.com/jp1ac4/liana", branch = "make-bitcoind-public", default-features = false } liana_ui = { path = "ui" } backtrace = "0.3" base64 = "0.13" diff --git a/gui/src/installer/step/mod.rs b/gui/src/installer/step/mod.rs index 9250e2c9c..bb7c00d49 100644 --- a/gui/src/installer/step/mod.rs +++ b/gui/src/installer/step/mod.rs @@ -9,7 +9,7 @@ pub use mnemonic::{BackupMnemonic, RecoverMnemonic}; use std::collections::HashMap; use std::net::{IpAddr, Ipv4Addr, SocketAddr, TcpListener}; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::str::FromStr; use iced::Command; @@ -71,8 +71,35 @@ pub struct DefineBitcoind { pub struct StartInternalBitcoindStep { bitcoind_datadir: PathBuf, network: Network, - started: Option>, + started: Option>, exe_path: Option, + rpc_port: Option, + bitcoind_config: Option, +} + +#[derive(PartialEq, Eq, Debug, Clone)] +pub enum StartInternalBitcoindError { + CommandError(String), + CouldNotCanonicalizeDataDir(String), + CouldNotCanonicalizeCookiePath(String), + BitcoinDError(String), +} + +impl std::fmt::Display for StartInternalBitcoindError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Self::CommandError(e) => { + write!(f, "Command to start bitcoind returned an error: {}", e) + } + Self::CouldNotCanonicalizeDataDir(e) => { + write!(f, "Failed to canonicalize datadir: {}", e) + } + Self::CouldNotCanonicalizeCookiePath(e) => { + write!(f, "Failed to canonicalize cookie path: {}", e) + } + Self::BitcoinDError(e) => write!(f, "bitcoind connection check failed: {}", e), + } + } } pub struct SelectBitcoindTypeStep { @@ -226,8 +253,8 @@ fn internal_bitcoind_config_path(liana_datadir: &PathBuf) -> PathBuf { config_path } -fn internal_bitcoind_cookie_path(liana_datadir: &PathBuf, network: &Network) -> PathBuf { - let mut cookie_path = internal_bitcoind_datadir(liana_datadir); +fn internal_bitcoind_cookie_path(bitcoind_datadir: &Path, network: &Network) -> PathBuf { + let mut cookie_path = bitcoind_datadir.to_path_buf(); if let Some(dir) = bitcoind_network_dir(network) { cookie_path.push(dir); } @@ -540,6 +567,8 @@ impl StartInternalBitcoindStep { network: Network::Bitcoin, started: None, exe_path: None, + rpc_port: None, + bitcoind_config: None, } } } @@ -550,25 +579,79 @@ impl Step for StartInternalBitcoindStep { self.exe_path = bitcoind_exe_path(); } self.network = ctx.bitcoin_config.network; + self.rpc_port = Some( + ctx.internal_bitcoind_config + .as_ref() + .expect("Already added") + .clone() + .networks + .get(&self.network) + .expect("Already added") + .rpc_port, + ); } fn update(&mut self, message: Message) -> Command { if let Message::StartInternalBitcoind(msg) = message { match msg { message::StartInternalBitcoindMsg::Start => { if let Some(path) = &self.exe_path { - let datadir = self - .bitcoind_datadir - .canonicalize() - .expect("Failed to canonicalize bitcoind datadir path"); + let datadir = match self.bitcoind_datadir.canonicalize() { + Ok(datadir) => datadir, + Err(e) => { + self.started = Some(Err( + StartInternalBitcoindError::CouldNotCanonicalizeDataDir( + e.to_string(), + ), + )); + return Command::none(); + } + }; + let args = vec![ format!("-chain={}", &self.network.to_core_arg()), format!("-datadir={}", &datadir.to_string_lossy()), ]; - let res = std::process::Command::new(path) + if let Err(e) = std::process::Command::new(path) .args(&args) .stdout(std::process::Stdio::null()) - .spawn(); - self.started = Some(res); + .spawn() + { + self.started = + Some(Err(StartInternalBitcoindError::CommandError(e.to_string()))); + return Command::none(); + } + // Need to wait for cookie file to appear. + std::thread::sleep(std::time::Duration::from_secs(1)); + let cookie_path = match internal_bitcoind_cookie_path( + &self.bitcoind_datadir, + &self.network, + ) + .canonicalize() + { + Ok(cookie_path) => cookie_path, + Err(e) => { + self.started = Some(Err( + StartInternalBitcoindError::CouldNotCanonicalizeCookiePath( + e.to_string(), + ), + )); + return Command::none(); + } + }; + + let bitcoind_config = BitcoindConfig { + cookie_path, + addr: internal_bitcoind_address(self.rpc_port.expect("Already added")), + }; + self.started = Some( + liana::BitcoinD::new( + &bitcoind_config, + "internal_bitcoind_connection_check".to_string(), + ) + .map_err(|e| StartInternalBitcoindError::BitcoinDError(e.to_string())) + .map(|_| ()), + ); + self.bitcoind_config = Some(bitcoind_config); } } }; @@ -586,26 +669,9 @@ impl Step for StartInternalBitcoindStep { } fn apply(&mut self, ctx: &mut Context) -> bool { - if let Some(Ok(_child)) = self.started.as_ref() { - // The command was executed successfully, but we have not yet checked connection. - let rpc_port = ctx - .internal_bitcoind_config - .as_ref() - .expect("Already added") - .networks - .get(&ctx.bitcoin_config.network) - .expect("Already added") - .rpc_port; - if let Ok(cookie_path) = - internal_bitcoind_cookie_path(&ctx.data_dir, &ctx.bitcoin_config.network) - .canonicalize() - { - ctx.bitcoind_config = Some(BitcoindConfig { - cookie_path, - addr: internal_bitcoind_address(rpc_port), - }); - return true; - } + if let Some(Ok(_)) = self.started { + ctx.bitcoind_config = self.bitcoind_config.clone(); + return true; } false } diff --git a/gui/src/installer/view.rs b/gui/src/installer/view.rs index d99766dae..5b6384169 100644 --- a/gui/src/installer/view.rs +++ b/gui/src/installer/view.rs @@ -28,6 +28,8 @@ use crate::{ }, }; +use super::step::StartInternalBitcoindError; + #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum Network { Mainnet, @@ -938,13 +940,12 @@ pub fn select_bitcoind_type<'a>(progress: (usize, usize)) -> Element<'a, Message pub fn start_internal_bitcoind<'a>( progress: (usize, usize), exe_path: Option<&PathBuf>, - started: Option<&Result>, + started: Option<&Result<(), StartInternalBitcoindError>>, ) -> Element<'a, Message> { let start_button = button::primary(None, "Start bitcoind").width(Length::Fixed(200.0)); let mut next_button = button::primary(None, "Next").width(Length::Fixed(200.0)); - if let Some(Ok(_child)) = started { - // Next button is pressable even if stderr, e.g. in case bitcoind already running. + if let Some(Ok(_)) = started { next_button = next_button.on_press(Message::Next); }; layout(