config: separate the Bitcoin and bitcoind-specifc settings
This commit is contained in:
parent
ea3595349d
commit
e510c0a30d
@ -93,7 +93,7 @@ fn socket_file(conf_file: Option<PathBuf>) -> PathBuf {
|
||||
|
||||
[
|
||||
data_dir,
|
||||
config.bitcoind_config.network.to_string().as_str(),
|
||||
config.bitcoin_config.network.to_string().as_str(),
|
||||
"minisafed_rpc",
|
||||
]
|
||||
.iter()
|
||||
|
||||
@ -16,7 +16,7 @@ impl DaemonControl {
|
||||
pub fn get_info(&self) -> GetInfoResult {
|
||||
GetInfoResult {
|
||||
version: VERSION.to_string(),
|
||||
network: self.config.bitcoind_config.network,
|
||||
network: self.config.bitcoin_config.network,
|
||||
blockheight: self.bitcoin.chain_tip().height,
|
||||
sync: self.bitcoin.sync_progress(),
|
||||
descriptors: GetInfoDescriptors {
|
||||
@ -39,7 +39,7 @@ impl DaemonControl {
|
||||
.derive(index.into())
|
||||
.translate_pk2(|xpk| xpk.derive_public_key(&self.secp))
|
||||
.expect("All pubkeys were derived, no wildcard.")
|
||||
.address(self.config.bitcoind_config.network)
|
||||
.address(self.config.bitcoin_config.network)
|
||||
.expect("It's a wsh() descriptor");
|
||||
GetAddressResult { address }
|
||||
}
|
||||
|
||||
@ -54,13 +54,17 @@ fn default_daemon() -> bool {
|
||||
/// Everything we need to know for talking to bitcoind serenely
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct BitcoindConfig {
|
||||
/// The network we are operating on, one of "bitcoin", "testnet", "regtest"
|
||||
pub network: Network,
|
||||
/// Path to bitcoind's cookie file, to authenticate the RPC connection
|
||||
pub cookie_path: PathBuf,
|
||||
/// The IP:port bitcoind's RPC is listening on
|
||||
pub addr: SocketAddr,
|
||||
/// The poll interval for bitcoind
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct BitcoinConfig {
|
||||
/// The network we are operating on, one of "bitcoin", "testnet", "regtest", "signet"
|
||||
pub network: Network,
|
||||
/// The poll interval for the Bitcoin interface
|
||||
#[serde(
|
||||
deserialize_with = "deserialize_duration",
|
||||
serialize_with = "serialize_duration",
|
||||
@ -91,8 +95,10 @@ pub struct Config {
|
||||
serialize_with = "serialize_to_string"
|
||||
)]
|
||||
pub main_descriptor: Descriptor<DescriptorPublicKey>,
|
||||
/// Everything we need to know to talk to bitcoind
|
||||
pub bitcoind_config: BitcoindConfig,
|
||||
/// Settings for the Bitcoin interface
|
||||
pub bitcoin_config: BitcoinConfig,
|
||||
/// Settings specific to bitcoind as the Bitcoin interface
|
||||
pub bitcoind_config: Option<BitcoindConfig>,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
@ -195,7 +201,7 @@ impl Config {
|
||||
/// Make sure the settings are sane.
|
||||
pub fn check(&self) -> Result<(), ConfigError> {
|
||||
// Check the network of the xpubs in the descriptors
|
||||
let expected_network = match self.bitcoind_config.network {
|
||||
let expected_network = match self.bitcoin_config.network {
|
||||
Network::Bitcoin => Network::Bitcoin,
|
||||
_ => Network::Testnet,
|
||||
};
|
||||
@ -214,7 +220,7 @@ impl Config {
|
||||
if unexpected_net {
|
||||
return Err(ConfigError::Unexpected(format!(
|
||||
"Our bitcoin network is {} but one xpub is not for network {}",
|
||||
self.bitcoind_config.network, expected_network
|
||||
self.bitcoin_config.network, expected_network
|
||||
)));
|
||||
}
|
||||
|
||||
@ -238,11 +244,13 @@ mod tests {
|
||||
log_level = "debug"
|
||||
main_descriptor = "wsh(andor(thresh(1,pk(xpub6BaZSKgpaVvibu2k78QsqeDWXp92xLHZxiu1WoqLB9hKhsBf3miBUDX7PJLgSPvkj66ThVHTqdnbXpeu8crXFmDUd4HeM4s4miQS2xsv3Qb/*)),and_v(v:multi(2,03b506a1dbe57b4bf48c95e0c7d417b87dd3b4349d290d2e7e9ba72c912652d80a,0295e7f5d12a2061f1fd2286cefec592dff656a19f55f4f01305d6aa56630880ce),older(4)),thresh(2,pkh(xpub6AHA9hZDN11k2ijHMeS5QqHx2KP9aMBRhTDqANMnwVtdyw2TDYRmF8PjpvwUFcL1Et8Hj59S3gTSMcUQ5gAqTz3Wd8EsMTmF3DChhqPQBnU/*),a:pkh(xpub6AaffFGfH6WXfm6pwWzmUMuECQnoLeB3agMKaLyEBZ5ZVfwtnS5VJKqXBt8o5ooCWVy2H87GsZshp7DeKE25eWLyd1Ccuh2ZubQUkgpiVux/*))))#532k8uvf"
|
||||
|
||||
[bitcoind_config]
|
||||
[bitcoin_config]
|
||||
network = "bitcoin"
|
||||
poll_interval_secs = 18
|
||||
|
||||
[bitcoind_config]
|
||||
cookie_path = "/home/user/.bitcoin/.cookie"
|
||||
addr = "127.0.0.1:8332"
|
||||
poll_interval_secs = 18
|
||||
"#.trim_start().replace(" ", "");
|
||||
toml::from_str::<Config>(&toml_str).expect("Deserializing toml_str");
|
||||
|
||||
@ -253,11 +261,13 @@ mod tests {
|
||||
log_level = 'TRACE'
|
||||
main_descriptor = 'wsh(andor(thresh(1,pk(xpub6BaZSKgpaVvibu2k78QsqeDWXp92xLHZxiu1WoqLB9hKhsBf3miBUDX7PJLgSPvkj66ThVHTqdnbXpeu8crXFmDUd4HeM4s4miQS2xsv3Qb/*)),and_v(v:multi(2,03b506a1dbe57b4bf48c95e0c7d417b87dd3b4349d290d2e7e9ba72c912652d80a,0295e7f5d12a2061f1fd2286cefec592dff656a19f55f4f01305d6aa56630880ce),older(4)),thresh(2,pkh(xpub6AHA9hZDN11k2ijHMeS5QqHx2KP9aMBRhTDqANMnwVtdyw2TDYRmF8PjpvwUFcL1Et8Hj59S3gTSMcUQ5gAqTz3Wd8EsMTmF3DChhqPQBnU/*),a:pkh(xpub6AaffFGfH6WXfm6pwWzmUMuECQnoLeB3agMKaLyEBZ5ZVfwtnS5VJKqXBt8o5ooCWVy2H87GsZshp7DeKE25eWLyd1Ccuh2ZubQUkgpiVux/*))))#532k8uvf'
|
||||
|
||||
[bitcoind_config]
|
||||
[bitcoin_config]
|
||||
network = 'bitcoin'
|
||||
poll_interval_secs = 18
|
||||
|
||||
[bitcoind_config]
|
||||
cookie_path = '/home/user/.bitcoin/.cookie'
|
||||
addr = '127.0.0.1:8332'
|
||||
poll_interval_secs = 18
|
||||
"#.trim_start().replace(" ", "");
|
||||
let parsed = toml::from_str::<Config>(&toml_str).expect("Deserializing toml_str");
|
||||
let serialized = toml::to_string_pretty(&parsed).expect("Serializing to toml");
|
||||
@ -273,16 +283,18 @@ mod tests {
|
||||
# The main descriptor semantics aren't checked, yet.
|
||||
main_descriptor = "wsh(andor(thresh(1,pk(xpub6BaZSKgpaVvibu2k78QsqeDWXp92xLHZxiu1WoqLB9hKhsBf3miBUDX7PJLgSPvkj66ThVHTqdnbXpeu8crXFmDUd4HeM4s4miQS2xsv3Qb/*)),and_v(v:multi(2,03b506a1dbe57b4bf48c95e0c7d417b87dd3b4349d290d2e7e9ba72c912652d80a,0295e7f5d12a2061f1fd2286cefec592dff656a19f55f4f01305d6aa56630880ce),older(4)),thresh(2,pkh(xpub6AHA9hZDN11k2ijHMeS5QqHx2KP9aMBRhTDqANMnwVtdyw2TDYRmF8PjpvwUFcL1Et8Hj59S3gTSMcUQ5gAqTz3Wd8EsMTmF3DChhqPQBnU/*),a:pkh(xpub6AaffFGfH6WXfm6pwWzmUMuECQnoLeB3agMKaLyEBZ5ZVfwtnS5VJKqXBt8o5ooCWVy2H87GsZshp7DeKE25eWLyd1Ccuh2ZubQUkgpiVux/*))))#532k88vf"
|
||||
|
||||
[bitcoind_config]
|
||||
[bitcoin_config]
|
||||
network = "bitcoin"
|
||||
poll_interval_secs = 18
|
||||
|
||||
[bitcoind_config]
|
||||
cookie_path = "/home/user/.bitcoin/.cookie"
|
||||
addr = "127.0.0.1:8332"
|
||||
poll_interval_secs = 18
|
||||
"#;
|
||||
let config_res: Result<Config, toml::de::Error> = toml::from_str(toml_str);
|
||||
config_res.expect_err("Deserializing an invalid toml_str");
|
||||
|
||||
// Not enough parameters: missing the network
|
||||
// Not enough parameters: missing the Bitcoin network
|
||||
let toml_str = r#"
|
||||
daemon = false
|
||||
log_level = "trace"
|
||||
@ -291,10 +303,12 @@ mod tests {
|
||||
# The main descriptor semantics aren't checked, yet.
|
||||
main_descriptor = "wsh(andor(thresh(1,pk(xpub6BaZSKgpaVvibu2k78QsqeDWXp92xLHZxiu1WoqLB9hKhsBf3miBUDX7PJLgSPvkj66ThVHTqdnbXpeu8crXFmDUd4HeM4s4miQS2xsv3Qb/*)),and_v(v:multi(2,03b506a1dbe57b4bf48c95e0c7d417b87dd3b4349d290d2e7e9ba72c912652d80a,0295e7f5d12a2061f1fd2286cefec592dff656a19f55f4f01305d6aa56630880ce),older(4)),thresh(2,pkh(xpub6AHA9hZDN11k2ijHMeS5QqHx2KP9aMBRhTDqANMnwVtdyw2TDYRmF8PjpvwUFcL1Et8Hj59S3gTSMcUQ5gAqTz3Wd8EsMTmF3DChhqPQBnU/*),a:pkh(xpub6AaffFGfH6WXfm6pwWzmUMuECQnoLeB3agMKaLyEBZ5ZVfwtnS5VJKqXBt8o5ooCWVy2H87GsZshp7DeKE25eWLyd1Ccuh2ZubQUkgpiVux/*))))#532k8uvf"
|
||||
|
||||
[bitcoin_config]
|
||||
poll_interval_secs = 18
|
||||
|
||||
[bitcoind_config]
|
||||
cookie_path = "/home/user/.bitcoin/.cookie"
|
||||
addr = "127.0.0.1:8332"
|
||||
poll_interval_secs = 18
|
||||
"#;
|
||||
let config_res: Result<Config, toml::de::Error> = toml::from_str(toml_str);
|
||||
config_res.expect_err("Deserializing an invalid toml_str");
|
||||
|
||||
33
src/lib.rs
33
src/lib.rs
@ -80,6 +80,7 @@ pub enum StartupError {
|
||||
Io(io::Error),
|
||||
DefaultDataDirNotFound,
|
||||
DatadirCreation(path::PathBuf, io::Error),
|
||||
MissingBitcoindConfig,
|
||||
Database(SqliteDbError),
|
||||
Bitcoind(BitcoindError),
|
||||
#[cfg(unix)]
|
||||
@ -98,6 +99,10 @@ impl fmt::Display for StartupError {
|
||||
f,
|
||||
"Could not create data directory at '{}': '{}'", dir_path.display(), e
|
||||
),
|
||||
Self::MissingBitcoindConfig => write!(
|
||||
f,
|
||||
"Our Bitcoin interface is bitcoind but we have no 'bitcoind_config' entry in the configuration."
|
||||
),
|
||||
Self::Database(e) => write!(f, "Error initializing database: '{}'.", e),
|
||||
Self::Bitcoind(e) => write!(f, "Error setting up bitcoind interface: '{}'.", e),
|
||||
#[cfg(unix)]
|
||||
@ -160,14 +165,14 @@ fn setup_sqlite(
|
||||
.collect();
|
||||
let options = if fresh_data_dir {
|
||||
Some(FreshDbOptions {
|
||||
bitcoind_network: config.bitcoind_config.network,
|
||||
bitcoind_network: config.bitcoin_config.network,
|
||||
main_descriptor: config.main_descriptor.clone(),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let sqlite = SqliteDb::new(db_path, options)?;
|
||||
sqlite.sanity_check(config.bitcoind_config.network, &config.main_descriptor)?;
|
||||
sqlite.sanity_check(config.bitcoin_config.network, &config.main_descriptor)?;
|
||||
log::info!("Database initialized and checked.");
|
||||
|
||||
Ok(sqlite)
|
||||
@ -185,7 +190,10 @@ fn setup_bitcoind(
|
||||
.iter()
|
||||
.collect();
|
||||
let bitcoind = BitcoinD::new(
|
||||
&config.bitcoind_config,
|
||||
config
|
||||
.bitcoind_config
|
||||
.as_ref()
|
||||
.ok_or(StartupError::MissingBitcoindConfig)?,
|
||||
wo_path.to_str().expect("Must be valid unicode").to_string(),
|
||||
)?;
|
||||
if fresh_data_dir {
|
||||
@ -193,7 +201,7 @@ fn setup_bitcoind(
|
||||
log::info!("Created a new watchonly wallet on bitcoind.");
|
||||
}
|
||||
bitcoind.try_load_watchonly_wallet();
|
||||
bitcoind.sanity_check(&config.main_descriptor, config.bitcoind_config.network)?;
|
||||
bitcoind.sanity_check(&config.main_descriptor, config.bitcoin_config.network)?;
|
||||
log::info!("Connection to bitcoind established and checked.");
|
||||
|
||||
Ok(bitcoind.with_retry_limit(None))
|
||||
@ -250,7 +258,7 @@ impl DaemonHandle {
|
||||
let mut data_dir = config
|
||||
.data_dir()
|
||||
.ok_or(StartupError::DefaultDataDirNotFound)?;
|
||||
data_dir.push(config.bitcoind_config.network.to_string());
|
||||
data_dir.push(config.bitcoin_config.network.to_string());
|
||||
let fresh_data_dir = !data_dir.as_path().exists();
|
||||
if fresh_data_dir {
|
||||
create_datadir(&data_dir)?;
|
||||
@ -295,7 +303,7 @@ impl DaemonHandle {
|
||||
let bitcoin_poller = poller::Poller::start(
|
||||
bit.clone(),
|
||||
db.clone(),
|
||||
config.bitcoind_config.poll_interval_secs,
|
||||
config.bitcoin_config.poll_interval_secs,
|
||||
);
|
||||
|
||||
// Finally, set up the API.
|
||||
@ -328,7 +336,7 @@ impl DaemonHandle {
|
||||
.data_dir()
|
||||
.expect("Didn't fail at startup, must not now")
|
||||
.as_path(),
|
||||
path::Path::new(&control.config.bitcoind_config.network.to_string()),
|
||||
path::Path::new(&control.config.bitcoin_config.network.to_string()),
|
||||
path::Path::new("minisafed_rpc"),
|
||||
]
|
||||
.iter()
|
||||
@ -356,7 +364,7 @@ impl DaemonHandle {
|
||||
#[cfg(all(test, unix))]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::config::BitcoindConfig;
|
||||
use crate::config::{BitcoinConfig, BitcoindConfig};
|
||||
|
||||
use miniscript::{bitcoin, Descriptor, DescriptorPublicKey};
|
||||
use std::{
|
||||
@ -543,18 +551,21 @@ mod tests {
|
||||
net::SocketAddrV4::new(net::Ipv4Addr::new(127, 0, 0, 1), 0).into();
|
||||
let server = net::TcpListener::bind(&addr).unwrap();
|
||||
let addr = server.local_addr().unwrap();
|
||||
let bitcoind_config = BitcoindConfig {
|
||||
let bitcoin_config = BitcoinConfig {
|
||||
network,
|
||||
poll_interval_secs: time::Duration::from_secs(2),
|
||||
};
|
||||
let bitcoind_config = BitcoindConfig {
|
||||
addr,
|
||||
cookie_path: cookie.clone(),
|
||||
poll_interval_secs: time::Duration::from_secs(2),
|
||||
};
|
||||
|
||||
// Create a dummy config with this bitcoind
|
||||
let desc_str = "wsh(andor(pk(xpub68JJTXc1MWK8KLW4HGLXZBJknja7kDUJuFHnM424LbziEXsfkh1WQCiEjjHw4zLqSUm4rvhgyGkkuRowE9tCJSgt3TQB5J3SKAbZ2SdcKST/*),older(10000),pk(xpub68JJTXc1MWK8PEQozKsRatrUHXKFNkD1Cb1BuQU9Xr5moCv87anqGyXLyUd4KpnDyZgo3gz4aN1r3NiaoweFW8UutBsBbgKHzaD5HkTkifK/*)))#tk6wzexy";
|
||||
let desc = Descriptor::<DescriptorPublicKey>::from_str(desc_str).unwrap();
|
||||
let config = Config {
|
||||
bitcoind_config,
|
||||
bitcoin_config,
|
||||
bitcoind_config: Some(bitcoind_config),
|
||||
data_dir: Some(data_dir.clone()),
|
||||
#[cfg(unix)]
|
||||
daemon: false,
|
||||
|
||||
@ -33,11 +33,13 @@ class Minisafed(TailableProc):
|
||||
|
||||
f.write(f'main_descriptor = "{main_desc}"\n')
|
||||
|
||||
f.write("[bitcoind_config]\n")
|
||||
f.write("[bitcoin_config]\n")
|
||||
f.write('network = "regtest"\n')
|
||||
f.write("poll_interval_secs = 1\n")
|
||||
|
||||
f.write("[bitcoind_config]\n")
|
||||
f.write(f"cookie_path = '{bitcoind_cookie_path}'\n")
|
||||
f.write(f"addr = '127.0.0.1:{bitcoind_rpc_port}'\n")
|
||||
f.write("poll_interval_secs = 1\n")
|
||||
|
||||
def start(self):
|
||||
TailableProc.start(self)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user