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 {
RawCommand::BuyXmr {
seller: Seller { seller },
bitcoin:
Bitcoin {
bitcoin_electrum_rpc_url,
bitcoin_target_block,
},
bitcoin,
bitcoin_change_address,
monero: Monero {
monero_daemon_address,
},
monero,
monero_receive_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::BuyXmr {
seller,
bitcoin_electrum_rpc_url: bitcoin_electrum_rpc_url_from(
} => {
let (bitcoin_electrum_rpc_url, bitcoin_target_block) =
bitcoin.apply_defaults(is_testnet)?;
let monero_daemon_address = monero.apply_defaults(is_testnet);
let monero_receive_address =
validate_monero_address(monero_receive_address, is_testnet)?;
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,
is_testnet,
)?,
bitcoin_target_block: bitcoin_target_block_from(bitcoin_target_block, is_testnet),
bitcoin_change_address,
monero_receive_address: validate_monero_address(
bitcoin_target_block,
bitcoin_change_address,
monero_receive_address,
is_testnet,
)?,
monero_daemon_address: monero_daemon_address_from(
monero_daemon_address,
is_testnet,
),
tor_socks5_port,
},
},
tor_socks5_port,
},
}
}
RawCommand::History => Arguments {
env_config: env_config_from(is_testnet),
debug,
@ -113,80 +106,70 @@ where
},
RawCommand::Resume {
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_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,
is_testnet,
),
tor_socks5_port,
},
},
tor_socks5_port,
},
}
}
RawCommand::Cancel {
swap_id: SwapId { swap_id },
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_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 {
swap_id: SwapId { swap_id },
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_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 {
rendezvous_point,
tor: Tor { tor_socks5_port },
@ -369,6 +352,18 @@ struct Monero {
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)]
struct Bitcoin {
#[structopt(long = "electrum-rpc", help = "Provide the Bitcoin Electrum RPC URL")]
@ -381,6 +376,28 @@ struct Bitcoin {
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)]
struct Tor {
#[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 {
if is_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 {
if testnet {
env::Testnet::get_config()