mirror of
https://github.com/comit-network/xmr-btc-swap.git
synced 2025-01-23 13:51:08 -05:00
Save Alice's peer-id in the db for Bob
This allows loading the seller-peer-id from the database upon resuming a swap. Thus, the parameters `--seller-peer-id` is removed for the `resume` command. Other than the peer-id the multi address of a seller can change and thus is still a parameter. This parameter might become optional once we add DHT support.
This commit is contained in:
parent
bc442bcad3
commit
d90496931b
@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- The `resume` command of the `swap` CLI no longer require the `--seller-peer-id` parameter.
|
||||||
|
This information is now saved in the database.
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- A changelog file.
|
- A changelog file.
|
||||||
|
@ -21,7 +21,7 @@ use std::sync::Arc;
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
use swap::bitcoin::{Amount, TxLock};
|
use swap::bitcoin::{Amount, TxLock};
|
||||||
use swap::cli::command::{AliceConnectParams, Arguments, Command, Data, MoneroParams};
|
use swap::cli::command::{AliceMultiaddress, Arguments, Command, Data, MoneroParams};
|
||||||
use swap::database::Database;
|
use swap::database::Database;
|
||||||
use swap::env::{Config, GetConfig};
|
use swap::env::{Config, GetConfig};
|
||||||
use swap::network::quote::BidQuote;
|
use swap::network::quote::BidQuote;
|
||||||
@ -81,9 +81,9 @@ async fn main() -> Result<()> {
|
|||||||
|
|
||||||
match args.cmd {
|
match args.cmd {
|
||||||
Command::BuyXmr {
|
Command::BuyXmr {
|
||||||
connect_params:
|
alice_peer_id,
|
||||||
AliceConnectParams {
|
alice_multi_addr:
|
||||||
peer_id: alice_peer_id,
|
AliceMultiaddress {
|
||||||
multiaddr: alice_addr,
|
multiaddr: alice_addr,
|
||||||
},
|
},
|
||||||
monero_params:
|
monero_params:
|
||||||
@ -131,9 +131,12 @@ async fn main() -> Result<()> {
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
let swap_id = Uuid::new_v4();
|
||||||
|
db.insert_peer_id(swap_id, alice_peer_id).await?;
|
||||||
|
|
||||||
let swap = Builder::new(
|
let swap = Builder::new(
|
||||||
db,
|
db,
|
||||||
Uuid::new_v4(),
|
swap_id,
|
||||||
bitcoin_wallet.clone(),
|
bitcoin_wallet.clone(),
|
||||||
Arc::new(monero_wallet),
|
Arc::new(monero_wallet),
|
||||||
env_config,
|
env_config,
|
||||||
@ -167,9 +170,8 @@ async fn main() -> Result<()> {
|
|||||||
}
|
}
|
||||||
Command::Resume {
|
Command::Resume {
|
||||||
swap_id,
|
swap_id,
|
||||||
connect_params:
|
alice_multi_addr:
|
||||||
AliceConnectParams {
|
AliceMultiaddress {
|
||||||
peer_id: alice_peer_id,
|
|
||||||
multiaddr: alice_addr,
|
multiaddr: alice_addr,
|
||||||
},
|
},
|
||||||
monero_params:
|
monero_params:
|
||||||
@ -189,6 +191,7 @@ async fn main() -> Result<()> {
|
|||||||
init_monero_wallet(data_dir, monero_daemon_host, env_config).await?;
|
init_monero_wallet(data_dir, monero_daemon_host, env_config).await?;
|
||||||
let bitcoin_wallet = Arc::new(bitcoin_wallet);
|
let bitcoin_wallet = Arc::new(bitcoin_wallet);
|
||||||
|
|
||||||
|
let alice_peer_id = db.get_peer_id(swap_id)?;
|
||||||
let mut swarm = swarm::new::<Behaviour>(&seed)?;
|
let mut swarm = swarm::new::<Behaviour>(&seed)?;
|
||||||
swarm.add_address(alice_peer_id, alice_addr);
|
swarm.add_address(alice_peer_id, alice_addr);
|
||||||
|
|
||||||
|
@ -37,8 +37,15 @@ pub struct Arguments {
|
|||||||
pub enum Command {
|
pub enum Command {
|
||||||
/// Start a XMR for BTC swap
|
/// Start a XMR for BTC swap
|
||||||
BuyXmr {
|
BuyXmr {
|
||||||
|
#[structopt(
|
||||||
|
long = "seller-peer-id",
|
||||||
|
default_value = DEFAULT_ALICE_PEER_ID,
|
||||||
|
help = "The peer id of a specific swap partner can be optionally provided"
|
||||||
|
)]
|
||||||
|
alice_peer_id: PeerId,
|
||||||
|
|
||||||
#[structopt(flatten)]
|
#[structopt(flatten)]
|
||||||
connect_params: AliceConnectParams,
|
alice_multi_addr: AliceMultiaddress,
|
||||||
|
|
||||||
#[structopt(long = "electrum-rpc",
|
#[structopt(long = "electrum-rpc",
|
||||||
help = "Provide the Bitcoin Electrum RPC URL",
|
help = "Provide the Bitcoin Electrum RPC URL",
|
||||||
@ -60,7 +67,7 @@ pub enum Command {
|
|||||||
swap_id: Uuid,
|
swap_id: Uuid,
|
||||||
|
|
||||||
#[structopt(flatten)]
|
#[structopt(flatten)]
|
||||||
connect_params: AliceConnectParams,
|
alice_multi_addr: AliceMultiaddress,
|
||||||
|
|
||||||
#[structopt(long = "electrum-rpc",
|
#[structopt(long = "electrum-rpc",
|
||||||
help = "Provide the Bitcoin Electrum RPC URL",
|
help = "Provide the Bitcoin Electrum RPC URL",
|
||||||
@ -108,14 +115,7 @@ pub enum Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(structopt::StructOpt, Debug)]
|
#[derive(structopt::StructOpt, Debug)]
|
||||||
pub struct AliceConnectParams {
|
pub struct AliceMultiaddress {
|
||||||
#[structopt(
|
|
||||||
long = "seller-peer-id",
|
|
||||||
default_value = DEFAULT_ALICE_PEER_ID,
|
|
||||||
help = "The peer id of a specific swap partner can be optionally provided"
|
|
||||||
)]
|
|
||||||
pub peer_id: PeerId,
|
|
||||||
|
|
||||||
#[structopt(
|
#[structopt(
|
||||||
long = "seller-addr",
|
long = "seller-addr",
|
||||||
default_value = DEFAULT_ALICE_MULTIADDR,
|
default_value = DEFAULT_ALICE_MULTIADDR,
|
||||||
|
@ -3,10 +3,12 @@ pub use bob::Bob;
|
|||||||
|
|
||||||
use anyhow::{anyhow, bail, Context, Result};
|
use anyhow::{anyhow, bail, Context, Result};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
use libp2p::PeerId;
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use std::str::FromStr;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
mod alice;
|
mod alice;
|
||||||
@ -63,7 +65,10 @@ impl Swap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Database(sled::Db);
|
pub struct Database {
|
||||||
|
swaps: sled::Tree,
|
||||||
|
peers: sled::Tree,
|
||||||
|
}
|
||||||
|
|
||||||
impl Database {
|
impl Database {
|
||||||
pub fn open(path: &Path) -> Result<Self> {
|
pub fn open(path: &Path) -> Result<Self> {
|
||||||
@ -72,22 +77,51 @@ impl Database {
|
|||||||
let db =
|
let db =
|
||||||
sled::open(path).with_context(|| format!("Could not open the DB at {:?}", path))?;
|
sled::open(path).with_context(|| format!("Could not open the DB at {:?}", path))?;
|
||||||
|
|
||||||
Ok(Database(db))
|
let swaps = db.open_tree("swaps")?;
|
||||||
|
let peers = db.open_tree("peers")?;
|
||||||
|
|
||||||
|
Ok(Database { swaps, peers })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn insert_peer_id(&self, swap_id: Uuid, peer_id: PeerId) -> Result<()> {
|
||||||
|
let peer_id_str = peer_id.to_string();
|
||||||
|
|
||||||
|
let key = serialize(&swap_id)?;
|
||||||
|
let value = serialize(&peer_id_str).context("Could not serialize peer-id")?;
|
||||||
|
|
||||||
|
self.peers.insert(key, value)?;
|
||||||
|
|
||||||
|
self.peers
|
||||||
|
.flush_async()
|
||||||
|
.await
|
||||||
|
.map(|_| ())
|
||||||
|
.context("Could not flush db")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_peer_id(&self, swap_id: Uuid) -> Result<PeerId> {
|
||||||
|
let key = serialize(&swap_id)?;
|
||||||
|
|
||||||
|
let encoded = self
|
||||||
|
.peers
|
||||||
|
.get(&key)?
|
||||||
|
.ok_or_else(|| anyhow!("No peer-id found for swap id {} in database", swap_id))?;
|
||||||
|
|
||||||
|
let peer_id: String = deserialize(&encoded).context("Could not deserialize peer-id")?;
|
||||||
|
Ok(PeerId::from_str(peer_id.as_str())?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn insert_latest_state(&self, swap_id: Uuid, state: Swap) -> Result<()> {
|
pub async fn insert_latest_state(&self, swap_id: Uuid, state: Swap) -> Result<()> {
|
||||||
let key = serialize(&swap_id)?;
|
let key = serialize(&swap_id)?;
|
||||||
let new_value = serialize(&state).context("Could not serialize new state value")?;
|
let new_value = serialize(&state).context("Could not serialize new state value")?;
|
||||||
|
|
||||||
let old_value = self.0.get(&key)?;
|
let old_value = self.swaps.get(&key)?;
|
||||||
|
|
||||||
self.0
|
self.swaps
|
||||||
.compare_and_swap(key, old_value, Some(new_value))
|
.compare_and_swap(key, old_value, Some(new_value))
|
||||||
.context("Could not write in the DB")?
|
.context("Could not write in the DB")?
|
||||||
.context("Stored swap somehow changed, aborting saving")?;
|
.context("Stored swap somehow changed, aborting saving")?;
|
||||||
|
|
||||||
// TODO: see if this can be done through sled config
|
self.swaps
|
||||||
self.0
|
|
||||||
.flush_async()
|
.flush_async()
|
||||||
.await
|
.await
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
@ -98,7 +132,7 @@ impl Database {
|
|||||||
let key = serialize(&swap_id)?;
|
let key = serialize(&swap_id)?;
|
||||||
|
|
||||||
let encoded = self
|
let encoded = self
|
||||||
.0
|
.swaps
|
||||||
.get(&key)?
|
.get(&key)?
|
||||||
.ok_or_else(|| anyhow!("Swap with id {} not found in database", swap_id))?;
|
.ok_or_else(|| anyhow!("Swap with id {} not found in database", swap_id))?;
|
||||||
|
|
||||||
@ -129,7 +163,7 @@ impl Database {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn all_swaps_iter(&self) -> impl Iterator<Item = Result<(Uuid, Swap)>> {
|
fn all_swaps_iter(&self) -> impl Iterator<Item = Result<(Uuid, Swap)>> {
|
||||||
self.0.iter().map(|item| {
|
self.swaps.iter().map(|item| {
|
||||||
let (key, value) = item.context("Failed to retrieve swap from DB")?;
|
let (key, value) = item.context("Failed to retrieve swap from DB")?;
|
||||||
|
|
||||||
let swap_id = deserialize::<Uuid>(&key)?;
|
let swap_id = deserialize::<Uuid>(&key)?;
|
||||||
@ -277,4 +311,52 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(err.downcast_ref::<NotBob>().unwrap(), &NotBob);
|
assert_eq!(err.downcast_ref::<NotBob>().unwrap(), &NotBob);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn can_save_swap_state_and_peer_id_with_same_swap_id() -> Result<()> {
|
||||||
|
let db_dir = tempfile::tempdir().unwrap();
|
||||||
|
let db = Database::open(db_dir.path()).unwrap();
|
||||||
|
|
||||||
|
let alice_id = Uuid::new_v4();
|
||||||
|
let alice_state = Alice::Done(AliceEndState::BtcPunished);
|
||||||
|
let alice_swap = Swap::Alice(alice_state);
|
||||||
|
let peer_id = PeerId::random();
|
||||||
|
|
||||||
|
db.insert_latest_state(alice_id, alice_swap.clone()).await?;
|
||||||
|
db.insert_peer_id(alice_id, peer_id).await?;
|
||||||
|
|
||||||
|
let loaded_swap = db.get_state(alice_id)?;
|
||||||
|
let loaded_peer_id = db.get_peer_id(alice_id)?;
|
||||||
|
|
||||||
|
assert_eq!(alice_swap, loaded_swap);
|
||||||
|
assert_eq!(peer_id, loaded_peer_id);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_reopen_db() -> Result<()> {
|
||||||
|
let db_dir = tempfile::tempdir().unwrap();
|
||||||
|
let alice_id = Uuid::new_v4();
|
||||||
|
let alice_state = Alice::Done(AliceEndState::BtcPunished);
|
||||||
|
let alice_swap = Swap::Alice(alice_state);
|
||||||
|
|
||||||
|
let peer_id = PeerId::random();
|
||||||
|
|
||||||
|
{
|
||||||
|
let db = Database::open(db_dir.path()).unwrap();
|
||||||
|
db.insert_latest_state(alice_id, alice_swap.clone()).await?;
|
||||||
|
db.insert_peer_id(alice_id, peer_id).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let db = Database::open(db_dir.path()).unwrap();
|
||||||
|
|
||||||
|
let loaded_swap = db.get_state(alice_id)?;
|
||||||
|
let loaded_peer_id = db.get_peer_id(alice_id)?;
|
||||||
|
|
||||||
|
assert_eq!(alice_swap, loaded_swap);
|
||||||
|
assert_eq!(peer_id, loaded_peer_id);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user