582: Asb price guarantees r=da-kami a=da-kami

Fixes #557 

Tested on test-/stagenet setup with Raspi.
The change log entry in the last commit sums up the changes. 


Co-authored-by: Daniel Karzel <daniel@comit.network>
This commit is contained in:
bors[bot] 2021-06-23 08:17:20 +00:00 committed by GitHub
commit c1a54a4024
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 66 additions and 7 deletions

View File

@ -12,6 +12,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Printing the deposit address to the terminal as a QR code.
To not break automated scripts or integrations with other software, this behaviour is disabled if `--json` is passed to the application.
### Fixed
- An issue where the ASB gives long price guarantees when setting up a swap.
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.
### Removed
- The websocket transport from the CLI.

View File

@ -15,6 +15,9 @@ pub enum Alice {
Started {
state3: alice::State3,
},
BtcLockTransactionSeen {
state3: alice::State3,
},
BtcLocked {
state3: alice::State3,
},
@ -81,6 +84,9 @@ impl From<&AliceState> for Alice {
AliceState::Started { state3 } => Alice::Started {
state3: state3.as_ref().clone(),
},
AliceState::BtcLockTransactionSeen { state3 } => Alice::BtcLockTransactionSeen {
state3: state3.as_ref().clone(),
},
AliceState::BtcLocked { state3 } => Alice::BtcLocked {
state3: state3.as_ref().clone(),
},
@ -179,6 +185,9 @@ impl From<Alice> for AliceState {
Alice::Started { state3 } => AliceState::Started {
state3: Box::new(state3),
},
Alice::BtcLockTransactionSeen { state3 } => AliceState::BtcLockTransactionSeen {
state3: Box::new(state3),
},
Alice::BtcLocked { state3 } => AliceState::BtcLocked {
state3: Box::new(state3),
},
@ -278,6 +287,9 @@ impl fmt::Display for Alice {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Alice::Started { .. } => write!(f, "Started"),
Alice::BtcLockTransactionSeen { .. } => {
write!(f, "Bitcoin lock transaction in mempool")
}
Alice::BtcLocked { .. } => f.write_str("Bitcoin locked"),
Alice::XmrLockTransactionSent { .. } => f.write_str("Monero lock transaction sent"),
Alice::XmrLocked { .. } => f.write_str("Monero locked"),

View File

@ -6,6 +6,7 @@ use time::NumericalStdDurationShort;
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Config {
pub bitcoin_lock_mempool_timeout: Duration,
pub bitcoin_lock_confirmed_timeout: Duration,
pub bitcoin_finality_confirmations: u32,
pub bitcoin_avg_block_time: Duration,
@ -43,7 +44,8 @@ pub struct Regtest;
impl GetConfig for Mainnet {
fn get_config() -> Config {
Config {
bitcoin_lock_confirmed_timeout: 24.hours(),
bitcoin_lock_mempool_timeout: 3.minutes(),
bitcoin_lock_confirmed_timeout: 2.hours(),
bitcoin_finality_confirmations: 2,
bitcoin_avg_block_time: 10.minutes(),
bitcoin_cancel_timelock: CancelTimelock::new(72),
@ -59,7 +61,8 @@ impl GetConfig for Mainnet {
impl GetConfig for Testnet {
fn get_config() -> Config {
Config {
bitcoin_lock_confirmed_timeout: 12.hours(),
bitcoin_lock_mempool_timeout: 3.minutes(),
bitcoin_lock_confirmed_timeout: 1.hours(),
bitcoin_finality_confirmations: 2,
bitcoin_avg_block_time: 10.minutes(),
bitcoin_cancel_timelock: CancelTimelock::new(12),
@ -75,6 +78,7 @@ impl GetConfig for Testnet {
impl GetConfig for Regtest {
fn get_config() -> Config {
Config {
bitcoin_lock_mempool_timeout: 30.seconds(),
bitcoin_lock_confirmed_timeout: 1.minutes(),
bitcoin_finality_confirmations: 1,
bitcoin_avg_block_time: 5.seconds(),

View File

@ -4,6 +4,7 @@ use crate::protocol::{alice, Message0, Message2, Message4};
use anyhow::{Context, Error};
use libp2p::PeerId;
use libp2p_async_await::BehaviourOutEvent;
use std::time::Duration;
use uuid::Uuid;
#[derive(Debug)]
@ -49,8 +50,8 @@ impl Default for Behaviour {
impl Behaviour {
pub fn run(&mut self, bob: PeerId, state0: State0) {
self.inner
.do_protocol_listener(bob, move |mut substream| async move {
self.inner.do_protocol_listener(bob, move |mut substream| {
let protocol = async move {
let message0 =
serde_cbor::from_slice::<Message0>(&substream.read_message(BUF_SIZE).await?)
.context("Failed to deserialize message0")?;
@ -83,7 +84,10 @@ impl Behaviour {
let state3 = state2.receive(message4)?;
Ok((bob, (swap_id, state3)))
})
};
async move { tokio::time::timeout(Duration::from_secs(60), protocol).await? }
});
}
}

View File

@ -23,6 +23,7 @@ pub async fn cancel(
// In case no XMR has been locked, move to Safely Aborted
AliceState::Started { .. }
| AliceState::BtcLockTransactionSeen { .. }
| AliceState::BtcLocked { .. } => bail!("Cannot cancel swap {} because it is in state {} where no XMR was locked.", swap_id, state),
AliceState::XmrLockTransactionSent { monero_wallet_restore_blockheight, transfer_proof, state3, }

View File

@ -36,7 +36,8 @@ pub async fn punish(
AliceState::Started { .. } => bail!(Error::NoBtcLocked(state)),
// Punish potentially possible (no knowledge of cancel transaction)
AliceState::BtcLocked { state3, .. }
AliceState::BtcLockTransactionSeen { state3 }
| AliceState::BtcLocked { state3, .. }
| AliceState::XmrLockTransactionSent {state3, ..}
| AliceState::XmrLocked {state3, ..}
| AliceState::XmrLockTransferProofSent {state3, ..}

View File

@ -84,6 +84,7 @@ pub async fn redeem(
Ok((txid, state))
}
AliceState::Started { .. }
| AliceState::BtcLockTransactionSeen { .. }
| AliceState::BtcLocked { .. }
| AliceState::XmrLockTransactionSent { .. }
| AliceState::XmrLocked { .. }

View File

@ -39,6 +39,7 @@ pub async fn refund(
// In case no XMR has been locked, move to Safely Aborted
AliceState::Started { .. }
| AliceState::BtcLockTransactionSeen { .. }
| AliceState::BtcLocked { .. } => bail!(Error::NoXmrLocked(state)),
// Refund potentially possible (no knowledge of cancel transaction)

View File

@ -8,7 +8,9 @@ pub async fn safely_abort(swap_id: Uuid, db: Arc<Database>) -> Result<AliceState
let state = db.get_state(swap_id)?.try_into_alice()?.into();
match state {
AliceState::Started { .. } | AliceState::BtcLocked { .. } => {
AliceState::Started { .. }
| AliceState::BtcLockTransactionSeen { .. }
| AliceState::BtcLocked { .. } => {
let state = AliceState::SafelyAborted;
let db_state = (&state).into();

View File

@ -21,6 +21,9 @@ pub enum AliceState {
Started {
state3: Box<State3>,
},
BtcLockTransactionSeen {
state3: Box<State3>,
},
BtcLocked {
state3: Box<State3>,
},
@ -79,6 +82,9 @@ impl fmt::Display for AliceState {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
AliceState::Started { .. } => write!(f, "started"),
AliceState::BtcLockTransactionSeen { .. } => {
write!(f, "bitcoin lock transaction in mempool")
}
AliceState::BtcLocked { .. } => write!(f, "btc is locked"),
AliceState::XmrLockTransactionSent { .. } => write!(f, "xmr lock transaction sent"),
AliceState::XmrLocked { .. } => write!(f, "xmr is locked"),

View File

@ -70,6 +70,27 @@ where
Ok(match state {
AliceState::Started { state3 } => {
let tx_lock_status = bitcoin_wallet.subscribe_to(state3.tx_lock.clone()).await;
match timeout(
env_config.bitcoin_lock_mempool_timeout,
tx_lock_status.wait_until_seen(),
)
.await
{
Err(_) => {
info!(
minutes = %env_config.bitcoin_lock_mempool_timeout.as_secs_f64() / 60.0,
"TxLock lock was not seen in mempool in time",
);
AliceState::SafelyAborted
}
Ok(res) => {
res?;
AliceState::BtcLockTransactionSeen { state3 }
}
}
}
AliceState::BtcLockTransactionSeen { state3 } => {
let tx_lock_status = bitcoin_wallet.subscribe_to(state3.tx_lock.clone()).await;
match timeout(
env_config.bitcoin_lock_confirmed_timeout,