mirror of
https://github.com/comit-network/xmr-btc-swap.git
synced 2025-01-25 14:56:23 -05:00
Include unreachable nodes in table output
We emit an `info!` log for every peer that we discover but only ever emitted a `debug!` log if we fail to connect. This leads to a situation where the user would run `swap list-sellers`, the logs would say "Discovered XYZ at ABC" but then get a potentially empty table. To not confuse the user, we include unreachable nodes in the table output. For example: ``` Connected to rendezvous point, discovering nodes in 'xmr-btc-swap-testnet' namespace ... Discovered peer 12D3KooWPZ69DRp4wbGB3wJsxxsg1XW1EVZ2evtVwcARCF3a1nrx at /dns4/ac4hgzmsmekwekjbdl77brufqqbylddugzze4tel6qsnlympgmr46iid.onion/tcp/8765 +-------+--------------+--------------+-------------+----------------------------------------------------------------------------------------------------------------------------------------+ | PRICE | MIN_QUANTITY | MAX_QUANTITY | STATUS | ADDRESS | +============================================================================================================================================================================================+ | ??? | ??? | ??? | Unreachable | /dns4/ac4hgzmsmekwekjbdl77brufqqbylddugzze4tel6qsnlympgmr46iid.onion/tcp/8765/p2p/12D3KooWPZ69DRp4wbGB3wJsxxsg1XW1EVZ2evtVwcARCF3a1nrx | +-------+--------------+--------------+-------------+----------------------------------------------------------------------------------------------------------------------------------------+ ```
This commit is contained in:
parent
09f395a26b
commit
987f8abb9d
@ -24,7 +24,7 @@ use std::sync::Arc;
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use swap::bitcoin::TxLock;
|
use swap::bitcoin::TxLock;
|
||||||
use swap::cli::command::{parse_args_and_apply_defaults, Arguments, Command, ParseResult};
|
use swap::cli::command::{parse_args_and_apply_defaults, Arguments, Command, ParseResult};
|
||||||
use swap::cli::{list_sellers, EventLoop};
|
use swap::cli::{list_sellers, EventLoop, SellerStatus};
|
||||||
use swap::database::Database;
|
use swap::database::Database;
|
||||||
use swap::env::Config;
|
use swap::env::Config;
|
||||||
use swap::libp2p_ext::MultiAddrExt;
|
use swap::libp2p_ext::MultiAddrExt;
|
||||||
@ -285,7 +285,7 @@ async fn main() -> Result<()> {
|
|||||||
.context("Failed to read in seed file")?;
|
.context("Failed to read in seed file")?;
|
||||||
let identity = seed.derive_libp2p_identity();
|
let identity = seed.derive_libp2p_identity();
|
||||||
|
|
||||||
let sellers = list_sellers(
|
let mut sellers = list_sellers(
|
||||||
rendezvous_node_peer_id,
|
rendezvous_node_peer_id,
|
||||||
rendezvous_node_addr,
|
rendezvous_node_addr,
|
||||||
namespace,
|
namespace,
|
||||||
@ -293,6 +293,7 @@ async fn main() -> Result<()> {
|
|||||||
identity,
|
identity,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
sellers.sort();
|
||||||
|
|
||||||
if json {
|
if json {
|
||||||
for seller in sellers {
|
for seller in sellers {
|
||||||
@ -301,15 +302,37 @@ async fn main() -> Result<()> {
|
|||||||
} else {
|
} else {
|
||||||
let mut table = Table::new();
|
let mut table = Table::new();
|
||||||
|
|
||||||
table.set_header(vec!["PRICE", "MIN_QUANTITY", "MAX_QUANTITY", "ADDRESS"]);
|
table.set_header(vec![
|
||||||
|
"PRICE",
|
||||||
|
"MIN_QUANTITY",
|
||||||
|
"MAX_QUANTITY",
|
||||||
|
"STATUS",
|
||||||
|
"ADDRESS",
|
||||||
|
]);
|
||||||
|
|
||||||
for seller in sellers {
|
for seller in sellers {
|
||||||
table.add_row(vec![
|
let row = match seller.status {
|
||||||
seller.quote.price.to_string(),
|
SellerStatus::Online(quote) => {
|
||||||
seller.quote.min_quantity.to_string(),
|
vec![
|
||||||
seller.quote.max_quantity.to_string(),
|
quote.price.to_string(),
|
||||||
seller.multiaddr.to_string(),
|
quote.min_quantity.to_string(),
|
||||||
]);
|
quote.max_quantity.to_string(),
|
||||||
|
"Online".to_owned(),
|
||||||
|
seller.multiaddr.to_string(),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
SellerStatus::Unreachable => {
|
||||||
|
vec![
|
||||||
|
"???".to_owned(),
|
||||||
|
"???".to_owned(),
|
||||||
|
"???".to_owned(),
|
||||||
|
"Unreachable".to_owned(),
|
||||||
|
seller.multiaddr.to_string(),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
table.add_row(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("{}", table);
|
println!("{}", table);
|
||||||
|
@ -10,14 +10,14 @@ pub mod transport;
|
|||||||
pub use behaviour::{Behaviour, OutEvent};
|
pub use behaviour::{Behaviour, OutEvent};
|
||||||
pub use cancel::cancel;
|
pub use cancel::cancel;
|
||||||
pub use event_loop::{EventLoop, EventLoopHandle};
|
pub use event_loop::{EventLoop, EventLoopHandle};
|
||||||
pub use list_sellers::list_sellers;
|
pub use list_sellers::{list_sellers, Seller, Status as SellerStatus};
|
||||||
pub use refund::refund;
|
pub use refund::refund;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::asb;
|
use crate::asb;
|
||||||
use crate::cli::list_sellers::Seller;
|
use crate::cli::list_sellers::{Seller, Status};
|
||||||
use crate::network::quote;
|
use crate::network::quote;
|
||||||
use crate::network::quote::BidQuote;
|
use crate::network::quote::BidQuote;
|
||||||
use crate::network::rendezvous::XmrBtcNamespace;
|
use crate::network::rendezvous::XmrBtcNamespace;
|
||||||
@ -122,7 +122,7 @@ mod tests {
|
|||||||
|
|
||||||
Seller {
|
Seller {
|
||||||
multiaddr: asb_address.with(Protocol::P2p(asb_peer_id.into())),
|
multiaddr: asb_address.with(Protocol::P2p(asb_peer_id.into())),
|
||||||
quote: static_quote,
|
status: Status::Online(static_quote),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ use libp2p::swarm::SwarmEvent;
|
|||||||
use libp2p::{identity, rendezvous, Multiaddr, PeerId, Swarm};
|
use libp2p::{identity, rendezvous, Multiaddr, PeerId, Swarm};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_with::{serde_as, DisplayFromStr};
|
use serde_with::{serde_as, DisplayFromStr};
|
||||||
|
use std::collections::hash_map::Entry;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
@ -52,11 +53,17 @@ pub async fn list_sellers(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[serde_as]
|
#[serde_as]
|
||||||
#[derive(Debug, Serialize, PartialEq, Eq, Hash)]
|
#[derive(Debug, Serialize, PartialEq, Eq, Hash, Ord, PartialOrd)]
|
||||||
pub struct Seller {
|
pub struct Seller {
|
||||||
|
pub status: Status,
|
||||||
#[serde_as(as = "DisplayFromStr")]
|
#[serde_as(as = "DisplayFromStr")]
|
||||||
pub multiaddr: Multiaddr,
|
pub multiaddr: Multiaddr,
|
||||||
pub quote: BidQuote,
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, PartialEq, Eq, Hash, Copy, Clone, Ord, PartialOrd)]
|
||||||
|
pub enum Status {
|
||||||
|
Online(BidQuote),
|
||||||
|
Unreachable,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -90,7 +97,7 @@ struct Behaviour {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum QuoteStatus {
|
enum QuoteStatus {
|
||||||
Pending,
|
Pending,
|
||||||
Received(BidQuote),
|
Received(Status),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -104,7 +111,8 @@ struct EventLoop {
|
|||||||
rendezvous_peer_id: PeerId,
|
rendezvous_peer_id: PeerId,
|
||||||
rendezvous_addr: Multiaddr,
|
rendezvous_addr: Multiaddr,
|
||||||
namespace: XmrBtcNamespace,
|
namespace: XmrBtcNamespace,
|
||||||
asb_address: HashMap<PeerId, Multiaddr>,
|
reachable_asb_address: HashMap<PeerId, Multiaddr>,
|
||||||
|
unreachable_asb_address: HashMap<PeerId, Multiaddr>,
|
||||||
asb_quote_status: HashMap<PeerId, QuoteStatus>,
|
asb_quote_status: HashMap<PeerId, QuoteStatus>,
|
||||||
state: State,
|
state: State,
|
||||||
}
|
}
|
||||||
@ -121,7 +129,8 @@ impl EventLoop {
|
|||||||
rendezvous_peer_id,
|
rendezvous_peer_id,
|
||||||
rendezvous_addr,
|
rendezvous_addr,
|
||||||
namespace,
|
namespace,
|
||||||
asb_address: Default::default(),
|
reachable_asb_address: Default::default(),
|
||||||
|
unreachable_asb_address: Default::default(),
|
||||||
asb_quote_status: Default::default(),
|
asb_quote_status: Default::default(),
|
||||||
state: State::WaitForDiscovery,
|
state: State::WaitForDiscovery,
|
||||||
}
|
}
|
||||||
@ -147,7 +156,7 @@ impl EventLoop {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
let address = endpoint.get_remote_address();
|
let address = endpoint.get_remote_address();
|
||||||
self.asb_address.insert(peer_id, address.clone());
|
self.reachable_asb_address.insert(peer_id, address.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SwarmEvent::UnreachableAddr { peer_id, error, address, .. } => {
|
SwarmEvent::UnreachableAddr { peer_id, error, address, .. } => {
|
||||||
@ -166,9 +175,16 @@ impl EventLoop {
|
|||||||
address,
|
address,
|
||||||
error
|
error
|
||||||
);
|
);
|
||||||
|
self.unreachable_asb_address.insert(peer_id, address.clone());
|
||||||
|
|
||||||
// if a different peer than the rendezvous node is unreachable (i.e. a seller) we remove that seller from the quote status state
|
match self.asb_quote_status.entry(peer_id) {
|
||||||
self.asb_quote_status.remove(&peer_id);
|
Entry::Occupied(mut entry) => {
|
||||||
|
entry.insert(QuoteStatus::Received(Status::Unreachable));
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
tracing::debug!(%peer_id, %error, "Connection error with unexpected peer")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SwarmEvent::Behaviour(OutEvent::Rendezvous(
|
SwarmEvent::Behaviour(OutEvent::Rendezvous(
|
||||||
@ -205,7 +221,7 @@ impl EventLoop {
|
|||||||
RequestResponseEvent::Message { peer, message } => {
|
RequestResponseEvent::Message { peer, message } => {
|
||||||
match message {
|
match message {
|
||||||
RequestResponseMessage::Response { response, .. } => {
|
RequestResponseMessage::Response { response, .. } => {
|
||||||
if self.asb_quote_status.insert(peer, QuoteStatus::Received(response)).is_none() {
|
if self.asb_quote_status.insert(peer, QuoteStatus::Received(Status::Online(response))).is_none() {
|
||||||
tracing::error!(%peer, "Received bid quote from unexpected peer, this record will be removed!");
|
tracing::error!(%peer, "Received bid quote from unexpected peer, this record will be removed!");
|
||||||
self.asb_quote_status.remove(&peer);
|
self.asb_quote_status.remove(&peer);
|
||||||
}
|
}
|
||||||
@ -247,15 +263,26 @@ impl EventLoop {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|(peer_id, quote_status)| match quote_status {
|
.map(|(peer_id, quote_status)| match quote_status {
|
||||||
QuoteStatus::Pending => Err(StillPending {}),
|
QuoteStatus::Pending => Err(StillPending {}),
|
||||||
QuoteStatus::Received(quote) => {
|
QuoteStatus::Received(Status::Online(quote)) => {
|
||||||
let address = self
|
let address = self
|
||||||
.asb_address
|
.reachable_asb_address
|
||||||
.get(&peer_id)
|
.get(&peer_id)
|
||||||
.expect("if we got a quote we must have stored an address");
|
.expect("if we got a quote we must have stored an address");
|
||||||
|
|
||||||
Ok(Seller {
|
Ok(Seller {
|
||||||
multiaddr: address.clone(),
|
multiaddr: address.clone(),
|
||||||
quote: *quote,
|
status: Status::Online(*quote),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
QuoteStatus::Received(Status::Unreachable) => {
|
||||||
|
let address = self
|
||||||
|
.unreachable_asb_address
|
||||||
|
.get(&peer_id)
|
||||||
|
.expect("if we got a quote we must have stored an address");
|
||||||
|
|
||||||
|
Ok(Seller {
|
||||||
|
multiaddr: address.clone(),
|
||||||
|
status: Status::Unreachable,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -279,3 +306,51 @@ impl From<PingEvent> for OutEvent {
|
|||||||
OutEvent::Ping(event)
|
OutEvent::Ping(event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sellers_sort_with_unreachable_coming_last() {
|
||||||
|
let mut list = vec![
|
||||||
|
Seller {
|
||||||
|
multiaddr: "/ip4/127.0.0.1/tcp/1234".parse().unwrap(),
|
||||||
|
status: Status::Unreachable,
|
||||||
|
},
|
||||||
|
Seller {
|
||||||
|
multiaddr: Multiaddr::empty(),
|
||||||
|
status: Status::Unreachable,
|
||||||
|
},
|
||||||
|
Seller {
|
||||||
|
multiaddr: "/ip4/127.0.0.1/tcp/5678".parse().unwrap(),
|
||||||
|
status: Status::Online(BidQuote {
|
||||||
|
price: Default::default(),
|
||||||
|
min_quantity: Default::default(),
|
||||||
|
max_quantity: Default::default(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
list.sort();
|
||||||
|
|
||||||
|
assert_eq!(list, vec![
|
||||||
|
Seller {
|
||||||
|
multiaddr: "/ip4/127.0.0.1/tcp/5678".parse().unwrap(),
|
||||||
|
status: Status::Online(BidQuote {
|
||||||
|
price: Default::default(),
|
||||||
|
min_quantity: Default::default(),
|
||||||
|
max_quantity: Default::default(),
|
||||||
|
})
|
||||||
|
},
|
||||||
|
Seller {
|
||||||
|
multiaddr: Multiaddr::empty(),
|
||||||
|
status: Status::Unreachable
|
||||||
|
},
|
||||||
|
Seller {
|
||||||
|
multiaddr: "/ip4/127.0.0.1/tcp/1234".parse().unwrap(),
|
||||||
|
status: Status::Unreachable
|
||||||
|
},
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -24,7 +24,7 @@ impl ProtocolName for BidQuoteProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Represents a quote for buying XMR.
|
/// Represents a quote for buying XMR.
|
||||||
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
|
||||||
pub struct BidQuote {
|
pub struct BidQuote {
|
||||||
/// The price at which the maker is willing to buy at.
|
/// The price at which the maker is willing to buy at.
|
||||||
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
|
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user