mirror of
https://github.com/comit-network/xmr-btc-swap.git
synced 2024-10-01 01:45:40 -04:00
Activate mainnet for the ASB
To run the ASB on testnet, one actively has to provide the `--testnet` flag. Mainnet and testnet data and config are separated into sub-folders, i.e. `{data/config-dir}/asb/testnet` and `{data-dir}/asb/mainnet`. The initial setup is also per network. If (default) config for the network cannot be found the initial setup is triggered. Startup includes network check to ensure the bitcoin/monero network in config file is the same as the one in the `env::Config`. Note: Wallet initialization is done with the network set in the `env::Config`, the network saved in the config file is just to indicate what network the config file is for.
This commit is contained in:
parent
9ac5b635d7
commit
02974811ad
@ -10,6 +10,9 @@ use uuid::Uuid;
|
||||
author
|
||||
)]
|
||||
pub struct Arguments {
|
||||
#[structopt(long, help = "Swap on testnet")]
|
||||
pub testnet: bool,
|
||||
|
||||
#[structopt(
|
||||
short,
|
||||
long = "json",
|
||||
|
@ -1,4 +1,6 @@
|
||||
use crate::env::{Mainnet, Testnet};
|
||||
use crate::fs::{ensure_directory_exists, system_config_dir, system_data_dir};
|
||||
use crate::monero;
|
||||
use crate::tor::{DEFAULT_CONTROL_PORT, DEFAULT_SOCKS5_PORT};
|
||||
use anyhow::{bail, Context, Result};
|
||||
use config::ConfigError;
|
||||
@ -11,14 +13,69 @@ use serde::{Deserialize, Serialize};
|
||||
use std::ffi::OsStr;
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::FromStr;
|
||||
use tracing::info;
|
||||
use url::Url;
|
||||
|
||||
const DEFAULT_LISTEN_ADDRESS_TCP: &str = "/ip4/0.0.0.0/tcp/9939";
|
||||
const DEFAULT_LISTEN_ADDRESS_WS: &str = "/ip4/0.0.0.0/tcp/9940/ws";
|
||||
const DEFAULT_ELECTRUM_RPC_URL: &str = "ssl://electrum.blockstream.info:60002";
|
||||
const DEFAULT_MONERO_WALLET_RPC_TESTNET_URL: &str = "http://127.0.0.1:38083/json_rpc";
|
||||
const DEFAULT_BITCOIN_CONFIRMATION_TARGET: usize = 3;
|
||||
pub trait GetDefaults {
|
||||
fn getConfigFileDefaults() -> Result<Defaults>;
|
||||
}
|
||||
|
||||
pub struct Defaults {
|
||||
pub config_path: PathBuf,
|
||||
data_dir: PathBuf,
|
||||
listen_address_tcp: Multiaddr,
|
||||
listen_address_ws: Multiaddr,
|
||||
electrum_rpc_url: Url,
|
||||
monero_wallet_rpc_url: Url,
|
||||
bitcoin_confirmation_target: usize,
|
||||
}
|
||||
|
||||
impl GetDefaults for Testnet {
|
||||
fn getConfigFileDefaults() -> Result<Defaults> {
|
||||
let defaults = Defaults {
|
||||
config_path: system_config_dir()
|
||||
.map(|dir| Path::join(&dir, "asb"))
|
||||
.map(|dir| Path::join(&dir, "testnet"))
|
||||
.map(|dir| Path::join(&dir, "config.toml"))
|
||||
.context("Could not generate default config file path")?,
|
||||
data_dir: system_data_dir()
|
||||
.map(|proj_dir| Path::join(&proj_dir, "asb"))
|
||||
.map(|proj_dir| Path::join(&proj_dir, "testnet"))
|
||||
.context("Could not generate default data dir")?,
|
||||
listen_address_tcp: Multiaddr::from_str("/ip4/0.0.0.0/tcp/9939")?,
|
||||
listen_address_ws: Multiaddr::from_str("/ip4/0.0.0.0/tcp/9940/ws")?,
|
||||
electrum_rpc_url: Url::parse("ssl://electrum.blockstream.info:60002")?,
|
||||
monero_wallet_rpc_url: Url::parse("http://127.0.0.1:38083/json_rpc")?,
|
||||
bitcoin_confirmation_target: 1,
|
||||
};
|
||||
|
||||
Ok(defaults)
|
||||
}
|
||||
}
|
||||
|
||||
impl GetDefaults for Mainnet {
|
||||
fn getConfigFileDefaults() -> Result<Defaults> {
|
||||
let defaults = Defaults {
|
||||
config_path: system_config_dir()
|
||||
.map(|dir| Path::join(&dir, "asb"))
|
||||
.map(|dir| Path::join(&dir, "mainnet"))
|
||||
.map(|dir| Path::join(&dir, "config.toml"))
|
||||
.context("Could not generate default config file path")?,
|
||||
data_dir: system_data_dir()
|
||||
.map(|proj_dir| Path::join(&proj_dir, "asb"))
|
||||
.map(|proj_dir| Path::join(&proj_dir, "mainnet"))
|
||||
.context("Could not generate default data dir")?,
|
||||
listen_address_tcp: Multiaddr::from_str("/ip4/0.0.0.0/tcp/9939")?,
|
||||
listen_address_ws: Multiaddr::from_str("/ip4/0.0.0.0/tcp/9940/ws")?,
|
||||
electrum_rpc_url: Url::parse("ssl://electrum.blockstream.info:50002")?,
|
||||
monero_wallet_rpc_url: Url::parse("http://127.0.0.1:18083/json_rpc")?,
|
||||
bitcoin_confirmation_target: 3,
|
||||
};
|
||||
|
||||
Ok(defaults)
|
||||
}
|
||||
}
|
||||
|
||||
const DEFAULT_MIN_BUY_AMOUNT: f64 = 0.002f64;
|
||||
const DEFAULT_MAX_BUY_AMOUNT: f64 = 0.02f64;
|
||||
@ -64,12 +121,14 @@ pub struct Network {
|
||||
pub struct Bitcoin {
|
||||
pub electrum_rpc_url: Url,
|
||||
pub target_block: usize,
|
||||
pub network: bitcoin::Network,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Monero {
|
||||
pub wallet_rpc_url: Url,
|
||||
pub network: monero::Network,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||
@ -118,30 +177,11 @@ pub fn read_config(config_path: PathBuf) -> Result<Result<Config, ConfigNotIniti
|
||||
Ok(Ok(file))
|
||||
}
|
||||
|
||||
/// Default location for storing the config file for the ASB
|
||||
// Takes the default system config-dir and adds a `/asb/config.toml`
|
||||
pub fn default_config_path() -> Result<PathBuf> {
|
||||
system_config_dir()
|
||||
.map(|dir| Path::join(&dir, "asb"))
|
||||
.map(|dir| Path::join(&dir, "config.toml"))
|
||||
.context("Could not generate default config file path")
|
||||
}
|
||||
|
||||
/// Default location for storing data for the CLI
|
||||
// Takes the default system data-dir and adds a `/asb`
|
||||
fn default_data_dir() -> Result<PathBuf> {
|
||||
system_data_dir()
|
||||
.map(|proj_dir| Path::join(&proj_dir, "asb"))
|
||||
.context("Could not generate default data dir")
|
||||
}
|
||||
|
||||
pub fn initial_setup<F>(config_path: PathBuf, config_file: F) -> Result<()>
|
||||
pub fn initial_setup<F>(config_path: PathBuf, config_file: F, testnet: bool) -> Result<()>
|
||||
where
|
||||
F: Fn() -> Result<Config>,
|
||||
F: Fn(bool) -> Result<Config>,
|
||||
{
|
||||
info!("Config file not found, running initial setup...");
|
||||
let initial_config = config_file()?;
|
||||
|
||||
let initial_config = config_file(testnet)?;
|
||||
let toml = toml::to_string(&initial_config)?;
|
||||
|
||||
ensure_directory_exists(config_path.as_path())?;
|
||||
@ -154,13 +194,30 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn query_user_for_initial_testnet_config() -> Result<Config> {
|
||||
pub fn query_user_for_initial_config(testnet: bool) -> Result<Config> {
|
||||
let (bitcoin_network, monero_network, defaults) = if testnet {
|
||||
tracing::info!("Running initial setup for testnet");
|
||||
|
||||
let bitcoin_network = bitcoin::Network::Testnet;
|
||||
let monero_network = monero::Network::Stagenet;
|
||||
let defaults = Testnet::getConfigFileDefaults()?;
|
||||
|
||||
(bitcoin_network, monero_network, defaults)
|
||||
} else {
|
||||
tracing::info!("Running initial setup for mainnet");
|
||||
let bitcoin_network = bitcoin::Network::Bitcoin;
|
||||
let monero_network = monero::Network::Mainnet;
|
||||
let defaults = Mainnet::getConfigFileDefaults()?;
|
||||
|
||||
(bitcoin_network, monero_network, defaults)
|
||||
};
|
||||
|
||||
println!();
|
||||
let data_dir = Input::with_theme(&ColorfulTheme::default())
|
||||
.with_prompt("Enter data directory for asb or hit return to use default")
|
||||
.default(
|
||||
default_data_dir()
|
||||
.context("No default data dir value for this system")?
|
||||
defaults
|
||||
.data_dir
|
||||
.to_str()
|
||||
.context("Unsupported characters in default path")?
|
||||
.to_string(),
|
||||
@ -170,28 +227,27 @@ pub fn query_user_for_initial_testnet_config() -> Result<Config> {
|
||||
|
||||
let target_block = Input::with_theme(&ColorfulTheme::default())
|
||||
.with_prompt("How fast should your Bitcoin transactions be confirmed? Your transaction fee will be calculated based on this target. Hit return to use default")
|
||||
.default(DEFAULT_BITCOIN_CONFIRMATION_TARGET)
|
||||
.default(defaults.bitcoin_confirmation_target)
|
||||
.interact_text()?;
|
||||
|
||||
let listen_addresses = Input::with_theme(&ColorfulTheme::default())
|
||||
.with_prompt("Enter multiaddresses (comma separated) on which asb should list for peer-to-peer communications or hit return to use default")
|
||||
.default( format!("{},{}", DEFAULT_LISTEN_ADDRESS_TCP, DEFAULT_LISTEN_ADDRESS_WS))
|
||||
.default( format!("{},{}", defaults.listen_address_tcp, defaults.listen_address_ws))
|
||||
.interact_text()?;
|
||||
let listen_addresses = listen_addresses
|
||||
.split(',')
|
||||
.map(|str| str.parse())
|
||||
.collect::<Result<Vec<Multiaddr>, _>>()?;
|
||||
|
||||
let electrum_rpc_url: String = Input::with_theme(&ColorfulTheme::default())
|
||||
let electrum_rpc_url: Url = Input::with_theme(&ColorfulTheme::default())
|
||||
.with_prompt("Enter Electrum RPC URL or hit return to use default")
|
||||
.default(DEFAULT_ELECTRUM_RPC_URL.to_owned())
|
||||
.default(defaults.electrum_rpc_url)
|
||||
.interact_text()?;
|
||||
let electrum_rpc_url = Url::parse(electrum_rpc_url.as_str())?;
|
||||
|
||||
let monero_wallet_rpc_url = Input::with_theme(&ColorfulTheme::default())
|
||||
.with_prompt("Enter Monero Wallet RPC URL or hit enter to use default")
|
||||
.default(DEFAULT_MONERO_WALLET_RPC_TESTNET_URL.to_owned())
|
||||
.default(defaults.monero_wallet_rpc_url)
|
||||
.interact_text()?;
|
||||
let monero_wallet_rpc_url = monero_wallet_rpc_url.as_str().parse()?;
|
||||
|
||||
let tor_control_port = Input::with_theme(&ColorfulTheme::default())
|
||||
.with_prompt("Enter Tor control port or hit enter to use default. If Tor is not running on your machine, no hidden service will be created.")
|
||||
@ -234,9 +290,11 @@ pub fn query_user_for_initial_testnet_config() -> Result<Config> {
|
||||
bitcoin: Bitcoin {
|
||||
electrum_rpc_url,
|
||||
target_block,
|
||||
network: bitcoin_network,
|
||||
},
|
||||
monero: Monero {
|
||||
wallet_rpc_url: monero_wallet_rpc_url,
|
||||
network: monero_network,
|
||||
},
|
||||
tor: TorConf {
|
||||
control_port: tor_control_port,
|
||||
@ -253,31 +311,31 @@ pub fn query_user_for_initial_testnet_config() -> Result<Config> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::str::FromStr;
|
||||
use tempfile::tempdir;
|
||||
|
||||
#[test]
|
||||
fn config_roundtrip() {
|
||||
fn config_roundtrip_testnet() {
|
||||
let temp_dir = tempdir().unwrap().path().to_path_buf();
|
||||
let config_path = Path::join(&temp_dir, "config.toml");
|
||||
|
||||
let defaults = Testnet::getConfigFileDefaults().unwrap();
|
||||
|
||||
let expected = Config {
|
||||
data: Data {
|
||||
dir: Default::default(),
|
||||
},
|
||||
bitcoin: Bitcoin {
|
||||
electrum_rpc_url: Url::from_str(DEFAULT_ELECTRUM_RPC_URL).unwrap(),
|
||||
target_block: DEFAULT_BITCOIN_CONFIRMATION_TARGET,
|
||||
electrum_rpc_url: defaults.electrum_rpc_url,
|
||||
target_block: defaults.bitcoin_confirmation_target,
|
||||
network: bitcoin::Network::Testnet,
|
||||
},
|
||||
network: Network {
|
||||
listen: vec![
|
||||
DEFAULT_LISTEN_ADDRESS_TCP.parse().unwrap(),
|
||||
DEFAULT_LISTEN_ADDRESS_WS.parse().unwrap(),
|
||||
],
|
||||
listen: vec![defaults.listen_address_tcp, defaults.listen_address_ws],
|
||||
},
|
||||
|
||||
monero: Monero {
|
||||
wallet_rpc_url: Url::from_str(DEFAULT_MONERO_WALLET_RPC_TESTNET_URL).unwrap(),
|
||||
wallet_rpc_url: defaults.monero_wallet_rpc_url,
|
||||
network: monero::Network::Testnet,
|
||||
},
|
||||
tor: Default::default(),
|
||||
maker: Maker {
|
||||
@ -287,7 +345,45 @@ mod tests {
|
||||
},
|
||||
};
|
||||
|
||||
initial_setup(config_path.clone(), || Ok(expected.clone())).unwrap();
|
||||
initial_setup(config_path.clone(), |_| Ok(expected.clone()), false).unwrap();
|
||||
let actual = read_config(config_path).unwrap().unwrap();
|
||||
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn config_roundtrip_mainnet() {
|
||||
let temp_dir = tempdir().unwrap().path().to_path_buf();
|
||||
let config_path = Path::join(&temp_dir, "config.toml");
|
||||
|
||||
let defaults = Mainnet::getConfigFileDefaults().unwrap();
|
||||
|
||||
let expected = Config {
|
||||
data: Data {
|
||||
dir: Default::default(),
|
||||
},
|
||||
bitcoin: Bitcoin {
|
||||
electrum_rpc_url: defaults.electrum_rpc_url,
|
||||
target_block: defaults.bitcoin_confirmation_target,
|
||||
network: bitcoin::Network::Bitcoin,
|
||||
},
|
||||
network: Network {
|
||||
listen: vec![defaults.listen_address_tcp, defaults.listen_address_ws],
|
||||
},
|
||||
|
||||
monero: Monero {
|
||||
wallet_rpc_url: defaults.monero_wallet_rpc_url,
|
||||
network: monero::Network::Mainnet,
|
||||
},
|
||||
tor: Default::default(),
|
||||
maker: Maker {
|
||||
min_buy_btc: bitcoin::Amount::from_btc(DEFAULT_MIN_BUY_AMOUNT).unwrap(),
|
||||
max_buy_btc: bitcoin::Amount::from_btc(DEFAULT_MAX_BUY_AMOUNT).unwrap(),
|
||||
ask_spread: Decimal::from_f64(DEFAULT_SPREAD).unwrap(),
|
||||
},
|
||||
};
|
||||
|
||||
initial_setup(config_path.clone(), |_| Ok(expected.clone()), true).unwrap();
|
||||
let actual = read_config(config_path).unwrap().unwrap();
|
||||
|
||||
assert_eq!(expected, actual);
|
||||
|
@ -12,7 +12,7 @@
|
||||
#![forbid(unsafe_code)]
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use anyhow::{bail, Context, Result};
|
||||
use libp2p::core::multiaddr::Protocol;
|
||||
use libp2p::core::Multiaddr;
|
||||
use libp2p::Swarm;
|
||||
@ -22,8 +22,8 @@ use std::sync::Arc;
|
||||
use structopt::StructOpt;
|
||||
use swap::asb::command::{Arguments, Command, ManualRecovery, RecoverCommandParams};
|
||||
use swap::asb::config::{
|
||||
default_config_path, initial_setup, query_user_for_initial_testnet_config, read_config, Config,
|
||||
ConfigNotInitialized,
|
||||
initial_setup, query_user_for_initial_config, read_config, Config, ConfigNotInitialized,
|
||||
GetDefaults,
|
||||
};
|
||||
use swap::database::Database;
|
||||
use swap::env::GetConfig;
|
||||
@ -45,23 +45,49 @@ const DEFAULT_WALLET_NAME: &str = "asb-wallet";
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
let opt = Arguments::from_args();
|
||||
asb::tracing::init(LevelFilter::DEBUG, opt.json).expect("initialize tracing");
|
||||
let Arguments {
|
||||
testnet,
|
||||
json,
|
||||
config,
|
||||
cmd,
|
||||
} = Arguments::from_args();
|
||||
asb::tracing::init(LevelFilter::DEBUG, json).expect("initialize tracing");
|
||||
|
||||
let config_path = if let Some(config_path) = opt.config {
|
||||
let config_path = if let Some(config_path) = config {
|
||||
config_path
|
||||
} else if testnet {
|
||||
env::Testnet::getConfigFileDefaults()?.config_path
|
||||
} else {
|
||||
default_config_path()?
|
||||
env::Mainnet::getConfigFileDefaults()?.config_path
|
||||
};
|
||||
|
||||
let config = match read_config(config_path.clone())? {
|
||||
Ok(config) => config,
|
||||
Err(ConfigNotInitialized {}) => {
|
||||
initial_setup(config_path.clone(), query_user_for_initial_testnet_config)?;
|
||||
initial_setup(config_path.clone(), query_user_for_initial_config, testnet)?;
|
||||
read_config(config_path)?.expect("after initial setup config can be read")
|
||||
}
|
||||
};
|
||||
|
||||
let env_config = if testnet {
|
||||
env::Testnet::get_config()
|
||||
} else {
|
||||
env::Mainnet::get_config()
|
||||
};
|
||||
|
||||
if config.monero.network != env_config.monero_network {
|
||||
bail!(format!(
|
||||
"Expected monero network in config file to be {:?} but was {:?}",
|
||||
env_config.monero_network, config.monero.network
|
||||
));
|
||||
}
|
||||
if config.bitcoin.network != env_config.bitcoin_network {
|
||||
bail!(format!(
|
||||
"Expected bitcoin network in config file to be {:?} but was {:?}",
|
||||
env_config.bitcoin_network, config.bitcoin.network
|
||||
));
|
||||
}
|
||||
|
||||
info!(
|
||||
db_folder = %config.data.dir.display(),
|
||||
"Database and Seed will be stored in",
|
||||
@ -75,9 +101,7 @@ async fn main() -> Result<()> {
|
||||
let seed =
|
||||
Seed::from_file_or_generate(&config.data.dir).expect("Could not retrieve/initialize seed");
|
||||
|
||||
let env_config = env::Testnet::get_config();
|
||||
|
||||
match opt.cmd {
|
||||
match cmd {
|
||||
Command::Start { resume_only } => {
|
||||
let bitcoin_wallet = init_bitcoin_wallet(&config, &seed, env_config).await?;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user