Reduce code duplication and make evaluation order determinisitic

The Rust compiler doesn't guarantee in which order field initialization
are executed. By extracting them, we can make sure they run in a certain
order. This will be important as we add more validations that can
fail.
This commit is contained in:
Thomas Eizinger 2021-07-08 13:31:57 +10:00
parent c275e33a6c
commit 367d75cab6
No known key found for this signature in database
GPG Key ID: 651AC83A6C6C8B96

View File

@ -69,41 +69,34 @@ where
let arguments = match args.cmd { let arguments = match args.cmd {
RawCommand::BuyXmr { RawCommand::BuyXmr {
seller: Seller { seller }, seller: Seller { seller },
bitcoin: bitcoin,
Bitcoin {
bitcoin_electrum_rpc_url,
bitcoin_target_block,
},
bitcoin_change_address, bitcoin_change_address,
monero: Monero { monero,
monero_daemon_address,
},
monero_receive_address, monero_receive_address,
tor: Tor { tor_socks5_port }, tor: Tor { tor_socks5_port },
} => Arguments { } => {
env_config: env_config_from(is_testnet), let (bitcoin_electrum_rpc_url, bitcoin_target_block) =
debug, bitcoin.apply_defaults(is_testnet)?;
json, let monero_daemon_address = monero.apply_defaults(is_testnet);
data_dir: data::data_dir_from(data, is_testnet)?, let monero_receive_address =
cmd: Command::BuyXmr { validate_monero_address(monero_receive_address, is_testnet)?;
seller,
bitcoin_electrum_rpc_url: bitcoin_electrum_rpc_url_from( Arguments {
env_config: env_config_from(is_testnet),
debug,
json,
data_dir: data::data_dir_from(data, is_testnet)?,
cmd: Command::BuyXmr {
seller,
bitcoin_electrum_rpc_url, bitcoin_electrum_rpc_url,
is_testnet, bitcoin_target_block,
)?, bitcoin_change_address,
bitcoin_target_block: bitcoin_target_block_from(bitcoin_target_block, is_testnet),
bitcoin_change_address,
monero_receive_address: validate_monero_address(
monero_receive_address, monero_receive_address,
is_testnet,
)?,
monero_daemon_address: monero_daemon_address_from(
monero_daemon_address, monero_daemon_address,
is_testnet, tor_socks5_port,
), },
tor_socks5_port, }
}, }
},
RawCommand::History => Arguments { RawCommand::History => Arguments {
env_config: env_config_from(is_testnet), env_config: env_config_from(is_testnet),
debug, debug,
@ -113,80 +106,70 @@ where
}, },
RawCommand::Resume { RawCommand::Resume {
swap_id: SwapId { swap_id }, swap_id: SwapId { swap_id },
bitcoin: bitcoin,
Bitcoin { monero,
tor: Tor { tor_socks5_port },
} => {
let (bitcoin_electrum_rpc_url, bitcoin_target_block) =
bitcoin.apply_defaults(is_testnet)?;
let monero_daemon_address = monero.apply_defaults(is_testnet);
Arguments {
env_config: env_config_from(is_testnet),
debug,
json,
data_dir: data::data_dir_from(data, is_testnet)?,
cmd: Command::Resume {
swap_id,
bitcoin_electrum_rpc_url, bitcoin_electrum_rpc_url,
bitcoin_target_block, bitcoin_target_block,
},
monero: Monero {
monero_daemon_address,
},
tor: Tor { tor_socks5_port },
} => Arguments {
env_config: env_config_from(is_testnet),
debug,
json,
data_dir: data::data_dir_from(data, is_testnet)?,
cmd: Command::Resume {
swap_id,
bitcoin_electrum_rpc_url: bitcoin_electrum_rpc_url_from(
bitcoin_electrum_rpc_url,
is_testnet,
)?,
bitcoin_target_block: bitcoin_target_block_from(bitcoin_target_block, is_testnet),
monero_daemon_address: monero_daemon_address_from(
monero_daemon_address, monero_daemon_address,
is_testnet, tor_socks5_port,
), },
tor_socks5_port, }
}, }
},
RawCommand::Cancel { RawCommand::Cancel {
swap_id: SwapId { swap_id }, swap_id: SwapId { swap_id },
force, force,
bitcoin: bitcoin,
Bitcoin { } => {
let (bitcoin_electrum_rpc_url, bitcoin_target_block) =
bitcoin.apply_defaults(is_testnet)?;
Arguments {
env_config: env_config_from(is_testnet),
debug,
json,
data_dir: data::data_dir_from(data, is_testnet)?,
cmd: Command::Cancel {
swap_id,
force,
bitcoin_electrum_rpc_url, bitcoin_electrum_rpc_url,
bitcoin_target_block, bitcoin_target_block,
}, },
} => Arguments { }
env_config: env_config_from(is_testnet), }
debug,
json,
data_dir: data::data_dir_from(data, is_testnet)?,
cmd: Command::Cancel {
swap_id,
force,
bitcoin_electrum_rpc_url: bitcoin_electrum_rpc_url_from(
bitcoin_electrum_rpc_url,
is_testnet,
)?,
bitcoin_target_block: bitcoin_target_block_from(bitcoin_target_block, is_testnet),
},
},
RawCommand::Refund { RawCommand::Refund {
swap_id: SwapId { swap_id }, swap_id: SwapId { swap_id },
force, force,
bitcoin: bitcoin,
Bitcoin { } => {
let (bitcoin_electrum_rpc_url, bitcoin_target_block) =
bitcoin.apply_defaults(is_testnet)?;
Arguments {
env_config: env_config_from(is_testnet),
debug,
json,
data_dir: data::data_dir_from(data, is_testnet)?,
cmd: Command::Refund {
swap_id,
force,
bitcoin_electrum_rpc_url, bitcoin_electrum_rpc_url,
bitcoin_target_block, bitcoin_target_block,
}, },
} => Arguments { }
env_config: env_config_from(is_testnet), }
debug,
json,
data_dir: data::data_dir_from(data, is_testnet)?,
cmd: Command::Refund {
swap_id,
force,
bitcoin_electrum_rpc_url: bitcoin_electrum_rpc_url_from(
bitcoin_electrum_rpc_url,
is_testnet,
)?,
bitcoin_target_block: bitcoin_target_block_from(bitcoin_target_block, is_testnet),
},
},
RawCommand::ListSellers { RawCommand::ListSellers {
rendezvous_point, rendezvous_point,
tor: Tor { tor_socks5_port }, tor: Tor { tor_socks5_port },
@ -369,6 +352,18 @@ struct Monero {
monero_daemon_address: Option<String>, monero_daemon_address: Option<String>,
} }
impl Monero {
fn apply_defaults(self, testnet: bool) -> String {
if let Some(address) = self.monero_daemon_address {
address
} else if testnet {
DEFAULT_MONERO_DAEMON_ADDRESS_STAGENET.to_string()
} else {
DEFAULT_MONERO_DAEMON_ADDRESS.to_string()
}
}
}
#[derive(structopt::StructOpt, Debug)] #[derive(structopt::StructOpt, Debug)]
struct Bitcoin { struct Bitcoin {
#[structopt(long = "electrum-rpc", help = "Provide the Bitcoin Electrum RPC URL")] #[structopt(long = "electrum-rpc", help = "Provide the Bitcoin Electrum RPC URL")]
@ -381,6 +376,28 @@ struct Bitcoin {
bitcoin_target_block: Option<usize>, bitcoin_target_block: Option<usize>,
} }
impl Bitcoin {
fn apply_defaults(self, testnet: bool) -> Result<(Url, usize)> {
let bitcoin_electrum_rpc_url = if let Some(url) = self.bitcoin_electrum_rpc_url {
url
} else if testnet {
Url::from_str(DEFAULT_ELECTRUM_RPC_URL_TESTNET)?
} else {
Url::from_str(DEFAULT_ELECTRUM_RPC_URL)?
};
let bitcoin_target_block = if let Some(target_block) = self.bitcoin_target_block {
target_block
} else if testnet {
DEFAULT_BITCOIN_CONFIRMATION_TARGET_TESTNET
} else {
DEFAULT_BITCOIN_CONFIRMATION_TARGET
};
Ok((bitcoin_electrum_rpc_url, bitcoin_target_block))
}
}
#[derive(structopt::StructOpt, Debug)] #[derive(structopt::StructOpt, Debug)]
struct Tor { struct Tor {
#[structopt( #[structopt(
@ -428,16 +445,6 @@ mod data {
} }
} }
fn bitcoin_electrum_rpc_url_from(url: Option<Url>, testnet: bool) -> Result<Url> {
if let Some(url) = url {
Ok(url)
} else if testnet {
Ok(Url::from_str(DEFAULT_ELECTRUM_RPC_URL_TESTNET)?)
} else {
Ok(Url::from_str(DEFAULT_ELECTRUM_RPC_URL)?)
}
}
fn rendezvous_namespace_from(is_testnet: bool) -> XmrBtcNamespace { fn rendezvous_namespace_from(is_testnet: bool) -> XmrBtcNamespace {
if is_testnet { if is_testnet {
XmrBtcNamespace::Testnet XmrBtcNamespace::Testnet
@ -446,26 +453,6 @@ fn rendezvous_namespace_from(is_testnet: bool) -> XmrBtcNamespace {
} }
} }
fn bitcoin_target_block_from(target_block: Option<usize>, testnet: bool) -> usize {
if let Some(target_block) = target_block {
target_block
} else if testnet {
DEFAULT_BITCOIN_CONFIRMATION_TARGET_TESTNET
} else {
DEFAULT_BITCOIN_CONFIRMATION_TARGET
}
}
fn monero_daemon_address_from(address: Option<String>, testnet: bool) -> String {
if let Some(address) = address {
address
} else if testnet {
DEFAULT_MONERO_DAEMON_ADDRESS_STAGENET.to_string()
} else {
DEFAULT_MONERO_DAEMON_ADDRESS.to_string()
}
}
fn env_config_from(testnet: bool) -> env::Config { fn env_config_from(testnet: bool) -> env::Config {
if testnet { if testnet {
env::Testnet::get_config() env::Testnet::get_config()