diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a34c1d3..e49dd774 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Adjust quote based on Bitcoin balance. If the max_buy_btc in the ASB config is higher than the available balance to trade it will return the max available balance discounting the locking fees for monero, in the case the balance is lower than the min_buy_btc config it will return 0 to the CLI. If the ASB returns a quote of 0 the CLI will not allow you continue with a trade. - Reduce required confirmations for Bitcoin transactions from 2 to 1 +- Both the ASB and CLI now support the [Identify](https://github.com/libp2p/specs/blob/master/identify/README.md) protocol. This makes its version and network (testnet/mainnet) avaliable to others ## [0.10.2] - 2021-12-25 diff --git a/Cargo.lock b/Cargo.lock index 8a58e2bc..6f66e617 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1783,6 +1783,7 @@ dependencies = [ "lazy_static", "libp2p-core", "libp2p-dns", + "libp2p-identify", "libp2p-metrics", "libp2p-mplex", "libp2p-noise", @@ -1846,12 +1847,29 @@ dependencies = [ "trust-dns-resolver", ] +[[package]] +name = "libp2p-identify" +version = "0.31.0" +source = "git+https://github.com/libp2p/rust-libp2p.git#6d3ab8a3debe8d69dcd004173999732f12d0da96" +dependencies = [ + "futures", + "libp2p-core", + "libp2p-swarm", + "log", + "lru 0.6.6", + "prost", + "prost-build", + "smallvec", + "wasm-timer", +] + [[package]] name = "libp2p-metrics" version = "0.1.0" source = "git+https://github.com/libp2p/rust-libp2p.git#6d3ab8a3debe8d69dcd004173999732f12d0da96" dependencies = [ "libp2p-core", + "libp2p-identify", "libp2p-ping", "libp2p-swarm", "open-metrics-client", @@ -1941,7 +1959,7 @@ dependencies = [ "libp2p-core", "libp2p-swarm", "log", - "lru", + "lru 0.7.0", "rand 0.7.3", "smallvec", "unsigned-varint", @@ -2112,6 +2130,15 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "lru" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ea2d928b485416e8908cff2d97d621db22b27f7b3b6729e438bcf42c671ba91" +dependencies = [ + "hashbrown", +] + [[package]] name = "lru" version = "0.7.0" diff --git a/swap/Cargo.toml b/swap/Cargo.toml index 0eda78ee..0aab53a0 100644 --- a/swap/Cargo.toml +++ b/swap/Cargo.toml @@ -31,7 +31,7 @@ ed25519-dalek = "1" futures = { version = "0.3", default-features = false } hex = "0.4" itertools = "0.10" -libp2p = { git = "https://github.com/libp2p/rust-libp2p.git", default-features = false, features = [ "tcp-tokio", "yamux", "mplex", "dns-tokio", "noise", "request-response", "websocket", "ping", "rendezvous" ] } +libp2p = { git = "https://github.com/libp2p/rust-libp2p.git", default-features = false, features = [ "tcp-tokio", "yamux", "mplex", "dns-tokio", "noise", "request-response", "websocket", "ping", "rendezvous", "identify" ] } monero = { version = "0.12", features = [ "serde_support" ] } monero-rpc = { path = "../monero-rpc" } pem = "1.0" diff --git a/swap/src/asb/network.rs b/swap/src/asb/network.rs index d24660b9..70c7f861 100644 --- a/swap/src/asb/network.rs +++ b/swap/src/asb/network.rs @@ -13,6 +13,7 @@ use libp2p::core::connection::ConnectionId; use libp2p::core::muxing::StreamMuxerBox; use libp2p::core::transport::Boxed; use libp2p::dns::TokioDnsConfig; +use libp2p::identify::{Identify, IdentifyConfig, IdentifyEvent}; use libp2p::ping::{Ping, PingConfig, PingEvent}; use libp2p::request_response::{RequestId, ResponseChannel}; use libp2p::swarm::{ @@ -111,6 +112,7 @@ pub mod behaviour { pub swap_setup: alice::Behaviour, pub transfer_proof: transfer_proof::Behaviour, pub encrypted_signature: encrypted_signature::Behaviour, + pub identify: Identify, /// Ping behaviour that ensures that the underlying network connection /// is still alive. If the ping fails a connection close event @@ -128,8 +130,14 @@ pub mod behaviour { latest_rate: LR, resume_only: bool, env_config: env::Config, + identify_params: (identity::Keypair, XmrBtcNamespace), rendezvous_params: Option<(identity::Keypair, PeerId, Multiaddr, XmrBtcNamespace)>, ) -> Self { + let agentVersion = format!("asb/{} ({})", env!("CARGO_PKG_VERSION"), identify_params.1); + let protocolVersion = "/comit/xmr/btc/1.0.0".to_string(); + let identifyConfig = IdentifyConfig::new(protocolVersion, identify_params.0.public()) + .with_agent_version(agentVersion); + Self { rendezvous: libp2p::swarm::toggle::Toggle::from(rendezvous_params.map( |(identity, rendezvous_peer_id, rendezvous_address, namespace)| { @@ -153,6 +161,7 @@ pub mod behaviour { transfer_proof: transfer_proof::alice(), encrypted_signature: encrypted_signature::alice(), ping: Ping::new(PingConfig::new().with_keep_alive(true)), + identify: Identify::new(identifyConfig), } } } @@ -163,6 +172,12 @@ pub mod behaviour { } } + impl From for OutEvent { + fn from(_: IdentifyEvent) -> Self { + OutEvent::Other + } + } + impl From for OutEvent { fn from(event: libp2p::rendezvous::client::Event) -> Self { OutEvent::Rendezvous(event) diff --git a/swap/src/bin/asb.rs b/swap/src/bin/asb.rs index 23300f20..a0e9b5e3 100644 --- a/swap/src/bin/asb.rs +++ b/swap/src/bin/asb.rs @@ -136,6 +136,8 @@ async fn main() -> Result<()> { }; let kraken_rate = KrakenRate::new(config.maker.ask_spread, kraken_price_updates); + let namespace = XmrBtcNamespace::from_is_testnet(testnet); + let mut swarm = swarm::asb( &seed, config.maker.min_buy_btc, @@ -143,16 +145,8 @@ async fn main() -> Result<()> { kraken_rate.clone(), resume_only, env_config, - config.network.rendezvous_point.map(|rendezvous_point| { - ( - rendezvous_point, - if testnet { - XmrBtcNamespace::Testnet - } else { - XmrBtcNamespace::Mainnet - }, - ) - }), + namespace, + config.network.rendezvous_point, )?; for listen in config.network.listen.clone() { diff --git a/swap/src/bin/swap.rs b/swap/src/bin/swap.rs index 92010783..a1188759 100644 --- a/swap/src/bin/swap.rs +++ b/swap/src/bin/swap.rs @@ -63,6 +63,7 @@ async fn main() -> Result<()> { monero_receive_address, monero_daemon_address, tor_socks5_port, + namespace, } => { let swap_id = Uuid::new_v4(); @@ -87,7 +88,12 @@ async fn main() -> Result<()> { .context("Seller address must contain peer ID")?; db.insert_address(seller_peer_id, seller.clone()).await?; - let behaviour = cli::Behaviour::new(seller_peer_id, env_config, bitcoin_wallet.clone()); + let behaviour = cli::Behaviour::new( + seller_peer_id, + env_config, + bitcoin_wallet.clone(), + (seed.derive_libp2p_identity(), namespace), + ); let mut swarm = swarm::cli(seed.derive_libp2p_identity(), tor_socks5_port, behaviour).await?; swarm.behaviour_mut().add_address(seller_peer_id, seller); @@ -243,6 +249,7 @@ async fn main() -> Result<()> { bitcoin_target_block, monero_daemon_address, tor_socks5_port, + namespace, } => { cli::tracing::init(debug, json, data_dir.join("logs"), Some(swap_id))?; let db = open_db(data_dir.join("sqlite")).await?; @@ -264,7 +271,12 @@ async fn main() -> Result<()> { let seller_peer_id = db.get_peer_id(swap_id).await?; let seller_addresses = db.get_addresses(seller_peer_id).await?; - let behaviour = cli::Behaviour::new(seller_peer_id, env_config, bitcoin_wallet.clone()); + let behaviour = cli::Behaviour::new( + seller_peer_id, + env_config, + bitcoin_wallet.clone(), + (seed.derive_libp2p_identity(), namespace), + ); let mut swarm = swarm::cli(seed.derive_libp2p_identity(), tor_socks5_port, behaviour).await?; let our_peer_id = swarm.local_peer_id(); diff --git a/swap/src/cli/behaviour.rs b/swap/src/cli/behaviour.rs index 716b7951..2ca8448f 100644 --- a/swap/src/cli/behaviour.rs +++ b/swap/src/cli/behaviour.rs @@ -1,13 +1,15 @@ use crate::network::quote::BidQuote; +use crate::network::rendezvous::XmrBtcNamespace; use crate::network::swap_setup::bob; use crate::network::{encrypted_signature, quote, redial, transfer_proof}; use crate::protocol::bob::State2; use crate::{bitcoin, env}; use anyhow::{anyhow, Error, Result}; use libp2p::core::Multiaddr; +use libp2p::identify::{Identify, IdentifyConfig, IdentifyEvent}; use libp2p::ping::{Ping, PingConfig, PingEvent}; use libp2p::request_response::{RequestId, ResponseChannel}; -use libp2p::{NetworkBehaviour, PeerId}; +use libp2p::{identity, NetworkBehaviour, PeerId}; use std::sync::Arc; use std::time::Duration; @@ -64,6 +66,7 @@ pub struct Behaviour { pub transfer_proof: transfer_proof::Behaviour, pub encrypted_signature: encrypted_signature::Behaviour, pub redial: redial::Behaviour, + pub identify: Identify, /// Ping behaviour that ensures that the underlying network connection is /// still alive. If the ping fails a connection close event will be @@ -76,7 +79,13 @@ impl Behaviour { alice: PeerId, env_config: env::Config, bitcoin_wallet: Arc, + identify_params: (identity::Keypair, XmrBtcNamespace), ) -> Self { + let agentVersion = format!("cli/{} ({})", env!("CARGO_PKG_VERSION"), identify_params.1); + let protocolVersion = "/comit/xmr/btc/1.0.0".to_string(); + let identifyConfig = IdentifyConfig::new(protocolVersion, identify_params.0.public()) + .with_agent_version(agentVersion); + Self { quote: quote::cli(), swap_setup: bob::Behaviour::new(env_config, bitcoin_wallet), @@ -84,6 +93,7 @@ impl Behaviour { encrypted_signature: encrypted_signature::bob(), redial: redial::Behaviour::new(alice, Duration::from_secs(2)), ping: Ping::new(PingConfig::new().with_keep_alive(true)), + identify: Identify::new(identifyConfig), } } @@ -100,3 +110,9 @@ impl From for OutEvent { OutEvent::Other } } + +impl From for OutEvent { + fn from(_: IdentifyEvent) -> Self { + OutEvent::Other + } +} diff --git a/swap/src/cli/command.rs b/swap/src/cli/command.rs index ae793e1d..631cc00e 100644 --- a/swap/src/cli/command.rs +++ b/swap/src/cli/command.rs @@ -99,6 +99,7 @@ where monero_receive_address, monero_daemon_address, tor_socks5_port, + namespace: XmrBtcNamespace::from_is_testnet(is_testnet), }, } } @@ -179,6 +180,7 @@ where bitcoin_target_block, monero_daemon_address, tor_socks5_port, + namespace: XmrBtcNamespace::from_is_testnet(is_testnet), }, } } @@ -230,8 +232,8 @@ where data_dir: data::data_dir_from(data, is_testnet)?, cmd: Command::ListSellers { rendezvous_point, - namespace: rendezvous_namespace_from(is_testnet), tor_socks5_port, + namespace: XmrBtcNamespace::from_is_testnet(is_testnet), }, }, RawCommand::ExportBitcoinWallet { bitcoin } => { @@ -273,6 +275,7 @@ pub enum Command { monero_receive_address: monero::Address, monero_daemon_address: String, tor_socks5_port: u16, + namespace: XmrBtcNamespace, }, History, Config, @@ -292,6 +295,7 @@ pub enum Command { bitcoin_target_block: usize, monero_daemon_address: String, tor_socks5_port: u16, + namespace: XmrBtcNamespace, }, Cancel { swap_id: Uuid, @@ -562,14 +566,6 @@ mod data { } } -fn rendezvous_namespace_from(is_testnet: bool) -> XmrBtcNamespace { - if is_testnet { - XmrBtcNamespace::Testnet - } else { - XmrBtcNamespace::Mainnet - } -} - fn env_config_from(testnet: bool) -> env::Config { if testnet { env::Testnet::get_config() @@ -1212,6 +1208,7 @@ mod tests { .unwrap(), monero_daemon_address: DEFAULT_MONERO_DAEMON_ADDRESS_STAGENET.to_string(), tor_socks5_port: DEFAULT_SOCKS5_PORT, + namespace: XmrBtcNamespace::Testnet, }, } } @@ -1231,6 +1228,7 @@ mod tests { .unwrap(), monero_daemon_address: DEFAULT_MONERO_DAEMON_ADDRESS.to_string(), tor_socks5_port: DEFAULT_SOCKS5_PORT, + namespace: XmrBtcNamespace::Mainnet, }, } } @@ -1248,6 +1246,7 @@ mod tests { bitcoin_target_block: DEFAULT_BITCOIN_CONFIRMATION_TARGET_TESTNET, monero_daemon_address: DEFAULT_MONERO_DAEMON_ADDRESS_STAGENET.to_string(), tor_socks5_port: DEFAULT_SOCKS5_PORT, + namespace: XmrBtcNamespace::Testnet, }, } } @@ -1264,6 +1263,7 @@ mod tests { bitcoin_target_block: DEFAULT_BITCOIN_CONFIRMATION_TARGET, monero_daemon_address: DEFAULT_MONERO_DAEMON_ADDRESS.to_string(), tor_socks5_port: DEFAULT_SOCKS5_PORT, + namespace: XmrBtcNamespace::Mainnet, }, } } diff --git a/swap/src/network/rendezvous.rs b/swap/src/network/rendezvous.rs index 5f8727c5..86a698a2 100644 --- a/swap/src/network/rendezvous.rs +++ b/swap/src/network/rendezvous.rs @@ -27,3 +27,13 @@ impl From for Namespace { } } } + +impl XmrBtcNamespace { + pub fn from_is_testnet(testnet: bool) -> XmrBtcNamespace { + if testnet { + XmrBtcNamespace::Testnet + } else { + XmrBtcNamespace::Mainnet + } + } +} diff --git a/swap/src/network/swarm.rs b/swap/src/network/swarm.rs index 8d4c7703..21bbfc4d 100644 --- a/swap/src/network/swarm.rs +++ b/swap/src/network/swarm.rs @@ -16,14 +16,15 @@ pub fn asb( latest_rate: LR, resume_only: bool, env_config: env::Config, - rendezvous_params: Option<(Multiaddr, XmrBtcNamespace)>, + namespace: XmrBtcNamespace, + rendezvous_point: Option, ) -> Result>> where LR: LatestRate + Send + 'static + Debug + Clone, { let identity = seed.derive_libp2p_identity(); - let rendezvous_params = if let Some((address, namespace)) = rendezvous_params { + let rendezvous_params = if let Some(address) = rendezvous_point { let peer_id = address .extract_peer_id() .context("Rendezvous node address must contain peer ID")?; @@ -39,6 +40,7 @@ where latest_rate, resume_only, env_config, + (identity.clone(), namespace), rendezvous_params, ); diff --git a/swap/tests/harness/mod.rs b/swap/tests/harness/mod.rs index b23201e0..e7971e66 100644 --- a/swap/tests/harness/mod.rs +++ b/swap/tests/harness/mod.rs @@ -19,6 +19,7 @@ use swap::bitcoin::{CancelTimelock, PunishTimelock, TxCancel, TxPunish, TxRedeem use swap::database::SqliteDatabase; use swap::env::{Config, GetConfig}; use swap::fs::ensure_directory_exists; +use swap::network::rendezvous::XmrBtcNamespace; use swap::network::swarm; use swap::protocol::alice::{AliceState, Swap}; use swap::protocol::bob::BobState; @@ -243,6 +244,7 @@ async fn start_alice( latest_rate, resume_only, env_config, + XmrBtcNamespace::Testnet, None, ) .unwrap(); @@ -469,18 +471,15 @@ impl BobParams { ) -> Result<(cli::EventLoop, cli::EventLoopHandle)> { let tor_socks5_port = get_port() .expect("We don't care about Tor in the tests so we get a free port to disable it."); + let identity = self.seed.derive_libp2p_identity(); let behaviour = cli::Behaviour::new( self.alice_peer_id, self.env_config, self.bitcoin_wallet.clone(), + (identity.clone(), XmrBtcNamespace::Testnet), ); - let mut swarm = swarm::cli( - self.seed.derive_libp2p_identity(), - tor_socks5_port, - behaviour, - ) - .await?; + let mut swarm = swarm::cli(identity.clone(), tor_socks5_port, behaviour).await?; swarm .behaviour_mut() .add_address(self.alice_peer_id, self.alice_address.clone());