mirror of
https://github.com/comit-network/xmr-btc-swap.git
synced 2025-08-08 22:42:35 -04:00
fixing tests in cli module
This commit is contained in:
parent
e1983d5639
commit
f5b62f967c
7 changed files with 629 additions and 596 deletions
16
Cargo.lock
generated
16
Cargo.lock
generated
|
@ -3624,6 +3624,21 @@ dependencies = [
|
||||||
"pest",
|
"pest",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sequential-macro"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eb5facc5f409a55d25bf271c853402a00e1187097d326757043f5dd711944d07"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sequential-test"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f0d9c0d773bc7e7733264f460e5dfa00b2510421ddd6284db0749eef8dfb79e9"
|
||||||
|
dependencies = [
|
||||||
|
"sequential-macro",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.148"
|
version = "1.0.148"
|
||||||
|
@ -4160,6 +4175,7 @@ dependencies = [
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"rust_decimal",
|
"rust_decimal",
|
||||||
"rust_decimal_macros",
|
"rust_decimal_macros",
|
||||||
|
"sequential-test",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_cbor",
|
"serde_cbor",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
|
|
@ -86,6 +86,7 @@ serde_cbor = "0.11"
|
||||||
spectral = "0.6"
|
spectral = "0.6"
|
||||||
tempfile = "3"
|
tempfile = "3"
|
||||||
testcontainers = "0.12"
|
testcontainers = "0.12"
|
||||||
|
sequential-test = "0.2.4"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
vergen = { version = "7", default-features = false, features = [ "git", "build" ] }
|
vergen = { version = "7", default-features = false, features = [ "git", "build" ] }
|
||||||
|
|
139
swap/src/api.rs
139
swap/src/api.rs
|
@ -2,7 +2,7 @@ use crate::bitcoin::{Amount, TxLock};
|
||||||
use crate::cli::command::{Bitcoin, Command, Monero, Tor};
|
use crate::cli::command::{Bitcoin, Command, Monero, Tor};
|
||||||
use crate::cli::{list_sellers, EventLoop, SellerStatus};
|
use crate::cli::{list_sellers, EventLoop, SellerStatus};
|
||||||
use crate::database::open_db;
|
use crate::database::open_db;
|
||||||
use crate::env::{Config, GetConfig, Mainnet, Testnet};
|
use crate::env::{Config as EnvConfig, GetConfig, Mainnet, Testnet};
|
||||||
use crate::fs::system_data_dir;
|
use crate::fs::system_data_dir;
|
||||||
use crate::libp2p_ext::MultiAddrExt;
|
use crate::libp2p_ext::MultiAddrExt;
|
||||||
use crate::network::quote::{BidQuote, ZeroQuoteReceived};
|
use crate::network::quote::{BidQuote, ZeroQuoteReceived};
|
||||||
|
@ -28,8 +28,11 @@ use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
use std::sync::Once;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
static START: Once = Once::new();
|
||||||
|
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Debug)]
|
||||||
pub struct Request {
|
pub struct Request {
|
||||||
pub params: Params,
|
pub params: Params,
|
||||||
|
@ -47,19 +50,24 @@ pub struct Params {
|
||||||
pub address: Option<bitcoin::Address>,
|
pub address: Option<bitcoin::Address>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
|
pub struct Config {
|
||||||
|
tor_socks5_port: Option<u16>,
|
||||||
|
namespace: XmrBtcNamespace,
|
||||||
|
server_address: Option<SocketAddr>,
|
||||||
|
env_config: EnvConfig,
|
||||||
|
seed: Option<Seed>,
|
||||||
|
debug: bool,
|
||||||
|
json: bool,
|
||||||
|
is_testnet: bool,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
pub db: Arc<dyn Database + Send + Sync>,
|
pub db: Arc<dyn Database + Send + Sync>,
|
||||||
bitcoin_wallet: Option<Arc<bitcoin::Wallet>>,
|
bitcoin_wallet: Option<Arc<bitcoin::Wallet>>,
|
||||||
monero_wallet: Option<Arc<monero::Wallet>>,
|
monero_wallet: Option<Arc<monero::Wallet>>,
|
||||||
monero_rpc_process: Option<monero::WalletRpcProcess>,
|
monero_rpc_process: Option<monero::WalletRpcProcess>,
|
||||||
tor_socks5_port: Option<u16>,
|
pub config: Config,
|
||||||
namespace: XmrBtcNamespace,
|
|
||||||
server_address: Option<SocketAddr>,
|
|
||||||
env_config: Config,
|
|
||||||
seed: Option<Seed>,
|
|
||||||
debug: bool,
|
|
||||||
json: bool,
|
|
||||||
is_testnet: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Request {
|
impl Request {
|
||||||
|
@ -68,8 +76,8 @@ impl Request {
|
||||||
Command::BuyXmr => {
|
Command::BuyXmr => {
|
||||||
let swap_id = Uuid::new_v4();
|
let swap_id = Uuid::new_v4();
|
||||||
|
|
||||||
let seed = context.seed.as_ref().unwrap();
|
let seed = context.config.seed.as_ref().unwrap();
|
||||||
let env_config = context.env_config;
|
let env_config = context.config.env_config;
|
||||||
let btc = context.bitcoin_wallet.as_ref().unwrap();
|
let btc = context.bitcoin_wallet.as_ref().unwrap();
|
||||||
let seller = self.params.seller.clone().unwrap();
|
let seller = self.params.seller.clone().unwrap();
|
||||||
let monero_receive_address = self.params.monero_receive_address.unwrap();
|
let monero_receive_address = self.params.monero_receive_address.unwrap();
|
||||||
|
@ -92,11 +100,11 @@ impl Request {
|
||||||
seller_peer_id,
|
seller_peer_id,
|
||||||
env_config,
|
env_config,
|
||||||
bitcoin_wallet.clone(),
|
bitcoin_wallet.clone(),
|
||||||
(seed.derive_libp2p_identity(), context.namespace),
|
(seed.derive_libp2p_identity(), context.config.namespace),
|
||||||
);
|
);
|
||||||
let mut swarm = swarm::cli(
|
let mut swarm = swarm::cli(
|
||||||
seed.derive_libp2p_identity(),
|
seed.derive_libp2p_identity(),
|
||||||
context.tor_socks5_port.unwrap(),
|
context.config.tor_socks5_port.unwrap(),
|
||||||
behaviour,
|
behaviour,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
@ -112,7 +120,7 @@ impl Request {
|
||||||
let estimate_fee = |amount| bitcoin_wallet.estimate_fee(TxLock::weight(), amount);
|
let estimate_fee = |amount| bitcoin_wallet.estimate_fee(TxLock::weight(), amount);
|
||||||
|
|
||||||
let (amount, fees) = match determine_btc_to_swap(
|
let (amount, fees) = match determine_btc_to_swap(
|
||||||
context.json,
|
context.config.json,
|
||||||
event_loop_handle.request_quote(),
|
event_loop_handle.request_quote(),
|
||||||
bitcoin_wallet.new_address(),
|
bitcoin_wallet.new_address(),
|
||||||
|| bitcoin_wallet.balance(),
|
|| bitcoin_wallet.balance(),
|
||||||
|
@ -224,7 +232,7 @@ impl Request {
|
||||||
let addr2 = "127.0.0.1:1234".parse()?;
|
let addr2 = "127.0.0.1:1234".parse()?;
|
||||||
|
|
||||||
let server_handle = {
|
let server_handle = {
|
||||||
if let Some(addr) = context.server_address {
|
if let Some(addr) = context.config.server_address {
|
||||||
let (_addr, handle) = rpc::run_server(addr, context).await?;
|
let (_addr, handle) = rpc::run_server(addr, context).await?;
|
||||||
Some(handle)
|
Some(handle)
|
||||||
} else {
|
} else {
|
||||||
|
@ -257,17 +265,17 @@ impl Request {
|
||||||
let seller_peer_id = context.db.get_peer_id(swap_id).await?;
|
let seller_peer_id = context.db.get_peer_id(swap_id).await?;
|
||||||
let seller_addresses = context.db.get_addresses(seller_peer_id).await?;
|
let seller_addresses = context.db.get_addresses(seller_peer_id).await?;
|
||||||
|
|
||||||
let seed = context.seed.as_ref().unwrap().derive_libp2p_identity();
|
let seed = context.config.seed.as_ref().unwrap().derive_libp2p_identity();
|
||||||
|
|
||||||
let behaviour = cli::Behaviour::new(
|
let behaviour = cli::Behaviour::new(
|
||||||
seller_peer_id,
|
seller_peer_id,
|
||||||
context.env_config,
|
context.config.env_config,
|
||||||
Arc::clone(context.bitcoin_wallet.as_ref().unwrap()),
|
Arc::clone(context.bitcoin_wallet.as_ref().unwrap()),
|
||||||
(seed.clone(), context.namespace),
|
(seed.clone(), context.config.namespace),
|
||||||
);
|
);
|
||||||
let mut swarm = swarm::cli(
|
let mut swarm = swarm::cli(
|
||||||
seed.clone(),
|
seed.clone(),
|
||||||
context.tor_socks5_port.clone().unwrap(),
|
context.config.tor_socks5_port.clone().unwrap(),
|
||||||
behaviour,
|
behaviour,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
@ -291,7 +299,7 @@ impl Request {
|
||||||
swap_id,
|
swap_id,
|
||||||
Arc::clone(context.bitcoin_wallet.as_ref().unwrap()),
|
Arc::clone(context.bitcoin_wallet.as_ref().unwrap()),
|
||||||
Arc::clone(context.monero_wallet.as_ref().unwrap()),
|
Arc::clone(context.monero_wallet.as_ref().unwrap()),
|
||||||
context.env_config,
|
context.config.env_config,
|
||||||
event_loop_handle,
|
event_loop_handle,
|
||||||
monero_receive_address,
|
monero_receive_address,
|
||||||
)
|
)
|
||||||
|
@ -343,13 +351,13 @@ impl Request {
|
||||||
.extract_peer_id()
|
.extract_peer_id()
|
||||||
.context("Rendezvous node address must contain peer ID")?;
|
.context("Rendezvous node address must contain peer ID")?;
|
||||||
|
|
||||||
let identity = context.seed.as_ref().unwrap().derive_libp2p_identity();
|
let identity = context.config.seed.as_ref().unwrap().derive_libp2p_identity();
|
||||||
|
|
||||||
let sellers = list_sellers(
|
let sellers = list_sellers(
|
||||||
rendezvous_node_peer_id,
|
rendezvous_node_peer_id,
|
||||||
rendezvous_point,
|
rendezvous_point,
|
||||||
context.namespace,
|
context.config.namespace,
|
||||||
context.tor_socks5_port.unwrap(),
|
context.config.tor_socks5_port.unwrap(),
|
||||||
identity,
|
identity,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
@ -413,7 +421,7 @@ impl Request {
|
||||||
let (spend_key, view_key) = state5.xmr_keys();
|
let (spend_key, view_key) = state5.xmr_keys();
|
||||||
|
|
||||||
let address = monero::Address::standard(
|
let address = monero::Address::standard(
|
||||||
context.env_config.monero_network,
|
context.config.env_config.monero_network,
|
||||||
monero::PublicKey::from_private_key(&spend_key),
|
monero::PublicKey::from_private_key(&spend_key),
|
||||||
monero::PublicKey::from(view_key.public()),
|
monero::PublicKey::from(view_key.public()),
|
||||||
);
|
);
|
||||||
|
@ -489,21 +497,26 @@ impl Context {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
cli::tracing::init(debug, json, data_dir.join("logs"), None)?;
|
START.call_once(|| {
|
||||||
|
let _ = cli::tracing::init(debug, json, data_dir.join("logs"), None);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
let init = Context {
|
let init = Context {
|
||||||
|
db: open_db(data_dir.join("sqlite")).await?,
|
||||||
bitcoin_wallet,
|
bitcoin_wallet,
|
||||||
monero_wallet,
|
monero_wallet,
|
||||||
monero_rpc_process,
|
monero_rpc_process,
|
||||||
tor_socks5_port,
|
config: Config {
|
||||||
namespace: XmrBtcNamespace::from_is_testnet(is_testnet),
|
tor_socks5_port,
|
||||||
db: open_db(data_dir.join("sqlite")).await?,
|
namespace: XmrBtcNamespace::from_is_testnet(is_testnet),
|
||||||
env_config,
|
env_config,
|
||||||
seed: Some(seed),
|
seed: Some(seed),
|
||||||
debug,
|
server_address,
|
||||||
json,
|
debug,
|
||||||
is_testnet,
|
json,
|
||||||
server_address,
|
is_testnet,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(init)
|
Ok(init)
|
||||||
|
@ -517,22 +530,12 @@ impl Serialize for Context {
|
||||||
{
|
{
|
||||||
// 3 is the number of fields in the struct.
|
// 3 is the number of fields in the struct.
|
||||||
let mut state = serializer.serialize_struct("Context", 3)?;
|
let mut state = serializer.serialize_struct("Context", 3)?;
|
||||||
state.serialize_field("debug", &self.debug)?;
|
state.serialize_field("debug", &self.config.debug)?;
|
||||||
state.serialize_field("json", &self.json)?;
|
state.serialize_field("json", &self.config.json)?;
|
||||||
state.end()
|
state.end()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for Context {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.tor_socks5_port == other.tor_socks5_port
|
|
||||||
&& self.namespace == other.namespace
|
|
||||||
&& self.debug == other.debug
|
|
||||||
&& self.json == other.json
|
|
||||||
&& self.server_address == other.server_address
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for Context {
|
impl fmt::Debug for Context {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "Testing {}", true)
|
write!(f, "Testing {}", true)
|
||||||
|
@ -543,7 +546,7 @@ async fn init_bitcoin_wallet(
|
||||||
electrum_rpc_url: Url,
|
electrum_rpc_url: Url,
|
||||||
seed: &Seed,
|
seed: &Seed,
|
||||||
data_dir: PathBuf,
|
data_dir: PathBuf,
|
||||||
env_config: Config,
|
env_config: EnvConfig,
|
||||||
bitcoin_target_block: usize,
|
bitcoin_target_block: usize,
|
||||||
) -> Result<bitcoin::Wallet> {
|
) -> Result<bitcoin::Wallet> {
|
||||||
let wallet_dir = data_dir.join("wallet");
|
let wallet_dir = data_dir.join("wallet");
|
||||||
|
@ -668,7 +671,7 @@ where
|
||||||
async fn init_monero_wallet(
|
async fn init_monero_wallet(
|
||||||
data_dir: PathBuf,
|
data_dir: PathBuf,
|
||||||
monero_daemon_address: String,
|
monero_daemon_address: String,
|
||||||
env_config: Config,
|
env_config: EnvConfig,
|
||||||
) -> Result<(monero::Wallet, monero::WalletRpcProcess)> {
|
) -> Result<(monero::Wallet, monero::WalletRpcProcess)> {
|
||||||
let network = env_config.monero_network;
|
let network = env_config.monero_network;
|
||||||
|
|
||||||
|
@ -709,7 +712,7 @@ mod data {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn env_config_from(testnet: bool) -> Config {
|
fn env_config_from(testnet: bool) -> EnvConfig {
|
||||||
if testnet {
|
if testnet {
|
||||||
Testnet::get_config()
|
Testnet::get_config()
|
||||||
} else {
|
} else {
|
||||||
|
@ -730,32 +733,30 @@ pub mod api_test {
|
||||||
pub const BITCOIN_MAINNET_ADDRESS: &str = "bc1qe4epnfklcaa0mun26yz5g8k24em5u9f92hy325";
|
pub const BITCOIN_MAINNET_ADDRESS: &str = "bc1qe4epnfklcaa0mun26yz5g8k24em5u9f92hy325";
|
||||||
pub const SWAP_ID: &str = "ea030832-3be9-454f-bb98-5ea9a788406b";
|
pub const SWAP_ID: &str = "ea030832-3be9-454f-bb98-5ea9a788406b";
|
||||||
|
|
||||||
impl Context {
|
impl Config {
|
||||||
pub async fn default(
|
pub fn default(
|
||||||
is_testnet: bool,
|
is_testnet: bool,
|
||||||
data_dir: PathBuf,
|
data_dir: Option<PathBuf>,
|
||||||
json: bool,
|
json: bool,
|
||||||
debug: bool,
|
debug: bool,
|
||||||
) -> Result<Context> {
|
) -> Self {
|
||||||
Ok(Context::build(
|
let data_dir = data::data_dir_from(data_dir, is_testnet).unwrap();
|
||||||
Some(Bitcoin {
|
|
||||||
bitcoin_electrum_rpc_url: None,
|
let seed = Seed::from_file_or_generate(data_dir.as_path()).unwrap();
|
||||||
bitcoin_target_block: None,
|
|
||||||
}),
|
let env_config = env_config_from(is_testnet);
|
||||||
Some(Monero {
|
Self {
|
||||||
monero_daemon_address: None,
|
tor_socks5_port: Some(9050),
|
||||||
}),
|
namespace: XmrBtcNamespace::from_is_testnet(is_testnet),
|
||||||
Some(Tor {
|
server_address: None,
|
||||||
tor_socks5_port: DEFAULT_SOCKS5_PORT,
|
env_config,
|
||||||
}),
|
seed: Some(seed),
|
||||||
Some(data_dir),
|
|
||||||
is_testnet,
|
|
||||||
debug,
|
debug,
|
||||||
json,
|
json,
|
||||||
None,
|
is_testnet
|
||||||
)
|
}
|
||||||
.await?)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
impl Request {
|
impl Request {
|
||||||
pub fn buy_xmr(is_testnet: bool) -> Request {
|
pub fn buy_xmr(is_testnet: bool) -> Request {
|
||||||
|
|
|
@ -15,7 +15,7 @@ pub use crate::bitcoin::refund::TxRefund;
|
||||||
pub use crate::bitcoin::timelocks::{BlockHeight, ExpiredTimelocks};
|
pub use crate::bitcoin::timelocks::{BlockHeight, ExpiredTimelocks};
|
||||||
pub use ::bitcoin::util::amount::Amount;
|
pub use ::bitcoin::util::amount::Amount;
|
||||||
pub use ::bitcoin::util::psbt::PartiallySignedTransaction;
|
pub use ::bitcoin::util::psbt::PartiallySignedTransaction;
|
||||||
pub use ::bitcoin::{Address, Network, Transaction, Txid};
|
pub use ::bitcoin::{Address, AddressType, Network, Transaction, Txid};
|
||||||
pub use ecdsa_fun::adaptor::EncryptedSignature;
|
pub use ecdsa_fun::adaptor::EncryptedSignature;
|
||||||
pub use ecdsa_fun::fun::Scalar;
|
pub use ecdsa_fun::fun::Scalar;
|
||||||
pub use ecdsa_fun::Signature;
|
pub use ecdsa_fun::Signature;
|
||||||
|
@ -250,6 +250,48 @@ pub fn current_epoch(
|
||||||
ExpiredTimelocks::None
|
ExpiredTimelocks::None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod bitcoin_address {
|
||||||
|
use anyhow::{bail, Result};
|
||||||
|
use serde::Serialize;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
#[derive(thiserror::Error, Debug, Clone, Copy, PartialEq, Serialize)]
|
||||||
|
#[error("Invalid Bitcoin address provided, expected address on network {expected:?} but address provided is on {actual:?}")]
|
||||||
|
pub struct BitcoinAddressNetworkMismatch {
|
||||||
|
#[serde(with = "crate::bitcoin::network")]
|
||||||
|
expected: bitcoin::Network,
|
||||||
|
#[serde(with = "crate::bitcoin::network")]
|
||||||
|
actual: bitcoin::Network,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse(addr_str: &str) -> Result<bitcoin::Address> {
|
||||||
|
let address = bitcoin::Address::from_str(addr_str)?;
|
||||||
|
|
||||||
|
if address.address_type() != Some(bitcoin::AddressType::P2wpkh) {
|
||||||
|
anyhow::bail!("Invalid Bitcoin address provided, only bech32 format is supported!")
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(address)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn validate(address: bitcoin::Address, is_testnet: bool) -> Result<bitcoin::Address> {
|
||||||
|
let expected_network = if is_testnet {
|
||||||
|
bitcoin::Network::Testnet
|
||||||
|
} else {
|
||||||
|
bitcoin::Network::Bitcoin
|
||||||
|
};
|
||||||
|
|
||||||
|
if address.network != expected_network {
|
||||||
|
bail!(BitcoinAddressNetworkMismatch {
|
||||||
|
expected: expected_network,
|
||||||
|
actual: address.network
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(address)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Bitcoin error codes: https://github.com/bitcoin/bitcoin/blob/97d3500601c1d28642347d014a6de1e38f53ae4e/src/rpc/protocol.h#L23
|
/// Bitcoin error codes: https://github.com/bitcoin/bitcoin/blob/97d3500601c1d28642347d014a6de1e38f53ae4e/src/rpc/protocol.h#L23
|
||||||
pub enum RpcErrorCode {
|
pub enum RpcErrorCode {
|
||||||
/// Transaction or block was rejected by network rules. Error code -26.
|
/// Transaction or block was rejected by network rules. Error code -26.
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -320,6 +320,43 @@ pub mod monero_amount {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod monero_address {
|
||||||
|
use anyhow::{bail, Result, Context};
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
#[derive(thiserror::Error, Debug, Clone, Copy, PartialEq)]
|
||||||
|
#[error("Invalid monero address provided, expected address on network {expected:?} but address provided is on {actual:?}")]
|
||||||
|
pub struct MoneroAddressNetworkMismatch {
|
||||||
|
pub expected: monero::Network,
|
||||||
|
pub actual: monero::Network,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse(s: &str) -> Result<monero::Address> {
|
||||||
|
monero::Address::from_str(s).with_context(|| {
|
||||||
|
format!(
|
||||||
|
"Failed to parse {} as a monero address, please make sure it is a valid address",
|
||||||
|
s
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn validate(address: monero::Address, is_testnet: bool) -> Result<monero::Address> {
|
||||||
|
let expected_network = if is_testnet {
|
||||||
|
monero::Network::Stagenet
|
||||||
|
} else {
|
||||||
|
monero::Network::Mainnet
|
||||||
|
};
|
||||||
|
|
||||||
|
if address.network != expected_network {
|
||||||
|
bail!(MoneroAddressNetworkMismatch {
|
||||||
|
expected: expected_network,
|
||||||
|
actual: address.network,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Ok(address)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -16,7 +16,7 @@ use torut::onion::TorSecretKeyV3;
|
||||||
|
|
||||||
pub const SEED_LENGTH: usize = 32;
|
pub const SEED_LENGTH: usize = 32;
|
||||||
|
|
||||||
#[derive(Eq, PartialEq)]
|
#[derive(Clone, Eq, PartialEq)]
|
||||||
pub struct Seed([u8; SEED_LENGTH]);
|
pub struct Seed([u8; SEED_LENGTH]);
|
||||||
|
|
||||||
impl Seed {
|
impl Seed {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue