mirror of
https://github.com/comit-network/xmr-btc-swap.git
synced 2025-01-11 15:39:37 -05:00
Alice's spot_price Behaviour reports back Error
Instead of handling all errors on the inside spot_price errors are bubbled up (as `SwapRequestDeclined`). This allows us to test both Alice's and Bob's behaviour for all scenarios.
This commit is contained in:
parent
5aac76598d
commit
03a0dc73cd
@ -6,11 +6,14 @@ use crate::protocol::alice::{execution_setup, spot_price, State3};
|
||||
use anyhow::{anyhow, Error};
|
||||
use libp2p::request_response::{RequestId, ResponseChannel};
|
||||
use libp2p::{NetworkBehaviour, PeerId};
|
||||
use std::fmt::Debug;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum OutEvent {
|
||||
SwapRequestDeclined {
|
||||
peer: PeerId,
|
||||
error: spot_price::Error,
|
||||
},
|
||||
ExecutionSetupStart {
|
||||
peer: PeerId,
|
||||
btc: bitcoin::Amount,
|
||||
@ -65,7 +68,7 @@ impl OutEvent {
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct Behaviour<LR>
|
||||
where
|
||||
LR: LatestRate + Send + 'static + Debug,
|
||||
LR: LatestRate + Send + 'static,
|
||||
{
|
||||
pub quote: quote::Behaviour,
|
||||
pub spot_price: spot_price::Behaviour<LR>,
|
||||
@ -76,7 +79,7 @@ where
|
||||
|
||||
impl<LR> Behaviour<LR>
|
||||
where
|
||||
LR: LatestRate + Send + 'static + Debug,
|
||||
LR: LatestRate + Send + 'static,
|
||||
{
|
||||
pub fn new(
|
||||
balance: monero::Amount,
|
||||
|
@ -3,6 +3,7 @@ use crate::database::Database;
|
||||
use crate::env::Config;
|
||||
use crate::network::quote::BidQuote;
|
||||
use crate::network::transfer_proof;
|
||||
use crate::protocol::alice::spot_price::Error;
|
||||
use crate::protocol::alice::{AliceState, Behaviour, OutEvent, State0, State3, Swap};
|
||||
use crate::{bitcoin, kraken, monero};
|
||||
use anyhow::{Context, Result};
|
||||
@ -203,6 +204,18 @@ where
|
||||
|
||||
self.swarm.behaviour_mut().execution_setup.run(peer, state0);
|
||||
}
|
||||
SwarmEvent::Behaviour(OutEvent::SwapRequestDeclined { peer, error }) => {
|
||||
match error {
|
||||
Error::ResumeOnlyMode | Error::MaxBuyAmountExceeded { .. } => {
|
||||
tracing::warn!(%peer, "Ignoring spot price request because: {}", error);
|
||||
}
|
||||
Error::BalanceTooLow { .. }
|
||||
| Error::LatestRateFetchFailed(_)
|
||||
| Error::SellQuoteCalculationFailed(_) => {
|
||||
tracing::error!(%peer, "Ignoring spot price request because: {}", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
SwarmEvent::Behaviour(OutEvent::QuoteRequested { channel, peer }) => {
|
||||
// TODO: Move the spot-price update into dedicated update stream to decouple it from quote requests
|
||||
let current_balance = self.monero_wallet.get_balance().await;
|
||||
|
@ -14,10 +14,16 @@ use std::collections::VecDeque;
|
||||
use std::fmt::Debug;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
pub struct OutEvent {
|
||||
peer: PeerId,
|
||||
btc: bitcoin::Amount,
|
||||
xmr: monero::Amount,
|
||||
pub enum OutEvent {
|
||||
ExecutionSetupParams {
|
||||
peer: PeerId,
|
||||
btc: bitcoin::Amount,
|
||||
xmr: monero::Amount,
|
||||
},
|
||||
Error {
|
||||
peer: PeerId,
|
||||
error: Error,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(NetworkBehaviour)]
|
||||
@ -25,7 +31,7 @@ pub struct OutEvent {
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct Behaviour<LR>
|
||||
where
|
||||
LR: LatestRate + Send + 'static + Debug,
|
||||
LR: LatestRate + Send + 'static,
|
||||
{
|
||||
behaviour: spot_price::Behaviour,
|
||||
|
||||
@ -50,7 +56,7 @@ where
|
||||
/// bubbled up to the parent behaviour.
|
||||
impl<LR> Behaviour<LR>
|
||||
where
|
||||
LR: LatestRate + Send + 'static + Debug,
|
||||
LR: LatestRate + Send + 'static,
|
||||
{
|
||||
pub fn new(
|
||||
balance: monero::Amount,
|
||||
@ -78,30 +84,24 @@ where
|
||||
self.balance = balance;
|
||||
}
|
||||
|
||||
fn send_error_response(
|
||||
fn decline(
|
||||
&mut self,
|
||||
peer: PeerId,
|
||||
channel: ResponseChannel<spot_price::Response>,
|
||||
error: Error<LR>,
|
||||
error: Error,
|
||||
) {
|
||||
match error {
|
||||
Error::ResumeOnlyMode | Error::MaxBuyAmountExceeded { .. } => {
|
||||
tracing::warn!(%peer, "Ignoring spot price request because: {}", error);
|
||||
}
|
||||
Error::BalanceTooLow { .. }
|
||||
| Error::LatestRateFetchFailed(_)
|
||||
| Error::SellQuoteCalculationFailed(_) => {
|
||||
tracing::error!(%peer, "Ignoring spot price request because: {}", error);
|
||||
}
|
||||
}
|
||||
|
||||
if self
|
||||
.behaviour
|
||||
.send_response(channel, spot_price::Response::Error(error.into()))
|
||||
.send_response(
|
||||
channel,
|
||||
spot_price::Response::Error(error.to_error_response()),
|
||||
)
|
||||
.is_err()
|
||||
{
|
||||
tracing::debug!(%peer, "Unable to send error response for spot price request");
|
||||
}
|
||||
|
||||
self.events.push_back(OutEvent::Error { peer, error });
|
||||
}
|
||||
|
||||
fn poll<BIE>(
|
||||
@ -120,7 +120,7 @@ where
|
||||
|
||||
impl<LR> NetworkBehaviourEventProcess<spot_price::OutEvent> for Behaviour<LR>
|
||||
where
|
||||
LR: LatestRate + Send + 'static + Debug,
|
||||
LR: LatestRate + Send + 'static,
|
||||
{
|
||||
fn inject_event(&mut self, event: spot_price::OutEvent) {
|
||||
let (peer, message) = match event {
|
||||
@ -150,13 +150,13 @@ where
|
||||
};
|
||||
|
||||
if self.resume_only {
|
||||
self.send_error_response(peer, channel, Error::ResumeOnlyMode);
|
||||
self.decline(peer, channel, Error::ResumeOnlyMode);
|
||||
return;
|
||||
}
|
||||
|
||||
let btc = request.btc;
|
||||
if btc > self.max_buy {
|
||||
self.send_error_response(peer, channel, Error::MaxBuyAmountExceeded {
|
||||
self.decline(peer, channel, Error::MaxBuyAmountExceeded {
|
||||
max: self.max_buy,
|
||||
buy: btc,
|
||||
});
|
||||
@ -166,14 +166,14 @@ where
|
||||
let rate = match self.latest_rate.latest_rate() {
|
||||
Ok(rate) => rate,
|
||||
Err(e) => {
|
||||
self.send_error_response(peer, channel, Error::LatestRateFetchFailed(e));
|
||||
self.decline(peer, channel, Error::LatestRateFetchFailed(Box::new(e)));
|
||||
return;
|
||||
}
|
||||
};
|
||||
let xmr = match rate.sell_quote(btc) {
|
||||
Ok(xmr) => xmr,
|
||||
Err(e) => {
|
||||
self.send_error_response(peer, channel, Error::SellQuoteCalculationFailed(e));
|
||||
self.decline(peer, channel, Error::SellQuoteCalculationFailed(e));
|
||||
return;
|
||||
}
|
||||
};
|
||||
@ -182,7 +182,7 @@ where
|
||||
let xmr_lock_fees = self.lock_fee;
|
||||
|
||||
if xmr_balance < xmr + xmr_lock_fees {
|
||||
self.send_error_response(peer, channel, Error::BalanceTooLow { buy: btc });
|
||||
self.decline(peer, channel, Error::BalanceTooLow { buy: btc });
|
||||
return;
|
||||
}
|
||||
|
||||
@ -194,43 +194,24 @@ where
|
||||
tracing::error!(%peer, "Failed to send spot price response of {} for {}", xmr, btc)
|
||||
}
|
||||
|
||||
self.events.push_back(OutEvent { peer, btc, xmr });
|
||||
self.events
|
||||
.push_back(OutEvent::ExecutionSetupParams { peer, btc, xmr });
|
||||
}
|
||||
}
|
||||
|
||||
impl From<OutEvent> for alice::OutEvent {
|
||||
fn from(event: OutEvent) -> Self {
|
||||
Self::ExecutionSetupStart {
|
||||
peer: event.peer,
|
||||
btc: event.btc,
|
||||
xmr: event.xmr,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<LR> From<Error<LR>> for spot_price::Error
|
||||
where
|
||||
LR: LatestRate + Debug,
|
||||
{
|
||||
fn from(error: Error<LR>) -> Self {
|
||||
match error {
|
||||
Error::ResumeOnlyMode => spot_price::Error::NoSwapsAccepted,
|
||||
Error::MaxBuyAmountExceeded { max, buy } => {
|
||||
spot_price::Error::MaxBuyAmountExceeded { max, buy }
|
||||
}
|
||||
Error::BalanceTooLow { buy } => spot_price::Error::BalanceTooLow { buy },
|
||||
Error::LatestRateFetchFailed(_) | Error::SellQuoteCalculationFailed(_) => {
|
||||
spot_price::Error::Other
|
||||
match event {
|
||||
OutEvent::ExecutionSetupParams { peer, btc, xmr } => {
|
||||
Self::ExecutionSetupStart { peer, btc, xmr }
|
||||
}
|
||||
OutEvent::Error { peer, error } => Self::SwapRequestDeclined { peer, error },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error<LR>
|
||||
where
|
||||
LR: LatestRate + Debug,
|
||||
{
|
||||
pub enum Error {
|
||||
#[error("ASB is running in resume-only mode")]
|
||||
ResumeOnlyMode,
|
||||
#[error("Maximum buy {max} exceeded {buy}")]
|
||||
@ -242,8 +223,24 @@ where
|
||||
BalanceTooLow { buy: bitcoin::Amount },
|
||||
|
||||
#[error("Failed to fetch latest rate")]
|
||||
LatestRateFetchFailed(LR::Error),
|
||||
LatestRateFetchFailed(#[source] Box<dyn std::error::Error + Send + 'static>),
|
||||
|
||||
#[error("Failed to calculate quote: {0}")]
|
||||
SellQuoteCalculationFailed(anyhow::Error),
|
||||
SellQuoteCalculationFailed(#[source] anyhow::Error),
|
||||
}
|
||||
|
||||
impl Error {
|
||||
pub fn to_error_response(&self) -> spot_price::Error {
|
||||
match self {
|
||||
Error::ResumeOnlyMode => spot_price::Error::NoSwapsAccepted,
|
||||
Error::MaxBuyAmountExceeded { max, buy } => spot_price::Error::MaxBuyAmountExceeded {
|
||||
max: *max,
|
||||
buy: *buy,
|
||||
},
|
||||
Error::BalanceTooLow { buy } => spot_price::Error::BalanceTooLow { buy: *buy },
|
||||
Error::LatestRateFetchFailed(_) | Error::SellQuoteCalculationFailed(_) => {
|
||||
spot_price::Error::Other
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user