Add resume-only mode for the ASB

Resume-only is a maintenance mode where no swaps are accepted but unfinished swaps are resumed.
This is achieve by ignoring incoming spot-price requests (that would lead to execution setup) in the event-loop.
pull/461/head
Daniel Karzel 3 years ago
parent 08d7d587cf
commit f6497778ed
No known key found for this signature in database
GPG Key ID: 30C3FC2E438ADB6E

@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Added
- Resume-only mode for the ASB.
When started with `--resume-only` the ASB does not accept new, incoming swap requests but only finishes swaps that are resumed upon startup.
### Fixed
- An issue where both the ASB and the CLI point to the same default directory `xmr-btc-swap` for storing data.

@ -34,6 +34,12 @@ pub enum Command {
default_value = "0.02"
)]
ask_spread: Decimal,
#[structopt(
long = "resume-only",
help = "For maintenance only. When set, no new swap requests will be accepted, but existing unfinished swaps will be resumed."
)]
resume_only: bool,
},
History,
WithdrawBtc {

@ -81,6 +81,7 @@ async fn main() -> Result<()> {
Command::Start {
max_buy,
ask_spread,
resume_only,
} => {
let bitcoin_wallet = init_bitcoin_wallet(&config, &seed, env_config).await?;
let monero_wallet = init_monero_wallet(&config, env_config).await?;
@ -133,6 +134,7 @@ async fn main() -> Result<()> {
Arc::new(db),
KrakenRate::new(ask_spread, kraken_price_updates),
max_buy,
resume_only,
)
.unwrap();

@ -41,7 +41,16 @@ pub struct Request {
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Response {
pub xmr: monero::Amount,
pub xmr: Option<monero::Amount>,
pub error: Option<Error>,
}
#[derive(Clone, Debug, thiserror::Error, Serialize, Deserialize)]
pub enum Error {
#[error(
"This seller currently does not accept incoming swap requests, please try again later"
)]
MaintenanceMode,
}
/// Constructs a new instance of the `spot-price` behaviour to be used by Alice.

@ -42,6 +42,7 @@ pub struct EventLoop<RS> {
max_buy: bitcoin::Amount,
swap_sender: mpsc::Sender<Swap>,
resume_only: bool,
/// Stores incoming [`EncryptedSignature`]s per swap.
recv_encrypted_signature: HashMap<Uuid, bmrng::RequestSender<bitcoin::EncryptedSignature, ()>>,
@ -62,6 +63,7 @@ impl<LR> EventLoop<LR>
where
LR: LatestRate,
{
#[allow(clippy::too_many_arguments)]
pub fn new(
swarm: Swarm<Behaviour>,
env_config: Config,
@ -70,6 +72,7 @@ where
db: Arc<Database>,
latest_rate: LR,
max_buy: bitcoin::Amount,
resume_only: bool,
) -> Result<(Self, mpsc::Receiver<Swap>)> {
let swap_channel = MpscChannels::default();
@ -81,6 +84,7 @@ where
db,
latest_rate,
swap_sender: swap_channel.sender,
resume_only,
max_buy,
recv_encrypted_signature: Default::default(),
inflight_encrypted_signatures: Default::default(),
@ -144,6 +148,20 @@ where
swarm_event = self.swarm.next_event() => {
match swarm_event {
SwarmEvent::Behaviour(OutEvent::SpotPriceRequested { request, channel, peer }) => {
if self.resume_only {
tracing::warn!(%peer, "Ignoring spot price request from {} because ASB started in resume-only mode", peer);
match self.swarm.behaviour_mut().spot_price.send_response(channel, spot_price::Response { xmr: None, error: Some(spot_price::Error::MaintenanceMode) }) {
Ok(_) => {},
Err(_) => {
tracing::debug!(%peer, "Failed to respond with error to spot price request");
continue;
}
}
continue;
}
let btc = request.btc;
let xmr = match self.handle_spot_price_request(btc, self.monero_wallet.clone()).await {
Ok(xmr) => xmr,
@ -153,7 +171,7 @@ where
}
};
match self.swarm.behaviour_mut().spot_price.send_response(channel, spot_price::Response { xmr }) {
match self.swarm.behaviour_mut().spot_price.send_response(channel, spot_price::Response { xmr: Some(xmr), error: None }) {
Ok(_) => {},
Err(_) => {
// if we can't respond, the peer probably just disconnected so it is not a huge deal, only log this on debug

@ -3,7 +3,7 @@ use crate::network::quote::BidQuote;
use crate::network::{encrypted_signature, spot_price};
use crate::protocol::bob::{Behaviour, OutEvent, State0, State2};
use crate::{bitcoin, monero};
use anyhow::{Context, Result};
use anyhow::{bail, Context, Result};
use futures::future::{BoxFuture, OptionFuture};
use futures::{FutureExt, StreamExt};
use libp2p::request_response::{RequestId, ResponseChannel};
@ -261,11 +261,22 @@ impl EventLoopHandle {
}
pub async fn request_spot_price(&mut self, btc: bitcoin::Amount) -> Result<monero::Amount> {
Ok(self
let response = self
.spot_price
.send_receive(spot_price::Request { btc })
.await?
.xmr)
.await?;
match (response.xmr, response.error) {
(Some(xmr), None) => Ok(xmr),
(_, Some(error)) => {
bail!(error);
}
(None, None) => {
bail!(
"Unexpected response for spot-price request, neither price nor error received"
);
}
}
}
pub async fn request_quote(&mut self) -> Result<BidQuote> {

@ -234,6 +234,7 @@ fn start_alice(
db,
FixedRate::default(),
bitcoin::Amount::ONE_BTC,
false,
)
.unwrap();

Loading…
Cancel
Save