Implement Identify protocol to make network and version of ASB available to peers

This commit is contained in:
binarybaron 2022-04-17 19:57:34 +02:00
parent a962aa465d
commit 9e96ef64d3
11 changed files with 108 additions and 32 deletions

View File

@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Adjust quote based on Bitcoin balance. - 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. 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 - 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 ## [0.10.2] - 2021-12-25

29
Cargo.lock generated
View File

@ -1783,6 +1783,7 @@ dependencies = [
"lazy_static", "lazy_static",
"libp2p-core", "libp2p-core",
"libp2p-dns", "libp2p-dns",
"libp2p-identify",
"libp2p-metrics", "libp2p-metrics",
"libp2p-mplex", "libp2p-mplex",
"libp2p-noise", "libp2p-noise",
@ -1846,12 +1847,29 @@ dependencies = [
"trust-dns-resolver", "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]] [[package]]
name = "libp2p-metrics" name = "libp2p-metrics"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/libp2p/rust-libp2p.git#6d3ab8a3debe8d69dcd004173999732f12d0da96" source = "git+https://github.com/libp2p/rust-libp2p.git#6d3ab8a3debe8d69dcd004173999732f12d0da96"
dependencies = [ dependencies = [
"libp2p-core", "libp2p-core",
"libp2p-identify",
"libp2p-ping", "libp2p-ping",
"libp2p-swarm", "libp2p-swarm",
"open-metrics-client", "open-metrics-client",
@ -1941,7 +1959,7 @@ dependencies = [
"libp2p-core", "libp2p-core",
"libp2p-swarm", "libp2p-swarm",
"log", "log",
"lru", "lru 0.7.0",
"rand 0.7.3", "rand 0.7.3",
"smallvec", "smallvec",
"unsigned-varint", "unsigned-varint",
@ -2112,6 +2130,15 @@ dependencies = [
"cfg-if 1.0.0", "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]] [[package]]
name = "lru" name = "lru"
version = "0.7.0" version = "0.7.0"

View File

@ -31,7 +31,7 @@ ed25519-dalek = "1"
futures = { version = "0.3", default-features = false } futures = { version = "0.3", default-features = false }
hex = "0.4" hex = "0.4"
itertools = "0.10" 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 = { version = "0.12", features = [ "serde_support" ] }
monero-rpc = { path = "../monero-rpc" } monero-rpc = { path = "../monero-rpc" }
pem = "1.0" pem = "1.0"

View File

@ -13,6 +13,7 @@ use libp2p::core::connection::ConnectionId;
use libp2p::core::muxing::StreamMuxerBox; use libp2p::core::muxing::StreamMuxerBox;
use libp2p::core::transport::Boxed; use libp2p::core::transport::Boxed;
use libp2p::dns::TokioDnsConfig; use libp2p::dns::TokioDnsConfig;
use libp2p::identify::{Identify, IdentifyConfig, IdentifyEvent};
use libp2p::ping::{Ping, PingConfig, PingEvent}; use libp2p::ping::{Ping, PingConfig, PingEvent};
use libp2p::request_response::{RequestId, ResponseChannel}; use libp2p::request_response::{RequestId, ResponseChannel};
use libp2p::swarm::{ use libp2p::swarm::{
@ -111,6 +112,7 @@ pub mod behaviour {
pub swap_setup: alice::Behaviour<LR>, pub swap_setup: alice::Behaviour<LR>,
pub transfer_proof: transfer_proof::Behaviour, pub transfer_proof: transfer_proof::Behaviour,
pub encrypted_signature: encrypted_signature::Behaviour, pub encrypted_signature: encrypted_signature::Behaviour,
pub identify: Identify,
/// Ping behaviour that ensures that the underlying network connection /// Ping behaviour that ensures that the underlying network connection
/// is still alive. If the ping fails a connection close event /// is still alive. If the ping fails a connection close event
@ -128,8 +130,14 @@ pub mod behaviour {
latest_rate: LR, latest_rate: LR,
resume_only: bool, resume_only: bool,
env_config: env::Config, env_config: env::Config,
identify_params: (identity::Keypair, XmrBtcNamespace),
rendezvous_params: Option<(identity::Keypair, PeerId, Multiaddr, XmrBtcNamespace)>, rendezvous_params: Option<(identity::Keypair, PeerId, Multiaddr, XmrBtcNamespace)>,
) -> Self { ) -> 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 { Self {
rendezvous: libp2p::swarm::toggle::Toggle::from(rendezvous_params.map( rendezvous: libp2p::swarm::toggle::Toggle::from(rendezvous_params.map(
|(identity, rendezvous_peer_id, rendezvous_address, namespace)| { |(identity, rendezvous_peer_id, rendezvous_address, namespace)| {
@ -153,6 +161,7 @@ pub mod behaviour {
transfer_proof: transfer_proof::alice(), transfer_proof: transfer_proof::alice(),
encrypted_signature: encrypted_signature::alice(), encrypted_signature: encrypted_signature::alice(),
ping: Ping::new(PingConfig::new().with_keep_alive(true)), ping: Ping::new(PingConfig::new().with_keep_alive(true)),
identify: Identify::new(identifyConfig),
} }
} }
} }
@ -163,6 +172,12 @@ pub mod behaviour {
} }
} }
impl From<IdentifyEvent> for OutEvent {
fn from(_: IdentifyEvent) -> Self {
OutEvent::Other
}
}
impl From<libp2p::rendezvous::client::Event> for OutEvent { impl From<libp2p::rendezvous::client::Event> for OutEvent {
fn from(event: libp2p::rendezvous::client::Event) -> Self { fn from(event: libp2p::rendezvous::client::Event) -> Self {
OutEvent::Rendezvous(event) OutEvent::Rendezvous(event)

View File

@ -136,6 +136,8 @@ async fn main() -> Result<()> {
}; };
let kraken_rate = KrakenRate::new(config.maker.ask_spread, kraken_price_updates); let kraken_rate = KrakenRate::new(config.maker.ask_spread, kraken_price_updates);
let namespace = XmrBtcNamespace::from_is_testnet(testnet);
let mut swarm = swarm::asb( let mut swarm = swarm::asb(
&seed, &seed,
config.maker.min_buy_btc, config.maker.min_buy_btc,
@ -143,16 +145,8 @@ async fn main() -> Result<()> {
kraken_rate.clone(), kraken_rate.clone(),
resume_only, resume_only,
env_config, env_config,
config.network.rendezvous_point.map(|rendezvous_point| { namespace,
( config.network.rendezvous_point,
rendezvous_point,
if testnet {
XmrBtcNamespace::Testnet
} else {
XmrBtcNamespace::Mainnet
},
)
}),
)?; )?;
for listen in config.network.listen.clone() { for listen in config.network.listen.clone() {

View File

@ -63,6 +63,7 @@ async fn main() -> Result<()> {
monero_receive_address, monero_receive_address,
monero_daemon_address, monero_daemon_address,
tor_socks5_port, tor_socks5_port,
namespace,
} => { } => {
let swap_id = Uuid::new_v4(); let swap_id = Uuid::new_v4();
@ -87,7 +88,12 @@ async fn main() -> Result<()> {
.context("Seller address must contain peer ID")?; .context("Seller address must contain peer ID")?;
db.insert_address(seller_peer_id, seller.clone()).await?; 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 = let mut swarm =
swarm::cli(seed.derive_libp2p_identity(), tor_socks5_port, behaviour).await?; swarm::cli(seed.derive_libp2p_identity(), tor_socks5_port, behaviour).await?;
swarm.behaviour_mut().add_address(seller_peer_id, seller); swarm.behaviour_mut().add_address(seller_peer_id, seller);
@ -243,6 +249,7 @@ async fn main() -> Result<()> {
bitcoin_target_block, bitcoin_target_block,
monero_daemon_address, monero_daemon_address,
tor_socks5_port, tor_socks5_port,
namespace,
} => { } => {
cli::tracing::init(debug, json, data_dir.join("logs"), Some(swap_id))?; cli::tracing::init(debug, json, data_dir.join("logs"), Some(swap_id))?;
let db = open_db(data_dir.join("sqlite")).await?; 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_peer_id = db.get_peer_id(swap_id).await?;
let seller_addresses = db.get_addresses(seller_peer_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 = let mut swarm =
swarm::cli(seed.derive_libp2p_identity(), tor_socks5_port, behaviour).await?; swarm::cli(seed.derive_libp2p_identity(), tor_socks5_port, behaviour).await?;
let our_peer_id = swarm.local_peer_id(); let our_peer_id = swarm.local_peer_id();

View File

@ -1,13 +1,15 @@
use crate::network::quote::BidQuote; use crate::network::quote::BidQuote;
use crate::network::rendezvous::XmrBtcNamespace;
use crate::network::swap_setup::bob; use crate::network::swap_setup::bob;
use crate::network::{encrypted_signature, quote, redial, transfer_proof}; use crate::network::{encrypted_signature, quote, redial, transfer_proof};
use crate::protocol::bob::State2; use crate::protocol::bob::State2;
use crate::{bitcoin, env}; use crate::{bitcoin, env};
use anyhow::{anyhow, Error, Result}; use anyhow::{anyhow, Error, Result};
use libp2p::core::Multiaddr; use libp2p::core::Multiaddr;
use libp2p::identify::{Identify, IdentifyConfig, IdentifyEvent};
use libp2p::ping::{Ping, PingConfig, PingEvent}; use libp2p::ping::{Ping, PingConfig, PingEvent};
use libp2p::request_response::{RequestId, ResponseChannel}; use libp2p::request_response::{RequestId, ResponseChannel};
use libp2p::{NetworkBehaviour, PeerId}; use libp2p::{identity, NetworkBehaviour, PeerId};
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
@ -64,6 +66,7 @@ pub struct Behaviour {
pub transfer_proof: transfer_proof::Behaviour, pub transfer_proof: transfer_proof::Behaviour,
pub encrypted_signature: encrypted_signature::Behaviour, pub encrypted_signature: encrypted_signature::Behaviour,
pub redial: redial::Behaviour, pub redial: redial::Behaviour,
pub identify: Identify,
/// Ping behaviour that ensures that the underlying network connection is /// Ping behaviour that ensures that the underlying network connection is
/// still alive. If the ping fails a connection close event will be /// still alive. If the ping fails a connection close event will be
@ -76,7 +79,13 @@ impl Behaviour {
alice: PeerId, alice: PeerId,
env_config: env::Config, env_config: env::Config,
bitcoin_wallet: Arc<bitcoin::Wallet>, bitcoin_wallet: Arc<bitcoin::Wallet>,
identify_params: (identity::Keypair, XmrBtcNamespace),
) -> Self { ) -> 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 { Self {
quote: quote::cli(), quote: quote::cli(),
swap_setup: bob::Behaviour::new(env_config, bitcoin_wallet), swap_setup: bob::Behaviour::new(env_config, bitcoin_wallet),
@ -84,6 +93,7 @@ impl Behaviour {
encrypted_signature: encrypted_signature::bob(), encrypted_signature: encrypted_signature::bob(),
redial: redial::Behaviour::new(alice, Duration::from_secs(2)), redial: redial::Behaviour::new(alice, Duration::from_secs(2)),
ping: Ping::new(PingConfig::new().with_keep_alive(true)), ping: Ping::new(PingConfig::new().with_keep_alive(true)),
identify: Identify::new(identifyConfig),
} }
} }
@ -100,3 +110,9 @@ impl From<PingEvent> for OutEvent {
OutEvent::Other OutEvent::Other
} }
} }
impl From<IdentifyEvent> for OutEvent {
fn from(_: IdentifyEvent) -> Self {
OutEvent::Other
}
}

View File

@ -99,6 +99,7 @@ where
monero_receive_address, monero_receive_address,
monero_daemon_address, monero_daemon_address,
tor_socks5_port, tor_socks5_port,
namespace: XmrBtcNamespace::from_is_testnet(is_testnet),
}, },
} }
} }
@ -179,6 +180,7 @@ where
bitcoin_target_block, bitcoin_target_block,
monero_daemon_address, monero_daemon_address,
tor_socks5_port, tor_socks5_port,
namespace: XmrBtcNamespace::from_is_testnet(is_testnet),
}, },
} }
} }
@ -230,8 +232,8 @@ where
data_dir: data::data_dir_from(data, is_testnet)?, data_dir: data::data_dir_from(data, is_testnet)?,
cmd: Command::ListSellers { cmd: Command::ListSellers {
rendezvous_point, rendezvous_point,
namespace: rendezvous_namespace_from(is_testnet),
tor_socks5_port, tor_socks5_port,
namespace: XmrBtcNamespace::from_is_testnet(is_testnet),
}, },
}, },
RawCommand::ExportBitcoinWallet { bitcoin } => { RawCommand::ExportBitcoinWallet { bitcoin } => {
@ -273,6 +275,7 @@ pub enum Command {
monero_receive_address: monero::Address, monero_receive_address: monero::Address,
monero_daemon_address: String, monero_daemon_address: String,
tor_socks5_port: u16, tor_socks5_port: u16,
namespace: XmrBtcNamespace,
}, },
History, History,
Config, Config,
@ -292,6 +295,7 @@ pub enum Command {
bitcoin_target_block: usize, bitcoin_target_block: usize,
monero_daemon_address: String, monero_daemon_address: String,
tor_socks5_port: u16, tor_socks5_port: u16,
namespace: XmrBtcNamespace,
}, },
Cancel { Cancel {
swap_id: Uuid, 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 { fn env_config_from(testnet: bool) -> env::Config {
if testnet { if testnet {
env::Testnet::get_config() env::Testnet::get_config()
@ -1212,6 +1208,7 @@ mod tests {
.unwrap(), .unwrap(),
monero_daemon_address: DEFAULT_MONERO_DAEMON_ADDRESS_STAGENET.to_string(), monero_daemon_address: DEFAULT_MONERO_DAEMON_ADDRESS_STAGENET.to_string(),
tor_socks5_port: DEFAULT_SOCKS5_PORT, tor_socks5_port: DEFAULT_SOCKS5_PORT,
namespace: XmrBtcNamespace::Testnet,
}, },
} }
} }
@ -1231,6 +1228,7 @@ mod tests {
.unwrap(), .unwrap(),
monero_daemon_address: DEFAULT_MONERO_DAEMON_ADDRESS.to_string(), monero_daemon_address: DEFAULT_MONERO_DAEMON_ADDRESS.to_string(),
tor_socks5_port: DEFAULT_SOCKS5_PORT, tor_socks5_port: DEFAULT_SOCKS5_PORT,
namespace: XmrBtcNamespace::Mainnet,
}, },
} }
} }
@ -1248,6 +1246,7 @@ mod tests {
bitcoin_target_block: DEFAULT_BITCOIN_CONFIRMATION_TARGET_TESTNET, bitcoin_target_block: DEFAULT_BITCOIN_CONFIRMATION_TARGET_TESTNET,
monero_daemon_address: DEFAULT_MONERO_DAEMON_ADDRESS_STAGENET.to_string(), monero_daemon_address: DEFAULT_MONERO_DAEMON_ADDRESS_STAGENET.to_string(),
tor_socks5_port: DEFAULT_SOCKS5_PORT, tor_socks5_port: DEFAULT_SOCKS5_PORT,
namespace: XmrBtcNamespace::Testnet,
}, },
} }
} }
@ -1264,6 +1263,7 @@ mod tests {
bitcoin_target_block: DEFAULT_BITCOIN_CONFIRMATION_TARGET, bitcoin_target_block: DEFAULT_BITCOIN_CONFIRMATION_TARGET,
monero_daemon_address: DEFAULT_MONERO_DAEMON_ADDRESS.to_string(), monero_daemon_address: DEFAULT_MONERO_DAEMON_ADDRESS.to_string(),
tor_socks5_port: DEFAULT_SOCKS5_PORT, tor_socks5_port: DEFAULT_SOCKS5_PORT,
namespace: XmrBtcNamespace::Mainnet,
}, },
} }
} }

View File

@ -27,3 +27,13 @@ impl From<XmrBtcNamespace> for Namespace {
} }
} }
} }
impl XmrBtcNamespace {
pub fn from_is_testnet(testnet: bool) -> XmrBtcNamespace {
if testnet {
XmrBtcNamespace::Testnet
} else {
XmrBtcNamespace::Mainnet
}
}
}

View File

@ -16,14 +16,15 @@ pub fn asb<LR>(
latest_rate: LR, latest_rate: LR,
resume_only: bool, resume_only: bool,
env_config: env::Config, env_config: env::Config,
rendezvous_params: Option<(Multiaddr, XmrBtcNamespace)>, namespace: XmrBtcNamespace,
rendezvous_point: Option<Multiaddr>,
) -> Result<Swarm<asb::Behaviour<LR>>> ) -> Result<Swarm<asb::Behaviour<LR>>>
where where
LR: LatestRate + Send + 'static + Debug + Clone, LR: LatestRate + Send + 'static + Debug + Clone,
{ {
let identity = seed.derive_libp2p_identity(); 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 let peer_id = address
.extract_peer_id() .extract_peer_id()
.context("Rendezvous node address must contain peer ID")?; .context("Rendezvous node address must contain peer ID")?;
@ -39,6 +40,7 @@ where
latest_rate, latest_rate,
resume_only, resume_only,
env_config, env_config,
(identity.clone(), namespace),
rendezvous_params, rendezvous_params,
); );

View File

@ -19,6 +19,7 @@ use swap::bitcoin::{CancelTimelock, PunishTimelock, TxCancel, TxPunish, TxRedeem
use swap::database::SqliteDatabase; use swap::database::SqliteDatabase;
use swap::env::{Config, GetConfig}; use swap::env::{Config, GetConfig};
use swap::fs::ensure_directory_exists; use swap::fs::ensure_directory_exists;
use swap::network::rendezvous::XmrBtcNamespace;
use swap::network::swarm; use swap::network::swarm;
use swap::protocol::alice::{AliceState, Swap}; use swap::protocol::alice::{AliceState, Swap};
use swap::protocol::bob::BobState; use swap::protocol::bob::BobState;
@ -243,6 +244,7 @@ async fn start_alice(
latest_rate, latest_rate,
resume_only, resume_only,
env_config, env_config,
XmrBtcNamespace::Testnet,
None, None,
) )
.unwrap(); .unwrap();
@ -469,18 +471,15 @@ impl BobParams {
) -> Result<(cli::EventLoop, cli::EventLoopHandle)> { ) -> Result<(cli::EventLoop, cli::EventLoopHandle)> {
let tor_socks5_port = get_port() 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."); .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( let behaviour = cli::Behaviour::new(
self.alice_peer_id, self.alice_peer_id,
self.env_config, self.env_config,
self.bitcoin_wallet.clone(), self.bitcoin_wallet.clone(),
(identity.clone(), XmrBtcNamespace::Testnet),
); );
let mut swarm = swarm::cli( let mut swarm = swarm::cli(identity.clone(), tor_socks5_port, behaviour).await?;
self.seed.derive_libp2p_identity(),
tor_socks5_port,
behaviour,
)
.await?;
swarm swarm
.behaviour_mut() .behaviour_mut()
.add_address(self.alice_peer_id, self.alice_address.clone()); .add_address(self.alice_peer_id, self.alice_address.clone());