605: Merge `--seller-addr` and `--seller-peer-id` into `--seller` parameter r=thomaseizinger a=thomaseizinger

This simplifies the CLI's interface.

It wills also play nicely with https://github.com/comit-network/xmr-btc-swap/pull/593.

Co-authored-by: Thomas Eizinger <thomas@eizinger.io>
This commit is contained in:
bors[bot] 2021-07-06 05:55:25 +00:00 committed by GitHub
commit 72673fa166
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 141 additions and 95 deletions

View File

@ -21,11 +21,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
Now, after sending a spot price the ASB will wait for one minute for the CLI's to trigger the execution setup, and three minutes to see the BTC lock transaction of the CLI in mempool after the swap started.
If the first timeout is triggered the execution setup will be aborted, if the second timeout is triggered the swap will be safely aborted.
### Changed
- The commandline interface of the CLI to combine `--seller-addr` and `--seller-peer-id`.
These two parameters have been merged into a parameter `--seller` that accepts a single [multiaddress](https://docs.libp2p.io/concepts/addressing/).
The multiaddress must end with a `/p2p` protocol defining the seller's peer ID.
### Removed
- The websocket transport from the CLI.
Websockets were only ever intended to be used for the ASB side to allow websites to retrieve quotes.
The CLI can use regular TCP connections and having both - TCP and websockets - causes problems and unnecessary overhead.
- The `--seller-addr` parameter from the CLI's `resume` command.
This information is now loaded from the database.
## [0.7.0] - 2021-05-28

View File

@ -27,6 +27,7 @@ use swap::cli::command::{parse_args_and_apply_defaults, Arguments, Command, Pars
use swap::cli::EventLoop;
use swap::database::Database;
use swap::env::Config;
use swap::libp2p_ext::MultiAddrExt;
use swap::network::quote::BidQuote;
use swap::network::swarm;
use swap::protocol::bob;
@ -58,8 +59,7 @@ async fn main() -> Result<()> {
match cmd {
Command::BuyXmr {
seller_peer_id,
seller_addr,
seller,
bitcoin_electrum_rpc_url,
bitcoin_target_block,
monero_receive_address,
@ -86,6 +86,11 @@ async fn main() -> Result<()> {
init_monero_wallet(data_dir, monero_daemon_address, env_config).await?;
let bitcoin_wallet = Arc::new(bitcoin_wallet);
let seller_peer_id = seller
.extract_peer_id()
.context("Seller address must contain peer ID")?;
db.insert_address(seller_peer_id, seller.clone()).await?;
let mut swarm = swarm::cli(
&seed,
seller_peer_id,
@ -94,9 +99,7 @@ async fn main() -> Result<()> {
bitcoin_wallet.clone(),
)
.await?;
swarm
.behaviour_mut()
.add_address(seller_peer_id, seller_addr);
swarm.behaviour_mut().add_address(seller_peer_id, seller);
tracing::debug!(peer_id = %swarm.local_peer_id(), "Network layer initialized");
@ -157,7 +160,6 @@ async fn main() -> Result<()> {
}
Command::Resume {
swap_id,
seller_addr,
bitcoin_electrum_rpc_url,
bitcoin_target_block,
monero_receive_address,
@ -187,6 +189,7 @@ async fn main() -> Result<()> {
let bitcoin_wallet = Arc::new(bitcoin_wallet);
let seller_peer_id = db.get_peer_id(swap_id)?;
let seller_addresses = db.get_addresses(seller_peer_id)?;
let mut swarm = swarm::cli(
&seed,
@ -198,9 +201,12 @@ async fn main() -> Result<()> {
.await?;
let our_peer_id = swarm.local_peer_id();
tracing::debug!(peer_id = %our_peer_id, "Initializing network module");
for seller_address in seller_addresses {
swarm
.behaviour_mut()
.add_address(seller_peer_id, seller_addr);
.add_address(seller_peer_id, seller_address);
}
let (event_loop, event_loop_handle) =
EventLoop::new(swap_id, swarm, seller_peer_id, env_config)?;

View File

@ -3,7 +3,6 @@ use crate::fs::system_data_dir;
use crate::{env, monero};
use anyhow::{Context, Result};
use libp2p::core::Multiaddr;
use libp2p::PeerId;
use std::ffi::OsString;
use std::path::PathBuf;
use std::str::FromStr;
@ -68,8 +67,7 @@ where
let arguments = match args.cmd {
RawCommand::BuyXmr {
seller_peer_id,
seller_addr: SellerAddr { seller_addr },
seller: Seller { seller },
bitcoin:
Bitcoin {
bitcoin_electrum_rpc_url,
@ -87,8 +85,7 @@ where
json,
data_dir: data::data_dir_from(data, is_testnet)?,
cmd: Command::BuyXmr {
seller_peer_id,
seller_addr,
seller,
bitcoin_electrum_rpc_url: bitcoin_electrum_rpc_url_from(
bitcoin_electrum_rpc_url,
is_testnet,
@ -114,7 +111,6 @@ where
},
RawCommand::Resume {
swap_id: SwapId { swap_id },
seller_addr: SellerAddr { seller_addr },
bitcoin:
Bitcoin {
bitcoin_electrum_rpc_url,
@ -133,7 +129,6 @@ where
data_dir: data::data_dir_from(data, is_testnet)?,
cmd: Command::Resume {
swap_id,
seller_addr,
bitcoin_electrum_rpc_url: bitcoin_electrum_rpc_url_from(
bitcoin_electrum_rpc_url,
is_testnet,
@ -201,8 +196,7 @@ where
#[derive(Debug, PartialEq)]
pub enum Command {
BuyXmr {
seller_peer_id: PeerId,
seller_addr: Multiaddr,
seller: Multiaddr,
bitcoin_electrum_rpc_url: Url,
bitcoin_target_block: usize,
monero_receive_address: monero::Address,
@ -212,7 +206,6 @@ pub enum Command {
History,
Resume {
swap_id: Uuid,
seller_addr: Multiaddr,
bitcoin_electrum_rpc_url: Url,
bitcoin_target_block: usize,
monero_receive_address: monero::Address,
@ -268,11 +261,8 @@ pub struct RawArguments {
pub enum RawCommand {
/// Start a XMR for BTC swap
BuyXmr {
#[structopt(long = "seller-peer-id", help = "The seller's peer id")]
seller_peer_id: PeerId,
#[structopt(flatten)]
seller_addr: SellerAddr,
seller: Seller,
#[structopt(flatten)]
bitcoin: Bitcoin,
@ -290,9 +280,6 @@ pub enum RawCommand {
#[structopt(flatten)]
swap_id: SwapId,
#[structopt(flatten)]
seller_addr: SellerAddr,
#[structopt(flatten)]
bitcoin: Bitcoin,
@ -373,9 +360,12 @@ pub struct SwapId {
}
#[derive(structopt::StructOpt, Debug)]
pub struct SellerAddr {
#[structopt(long = "seller-addr", help = "The seller's multiaddress")]
pub seller_addr: Multiaddr,
pub struct Seller {
#[structopt(
long,
help = "The seller's address. Must include a peer ID part, i.e. `/p2p/`"
)]
pub seller: Multiaddr,
}
mod data {
@ -492,8 +482,8 @@ mod tests {
const MONERO_STAGENET_ADDRESS: &str = "53gEuGZUhP9JMEBZoGaFNzhwEgiG7hwQdMCqFxiyiTeFPmkbt1mAoNybEUvYBKHcnrSgxnVWgZsTvRBaHBNXPa8tHiCU51a";
const MONERO_MAINNET_ADDRESS: &str = "44Ato7HveWidJYUAVw5QffEcEtSH1DwzSP3FPPkHxNAS4LX9CqgucphTisH978FLHE34YNEx7FcbBfQLQUU8m3NUC4VqsRa";
const MUTLI_ADDRESS: &str = "/ip4/127.0.0.1/tcp/9939";
const PEER_ID: &str = "12D3KooWCdMKjesXMJz1SiZ7HgotrxuqhQJbP5sgBm2BwP1cqThi";
const MULTI_ADDRESS: &str =
"/ip4/127.0.0.1/tcp/9939/p2p/12D3KooWCdMKjesXMJz1SiZ7HgotrxuqhQJbP5sgBm2BwP1cqThi";
const SWAP_ID: &str = "ea030832-3be9-454f-bb98-5ea9a788406b";
#[test]
@ -503,10 +493,8 @@ mod tests {
"buy-xmr",
"--receive-address",
MONERO_MAINNET_ADDRESS,
"--seller-addr",
MUTLI_ADDRESS,
"--seller-peer-id",
PEER_ID,
"--seller",
MULTI_ADDRESS,
];
let expected_args = ParseResult::Arguments(Arguments::buy_xmr_mainnet_defaults());
@ -523,10 +511,8 @@ mod tests {
"buy-xmr",
"--receive-address",
MONERO_STAGENET_ADDRESS,
"--seller-addr",
MUTLI_ADDRESS,
"--seller-peer-id",
PEER_ID,
"--seller",
MULTI_ADDRESS,
];
let args = parse_args_and_apply_defaults(raw_ars).unwrap();
@ -544,10 +530,8 @@ mod tests {
"buy-xmr",
"--receive-address",
MONERO_STAGENET_ADDRESS,
"--seller-addr",
MUTLI_ADDRESS,
"--seller-peer-id",
PEER_ID,
"--seller",
MULTI_ADDRESS,
];
let err = parse_args_and_apply_defaults(raw_ars).unwrap_err();
@ -569,10 +553,8 @@ mod tests {
"buy-xmr",
"--receive-address",
MONERO_MAINNET_ADDRESS,
"--seller-addr",
MUTLI_ADDRESS,
"--seller-peer-id",
PEER_ID,
"--seller",
MULTI_ADDRESS,
];
let err = parse_args_and_apply_defaults(raw_ars).unwrap_err();
@ -595,8 +577,6 @@ mod tests {
SWAP_ID,
"--receive-address",
MONERO_MAINNET_ADDRESS,
"--seller-addr",
MUTLI_ADDRESS,
];
let args = parse_args_and_apply_defaults(raw_ars).unwrap();
@ -617,8 +597,6 @@ mod tests {
SWAP_ID,
"--receive-address",
MONERO_STAGENET_ADDRESS,
"--seller-addr",
MUTLI_ADDRESS,
];
let args = parse_args_and_apply_defaults(raw_ars).unwrap();
@ -688,10 +666,8 @@ mod tests {
"buy-xmr",
"--receive-address",
MONERO_MAINNET_ADDRESS,
"--seller-addr",
MUTLI_ADDRESS,
"--seller-peer-id",
PEER_ID,
"--seller",
MULTI_ADDRESS,
];
let args = parse_args_and_apply_defaults(raw_ars).unwrap();
@ -712,10 +688,8 @@ mod tests {
"buy-xmr",
"--receive-address",
MONERO_STAGENET_ADDRESS,
"--seller-addr",
MUTLI_ADDRESS,
"--seller-peer-id",
PEER_ID,
"--seller",
MULTI_ADDRESS,
];
let args = parse_args_and_apply_defaults(raw_ars).unwrap();
@ -737,8 +711,6 @@ mod tests {
SWAP_ID,
"--receive-address",
MONERO_MAINNET_ADDRESS,
"--seller-addr",
MUTLI_ADDRESS,
];
let args = parse_args_and_apply_defaults(raw_ars).unwrap();
@ -761,8 +733,6 @@ mod tests {
SWAP_ID,
"--receive-address",
MONERO_STAGENET_ADDRESS,
"--seller-addr",
MUTLI_ADDRESS,
];
let args = parse_args_and_apply_defaults(raw_ars).unwrap();
@ -784,10 +754,8 @@ mod tests {
"buy-xmr",
"--receive-address",
MONERO_MAINNET_ADDRESS,
"--seller-addr",
MUTLI_ADDRESS,
"--seller-peer-id",
PEER_ID,
"--seller",
MULTI_ADDRESS,
];
let args = parse_args_and_apply_defaults(raw_ars).unwrap();
@ -803,10 +771,8 @@ mod tests {
"buy-xmr",
"--receive-address",
MONERO_STAGENET_ADDRESS,
"--seller-addr",
MUTLI_ADDRESS,
"--seller-peer-id",
PEER_ID,
"--seller",
MULTI_ADDRESS,
];
let args = parse_args_and_apply_defaults(raw_ars).unwrap();
@ -823,8 +789,6 @@ mod tests {
SWAP_ID,
"--receive-address",
MONERO_MAINNET_ADDRESS,
"--seller-addr",
MUTLI_ADDRESS,
];
let args = parse_args_and_apply_defaults(raw_ars).unwrap();
@ -842,8 +806,6 @@ mod tests {
SWAP_ID,
"--receive-address",
MONERO_STAGENET_ADDRESS,
"--seller-addr",
MUTLI_ADDRESS,
];
let args = parse_args_and_apply_defaults(raw_ars).unwrap();
@ -861,10 +823,8 @@ mod tests {
"buy-xmr",
"--receive-address",
MONERO_MAINNET_ADDRESS,
"--seller-addr",
MUTLI_ADDRESS,
"--seller-peer-id",
PEER_ID,
"--seller",
MULTI_ADDRESS,
];
let args = parse_args_and_apply_defaults(raw_ars).unwrap();
@ -880,10 +840,8 @@ mod tests {
"buy-xmr",
"--receive-address",
MONERO_STAGENET_ADDRESS,
"--seller-addr",
MUTLI_ADDRESS,
"--seller-peer-id",
PEER_ID,
"--seller",
MULTI_ADDRESS,
];
let args = parse_args_and_apply_defaults(raw_ars).unwrap();
@ -900,8 +858,6 @@ mod tests {
SWAP_ID,
"--receive-address",
MONERO_MAINNET_ADDRESS,
"--seller-addr",
MUTLI_ADDRESS,
];
let args = parse_args_and_apply_defaults(raw_ars).unwrap();
@ -919,8 +875,6 @@ mod tests {
SWAP_ID,
"--receive-address",
MONERO_STAGENET_ADDRESS,
"--seller-addr",
MUTLI_ADDRESS,
];
let args = parse_args_and_apply_defaults(raw_ars).unwrap();
@ -938,8 +892,7 @@ mod tests {
json: false,
data_dir: data_dir_path_cli().join(TESTNET),
cmd: Command::BuyXmr {
seller_peer_id: PeerId::from_str(PEER_ID).unwrap(),
seller_addr: Multiaddr::from_str(MUTLI_ADDRESS).unwrap(),
seller: Multiaddr::from_str(MULTI_ADDRESS).unwrap(),
bitcoin_electrum_rpc_url: Url::from_str(DEFAULT_ELECTRUM_RPC_URL_TESTNET)
.unwrap(),
bitcoin_target_block: DEFAULT_BITCOIN_CONFIRMATION_TARGET_TESTNET,
@ -958,8 +911,7 @@ mod tests {
json: false,
data_dir: data_dir_path_cli().join(MAINNET),
cmd: Command::BuyXmr {
seller_peer_id: PeerId::from_str(PEER_ID).unwrap(),
seller_addr: Multiaddr::from_str(MUTLI_ADDRESS).unwrap(),
seller: Multiaddr::from_str(MULTI_ADDRESS).unwrap(),
bitcoin_electrum_rpc_url: Url::from_str(DEFAULT_ELECTRUM_RPC_URL).unwrap(),
bitcoin_target_block: DEFAULT_BITCOIN_CONFIRMATION_TARGET,
monero_receive_address: monero::Address::from_str(MONERO_MAINNET_ADDRESS)
@ -978,7 +930,6 @@ mod tests {
data_dir: data_dir_path_cli().join(TESTNET),
cmd: Command::Resume {
swap_id: Uuid::from_str(SWAP_ID).unwrap(),
seller_addr: Multiaddr::from_str(MUTLI_ADDRESS).unwrap(),
bitcoin_electrum_rpc_url: Url::from_str(DEFAULT_ELECTRUM_RPC_URL_TESTNET)
.unwrap(),
bitcoin_target_block: DEFAULT_BITCOIN_CONFIRMATION_TARGET_TESTNET,
@ -998,7 +949,6 @@ mod tests {
data_dir: data_dir_path_cli().join(MAINNET),
cmd: Command::Resume {
swap_id: Uuid::from_str(SWAP_ID).unwrap(),
seller_addr: Multiaddr::from_str(MUTLI_ADDRESS).unwrap(),
bitcoin_electrum_rpc_url: Url::from_str(DEFAULT_ELECTRUM_RPC_URL).unwrap(),
bitcoin_target_block: DEFAULT_BITCOIN_CONFIRMATION_TARGET,
monero_receive_address: monero::Address::from_str(MONERO_MAINNET_ADDRESS)

View File

@ -3,7 +3,7 @@ pub use bob::Bob;
use anyhow::{anyhow, bail, Context, Result};
use itertools::Itertools;
use libp2p::PeerId;
use libp2p::{Multiaddr, PeerId};
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use std::fmt::Display;
@ -68,6 +68,7 @@ impl Swap {
pub struct Database {
swaps: sled::Tree,
peers: sled::Tree,
addresses: sled::Tree,
}
impl Database {
@ -79,8 +80,13 @@ impl Database {
let swaps = db.open_tree("swaps")?;
let peers = db.open_tree("peers")?;
let addresses = db.open_tree("addresses")?;
Ok(Database { swaps, peers })
Ok(Database {
swaps,
peers,
addresses,
})
}
pub async fn insert_peer_id(&self, swap_id: Uuid, peer_id: PeerId) -> Result<()> {
@ -110,6 +116,46 @@ impl Database {
Ok(PeerId::from_str(peer_id.as_str())?)
}
pub async fn insert_address(&self, peer_id: PeerId, address: Multiaddr) -> Result<()> {
let key = peer_id.to_bytes();
let existing_addresses = self.addresses.get(&key)?;
let new_addresses = {
let existing_addresses = existing_addresses.clone();
Some(match existing_addresses {
Some(encoded) => {
let mut addresses = deserialize::<Vec<Multiaddr>>(&encoded)?;
addresses.push(address);
serialize(&addresses)?
}
None => serialize(&[address])?,
})
};
self.addresses
.compare_and_swap(key, existing_addresses, new_addresses)??;
self.addresses
.flush_async()
.await
.map(|_| ())
.context("Could not flush db")
}
pub fn get_addresses(&self, peer_id: PeerId) -> Result<Vec<Multiaddr>> {
let key = peer_id.to_bytes();
let addresses = match self.addresses.get(&key)? {
Some(encoded) => deserialize(&encoded).context("Failed to deserialize addresses")?,
None => vec![],
};
Ok(addresses)
}
pub async fn insert_latest_state(&self, swap_id: Uuid, state: Swap) -> Result<()> {
let key = serialize(&swap_id)?;
let new_value = serialize(&state).context("Could not serialize new state value")?;
@ -359,4 +405,24 @@ mod tests {
Ok(())
}
#[tokio::test]
async fn save_and_load_addresses() -> Result<()> {
let db_dir = tempfile::tempdir()?;
let peer_id = PeerId::random();
let home1 = "/ip4/127.0.0.1/tcp/1".parse::<Multiaddr>()?;
let home2 = "/ip4/127.0.0.1/tcp/2".parse::<Multiaddr>()?;
{
let db = Database::open(db_dir.path())?;
db.insert_address(peer_id, home1.clone()).await?;
db.insert_address(peer_id, home2.clone()).await?;
}
let addresses = Database::open(db_dir.path())?.get_addresses(peer_id)?;
assert_eq!(addresses, vec![home1, home2]);
Ok(())
}
}

View File

@ -23,6 +23,7 @@ pub mod database;
pub mod env;
pub mod fs;
pub mod kraken;
pub mod libp2p_ext;
pub mod monero;
pub mod network;
pub mod protocol;

15
swap/src/libp2p_ext.rs Normal file
View File

@ -0,0 +1,15 @@
use libp2p::multiaddr::Protocol;
use libp2p::{Multiaddr, PeerId};
pub trait MultiAddrExt {
fn extract_peer_id(&self) -> Option<PeerId>;
}
impl MultiAddrExt for Multiaddr {
fn extract_peer_id(&self) -> Option<PeerId> {
match self.iter().last()? {
Protocol::P2p(multihash) => PeerId::from_multihash(multihash).ok(),
_ => None,
}
}
}