Skip to content

Commit

Permalink
Merge #592: gui: configure and start bitcoind
Browse files Browse the repository at this point in the history
698eff7 doc: Add step to choose bitcoind type (jp1ac4)
36cf85d gui: add option to use internal bitcoind (jp1ac4)
765c68b installer: allow for different previous messages (jp1ac4)

Pull request description:

  This is to resolve part of #570 (configure and start an already-installed bitcoind).

  I'm opening this draft PR so that you can provide feedback and check if any changes in approach are required.

  I've added optional steps to the installer for the user to configure and start an "internal" bitcoind that uses `~/.liana/bitcoind_datadir` as its data directory.

  The main things missing are:
  - [x] Make it work on Windows.
  - [x] Stop internal bitcoind when Liana is not running.
  - [x] Start this internal bitcoind, if applicable, when returning to Liana after installation. One option for this would be to check in the Liana config file whether the bitcoind `.cookie` file is within the `~/.liana/bitcoind_datadir` folder, which would indicate that the internal bitcoind should be used, and then to start it (we might need to store the executable path if it's not in PATH).
  - [x] Tests!

ACKs for top commit:
  edouardparis:
    ACK 698eff7

Tree-SHA512: ce561cd74944b9a80e73bf0f45eafc613a033b115276c208cba95a00920409d3ec56b81cf50fd29eb60c82b96c1d9295a51b8df7e7ca62a4474dd77461564dd0
  • Loading branch information
edouardparis committed Aug 23, 2023
2 parents 557c775 + 698eff7 commit afd10bf
Show file tree
Hide file tree
Showing 15 changed files with 1,073 additions and 36 deletions.
15 changes: 12 additions & 3 deletions doc/TRY.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,18 @@ mnemonic as well as the descriptor in the next two screens. Otherwise just make
ticking the boxes. If you are using a signing device simulator you'll have a step for registering
the descriptor on it.

Finally, configure the connection to `bitcoind`. The default should work for what we did in this
guide. Click on continue and finalize the installation.

You can then decide whether you would like to manage `bitcoind` yourself or let Liana configure
and start/stop it while the GUI is being used:
- If you choose to manage `bitcoind` yourself, the next step will be to configure the connection.
The default should work for what we did in this guide.
- If you choose to let Liana manage `bitcoind`, the next step will search for a `bitcoind`
executable on your computer and start it, using `<Liana data directory>/bitcoind_datadir` as the
data directory and creating a `bitcoin.conf` file therein.

Click on continue and finalize the installation.

In the case of a Liana-managed `bitcoind`, it will be automatically started the next time you
start Liana for the given network.

## Step 3: have fun

Expand Down
85 changes: 85 additions & 0 deletions gui/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions gui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ toml = "0.5"

chrono = "0.4"

rust-ini = "0.19.0"
which = "4.4.0"

[dev-dependencies]
tokio = {version = "1.9.0", features = ["rt", "macros"]}

Expand Down
17 changes: 16 additions & 1 deletion gui/src/app/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@ use serde::{Deserialize, Serialize};
use std::path::{Path, PathBuf};
use tracing_subscriber::filter;

/// Config required to start internal bitcoind.
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct InternalBitcoindExeConfig {
/// Internal bitcoind executable path.
pub exe_path: PathBuf,
/// Internal bitcoind data dir.
pub data_dir: PathBuf,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Config {
/// Path to lianad configuration file.
Expand All @@ -16,18 +25,24 @@ pub struct Config {
/// hardware wallets config.
/// LEGACY: Use Settings module instead.
pub hardware_wallets: Option<Vec<HardwareWalletConfig>>,
/// Internal bitcoind executable config.
pub internal_bitcoind_exe_config: Option<InternalBitcoindExeConfig>,
}

pub const DEFAULT_FILE_NAME: &str = "gui.toml";

impl Config {
pub fn new(daemon_config_path: PathBuf) -> Self {
pub fn new(
daemon_config_path: PathBuf,
internal_bitcoind_exe_config: Option<InternalBitcoindExeConfig>,
) -> Self {
Self {
daemon_config_path: Some(daemon_config_path),
daemon_rpc_path: None,
log_level: None,
debug: None,
hardware_wallets: None,
internal_bitcoind_exe_config,
}
}

Expand Down
8 changes: 8 additions & 0 deletions gui/src/app/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ use state::{

use crate::{
app::{cache::Cache, error::Error, menu::Menu, wallet::Wallet},
bitcoind::stop_internal_bitcoind,
daemon::{embedded::EmbeddedDaemon, Daemon},
};

Expand Down Expand Up @@ -115,6 +116,13 @@ impl App {
if !self.daemon.is_external() {
self.daemon.stop();
info!("Internal daemon stopped");
if self.config.internal_bitcoind_exe_config.is_some() {
if let Some(daemon_config) = self.daemon.config() {
if let Some(bitcoind_config) = &daemon_config.bitcoind_config {
stop_internal_bitcoind(bitcoind_config);
}
}
}
}
}

Expand Down
77 changes: 77 additions & 0 deletions gui/src/bitcoind.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
use liana::{config::BitcoindConfig, miniscript::bitcoin};

use tracing::{info, warn};

use crate::app::config::InternalBitcoindExeConfig;

/// Possible errors when starting bitcoind.
#[derive(PartialEq, Eq, Debug, Clone)]
pub enum StartInternalBitcoindError {
CommandError(String),
CouldNotCanonicalizeDataDir(String),
CouldNotCanonicalizeCookiePath(String),
CookieFileNotFound(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::CookieFileNotFound(path) => {
write!(
f,
"Cookie file was not found at the expected path: {}",
path
)
}
Self::BitcoinDError(e) => write!(f, "bitcoind connection check failed: {}", e),
}
}
}

/// Start internal bitcoind for the given network.
pub fn start_internal_bitcoind(
network: &bitcoin::Network,
exe_config: InternalBitcoindExeConfig,
) -> Result<std::process::Child, StartInternalBitcoindError> {
let args = vec![
format!("-chain={}", network.to_core_arg()),
format!(
"-datadir={}",
exe_config
.data_dir
.canonicalize()
.map_err(|e| StartInternalBitcoindError::CouldNotCanonicalizeDataDir(
e.to_string()
))?
.to_string_lossy()
),
];
std::process::Command::new(exe_config.exe_path)
.args(&args)
.stdout(std::process::Stdio::null()) // We still get bitcoind's logs in debug.log.
.spawn()
.map_err(|e| StartInternalBitcoindError::CommandError(e.to_string()))
}

/// Stop (internal) bitcoind.
pub fn stop_internal_bitcoind(bitcoind_config: &BitcoindConfig) {
match liana::BitcoinD::new(bitcoind_config, "internal_bitcoind_stop".to_string()) {
Ok(bitcoind) => {
info!("Stopping internal bitcoind...");
bitcoind.stop();
}
Err(e) => {
warn!("Could not create interface to internal bitcoind: '{}'.", e);
}
}
}
9 changes: 9 additions & 0 deletions gui/src/installer/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::time::Duration;

use crate::{
app::{
config::InternalBitcoindExeConfig,
settings::{KeySetting, Settings, WalletSetting},
wallet::DEFAULT_WALLET_NAME,
},
Expand All @@ -18,6 +19,8 @@ use liana::{
miniscript::bitcoin,
};

use super::step::InternalBitcoindConfig;

#[derive(Clone)]
pub struct Context {
pub bitcoin_config: BitcoinConfig,
Expand All @@ -30,6 +33,9 @@ pub struct Context {
// In case a user entered a mnemonic,
// we dont want to override the generated signer with it.
pub recovered_signer: Option<Arc<Signer>>,
pub bitcoind_is_external: bool,
pub internal_bitcoind_config: Option<InternalBitcoindConfig>,
pub internal_bitcoind_exe_config: Option<InternalBitcoindExeConfig>,
}

impl Context {
Expand All @@ -46,6 +52,9 @@ impl Context {
data_dir,
hw_is_used: false,
recovered_signer: None,
bitcoind_is_external: true,
internal_bitcoind_config: None,
internal_bitcoind_exe_config: None,
}
}

Expand Down
15 changes: 15 additions & 0 deletions gui/src/installer/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ pub enum Message {
UseHotSigner,
Installed(Result<PathBuf, Error>),
Network(Network),
SelectBitcoindType(SelectBitcoindTypeMsg),
InternalBitcoind(InternalBitcoindMsg),
DefineBitcoind(DefineBitcoind),
DefineDescriptor(DefineDescriptor),
ImportXpub(usize, Result<DescriptorPublicKey, Error>),
Expand All @@ -43,6 +45,19 @@ pub enum DefineBitcoind {
PingBitcoind,
}

#[derive(Debug, Clone)]
pub enum SelectBitcoindTypeMsg {
UseExternal(bool),
}

#[derive(Debug, Clone)]
pub enum InternalBitcoindMsg {
Previous,
Reload,
DefineConfig,
Start,
}

#[derive(Debug, Clone)]
pub enum DefineDescriptor {
ImportDescriptor(String),
Expand Down
Loading

0 comments on commit afd10bf

Please sign in to comment.