mirror of
https://github.com/comit-network/xmr-btc-swap.git
synced 2025-01-12 07:59:33 -05:00
Merge #243
243: Some cleanup + improve logging of the `swap_cli` r=thomaseizinger a=thomaseizinger Please see commit messages for details. I've also included a few minor cleanups that I noticed on the way. Co-authored-by: Thomas Eizinger <thomas@eizinger.io>
This commit is contained in:
commit
8bc918c511
24
Cargo.lock
generated
24
Cargo.lock
generated
@ -302,6 +302,12 @@ version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdcf67bb7ba7797a081cd19009948ab533af7c355d5caf1d08c777582d351e9c"
|
||||
|
||||
[[package]]
|
||||
name = "big-bytes"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d73a8ae8ce52d09395e4cafc83b5b81c3deb70a97740e907669c8683c4dd50a"
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.1"
|
||||
@ -560,6 +566,18 @@ dependencies = [
|
||||
"zeroize 1.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.33.3"
|
||||
@ -3525,6 +3543,7 @@ dependencies = [
|
||||
"backoff",
|
||||
"base64 0.12.3",
|
||||
"bdk",
|
||||
"big-bytes",
|
||||
"bitcoin",
|
||||
"bitcoin-harness",
|
||||
"config",
|
||||
@ -3943,11 +3962,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tracing-subscriber"
|
||||
version = "0.2.15"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1fa8f0c8f4c594e4fc9debc1990deab13238077271ba84dd853d54902ee3401"
|
||||
checksum = "8ab8966ac3ca27126141f7999361cc97dd6fb4b71da04c02044fa9045d98bb96"
|
||||
dependencies = [
|
||||
"ansi_term 0.12.1",
|
||||
"chrono",
|
||||
"lazy_static",
|
||||
"matchers",
|
||||
"regex",
|
||||
|
@ -20,6 +20,7 @@ atty = "0.2"
|
||||
backoff = { version = "0.3", features = ["tokio"] }
|
||||
base64 = "0.12"
|
||||
bdk = { version = "0.4" }
|
||||
big-bytes = "1"
|
||||
bitcoin = { version = "0.26", features = ["rand", "use-serde"] }
|
||||
config = { version = "0.10", default-features = false, features = ["toml"] }
|
||||
conquer-once = "0.3"
|
||||
@ -57,7 +58,7 @@ toml = "0.5"
|
||||
tracing = { version = "0.1", features = ["attributes"] }
|
||||
tracing-futures = { version = "0.2", features = ["std-future", "futures-03"] }
|
||||
tracing-log = "0.1"
|
||||
tracing-subscriber = { version = "0.2", default-features = false, features = ["fmt", "ansi", "env-filter"] }
|
||||
tracing-subscriber = { version = "0.2", default-features = false, features = ["fmt", "ansi", "env-filter", "chrono"] }
|
||||
url = { version = "2.1", features = ["serde"] }
|
||||
uuid = { version = "0.8", features = ["serde", "v4"] }
|
||||
void = "1"
|
||||
|
@ -34,10 +34,9 @@ use swap::{
|
||||
bob::{cancel::CancelError, Builder},
|
||||
},
|
||||
seed::Seed,
|
||||
trace::init_tracing,
|
||||
};
|
||||
use tracing::{debug, error, info, warn};
|
||||
use tracing_subscriber::filter::LevelFilter;
|
||||
use tracing::{debug, error, info, warn, Level};
|
||||
use tracing_subscriber::FmtSubscriber;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[macro_use]
|
||||
@ -47,17 +46,41 @@ const MONERO_BLOCKCHAIN_MONITORING_WALLET_NAME: &str = "swap-tool-blockchain-mon
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
init_tracing(LevelFilter::DEBUG).expect("initialize tracing");
|
||||
let args = Arguments::from_args();
|
||||
|
||||
let opt = Arguments::from_args();
|
||||
let is_terminal = atty::is(atty::Stream::Stderr);
|
||||
let base_subscriber = |level| {
|
||||
FmtSubscriber::builder()
|
||||
.with_writer(std::io::stderr)
|
||||
.with_ansi(is_terminal)
|
||||
.with_target(false)
|
||||
.with_env_filter(format!("swap={}", level))
|
||||
};
|
||||
|
||||
let config = match opt.config {
|
||||
if args.debug {
|
||||
let subscriber = base_subscriber(Level::DEBUG)
|
||||
.with_timer(tracing_subscriber::fmt::time::ChronoLocal::with_format(
|
||||
"%F %T".to_owned(),
|
||||
))
|
||||
.finish();
|
||||
|
||||
tracing::subscriber::set_global_default(subscriber)?;
|
||||
} else {
|
||||
let subscriber = base_subscriber(Level::INFO)
|
||||
.without_time()
|
||||
.with_level(false)
|
||||
.finish();
|
||||
|
||||
tracing::subscriber::set_global_default(subscriber)?;
|
||||
}
|
||||
|
||||
let config = match args.config {
|
||||
Some(config_path) => read_config(config_path)??,
|
||||
None => Config::testnet(),
|
||||
};
|
||||
|
||||
info!(
|
||||
"Database and Seed will be stored in directory: {}",
|
||||
debug!(
|
||||
"Database and seed will be stored in {}",
|
||||
config.data.dir.display()
|
||||
);
|
||||
|
||||
@ -79,7 +102,7 @@ async fn main() -> Result<()> {
|
||||
.run(monero_network, "stagenet.community.xmr.to")
|
||||
.await?;
|
||||
|
||||
match opt.cmd.unwrap_or_default() {
|
||||
match args.cmd.unwrap_or_default() {
|
||||
Command::BuyXmr {
|
||||
alice_peer_id,
|
||||
alice_addr,
|
||||
@ -98,8 +121,8 @@ async fn main() -> Result<()> {
|
||||
|
||||
// TODO: Also wait for more funds if balance < dust
|
||||
if bitcoin_wallet.balance().await? == Amount::ZERO {
|
||||
debug!(
|
||||
"Waiting for BTC at address {}",
|
||||
info!(
|
||||
"Please deposit BTC to {}",
|
||||
bitcoin_wallet.new_address().await?
|
||||
);
|
||||
|
||||
@ -110,12 +133,15 @@ async fn main() -> Result<()> {
|
||||
}
|
||||
|
||||
debug!("Received {}", bitcoin_wallet.balance().await?);
|
||||
} else {
|
||||
info!(
|
||||
"Still got {} left in wallet, swapping ...",
|
||||
bitcoin_wallet.balance().await?
|
||||
);
|
||||
}
|
||||
|
||||
let send_bitcoin = bitcoin_wallet.max_giveable(TxLock::script_size()).await?;
|
||||
|
||||
info!("Swapping {} ...", send_bitcoin);
|
||||
|
||||
let bob_factory = Builder::new(
|
||||
seed,
|
||||
db,
|
||||
@ -233,7 +259,7 @@ async fn main() -> Result<()> {
|
||||
cancel_result = cancel => {
|
||||
match cancel_result? {
|
||||
Ok((txid, _)) => {
|
||||
info!("Cancel transaction successfully published with id {}", txid)
|
||||
debug!("Cancel transaction successfully published with id {}", txid)
|
||||
}
|
||||
Err(CancelError::CancelTimelockNotExpiredYet) => error!(
|
||||
"The Cancel Transaction cannot be published yet, \
|
||||
@ -318,13 +344,7 @@ async fn init_wallets(
|
||||
bitcoin_wallet
|
||||
.sync_wallet()
|
||||
.await
|
||||
.expect("Could not sync btc wallet");
|
||||
|
||||
let bitcoin_balance = bitcoin_wallet.balance().await?;
|
||||
info!(
|
||||
"Connection to Bitcoin wallet succeeded, balance: {}",
|
||||
bitcoin_balance
|
||||
);
|
||||
.context("failed to sync balance of bitcoin wallet")?;
|
||||
|
||||
let monero_wallet = monero::Wallet::new(
|
||||
monero_wallet_rpc_url.clone(),
|
||||
@ -346,19 +366,16 @@ async fn init_wallets(
|
||||
monero_wallet_rpc_url
|
||||
))?;
|
||||
|
||||
info!(
|
||||
debug!(
|
||||
"Created Monero wallet for blockchain monitoring with name {}",
|
||||
MONERO_BLOCKCHAIN_MONITORING_WALLET_NAME
|
||||
);
|
||||
} else {
|
||||
info!(
|
||||
"Opened Monero wallet for blockchain monitoring with name {}",
|
||||
MONERO_BLOCKCHAIN_MONITORING_WALLET_NAME
|
||||
);
|
||||
}
|
||||
|
||||
let _test_wallet_connection = monero_wallet.block_height().await?;
|
||||
info!("The Monero wallet RPC is set up correctly!");
|
||||
let _test_wallet_connection = monero_wallet
|
||||
.block_height()
|
||||
.await
|
||||
.context("failed to validate connection to monero-wallet-rpc")?;
|
||||
|
||||
Ok((bitcoin_wallet, monero_wallet))
|
||||
}
|
||||
|
@ -19,13 +19,11 @@ pub use ::bitcoin::{util::amount::Amount, Address, Network, Transaction, Txid};
|
||||
pub use ecdsa_fun::{adaptor::EncryptedSignature, fun::Scalar, Signature};
|
||||
pub use wallet::Wallet;
|
||||
|
||||
use crate::execution_params::ExecutionParams;
|
||||
use ::bitcoin::{
|
||||
hashes::{hex::ToHex, Hash},
|
||||
secp256k1, SigHash,
|
||||
};
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use async_trait::async_trait;
|
||||
use ecdsa_fun::{
|
||||
adaptor::{Adaptor, HashTranscript},
|
||||
fun::Point,
|
||||
@ -201,45 +199,6 @@ pub fn build_shared_output_descriptor(A: Point, B: Point) -> Descriptor<bitcoin:
|
||||
Descriptor::Wsh(Wsh::new(miniscript).expect("a valid descriptor"))
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait SignTxLock {
|
||||
async fn sign_tx_lock(&self, tx_lock: TxLock) -> Result<Transaction>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait BroadcastSignedTransaction {
|
||||
async fn broadcast_signed_transaction(&self, transaction: Transaction) -> Result<Txid>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait WatchForRawTransaction {
|
||||
async fn watch_for_raw_transaction(&self, txid: Txid) -> Result<Transaction>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait WaitForTransactionFinality {
|
||||
async fn wait_for_transaction_finality(
|
||||
&self,
|
||||
txid: Txid,
|
||||
execution_params: ExecutionParams,
|
||||
) -> Result<()>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait GetBlockHeight {
|
||||
async fn get_block_height(&self) -> Result<BlockHeight>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait TransactionBlockHeight {
|
||||
async fn transaction_block_height(&self, txid: Txid) -> Result<BlockHeight>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait GetRawTransaction {
|
||||
async fn get_raw_transaction(&self, txid: Txid) -> Result<Transaction>;
|
||||
}
|
||||
|
||||
pub fn recover(S: PublicKey, sig: Signature, encsig: EncryptedSignature) -> Result<SecretKey> {
|
||||
let adaptor = Adaptor::<HashTranscript<Sha256>, Deterministic<Sha256>>::default();
|
||||
|
||||
@ -251,25 +210,22 @@ pub fn recover(S: PublicKey, sig: Signature, encsig: EncryptedSignature) -> Resu
|
||||
Ok(s)
|
||||
}
|
||||
|
||||
pub async fn poll_until_block_height_is_gte<B>(client: &B, target: BlockHeight) -> Result<()>
|
||||
where
|
||||
B: GetBlockHeight,
|
||||
{
|
||||
pub async fn poll_until_block_height_is_gte(
|
||||
client: &crate::bitcoin::Wallet,
|
||||
target: BlockHeight,
|
||||
) -> Result<()> {
|
||||
while client.get_block_height().await? < target {
|
||||
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn current_epoch<W>(
|
||||
bitcoin_wallet: &W,
|
||||
pub async fn current_epoch(
|
||||
bitcoin_wallet: &crate::bitcoin::Wallet,
|
||||
cancel_timelock: CancelTimelock,
|
||||
punish_timelock: PunishTimelock,
|
||||
lock_tx_id: ::bitcoin::Txid,
|
||||
) -> Result<ExpiredTimelocks>
|
||||
where
|
||||
W: WatchForRawTransaction + TransactionBlockHeight + GetBlockHeight,
|
||||
{
|
||||
) -> Result<ExpiredTimelocks> {
|
||||
let current_block_height = bitcoin_wallet.get_block_height().await?;
|
||||
let lock_tx_height = bitcoin_wallet.transaction_block_height(lock_tx_id).await?;
|
||||
let cancel_timelock_height = lock_tx_height + cancel_timelock;
|
||||
@ -285,14 +241,11 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn wait_for_cancel_timelock_to_expire<W>(
|
||||
bitcoin_wallet: &W,
|
||||
pub async fn wait_for_cancel_timelock_to_expire(
|
||||
bitcoin_wallet: &crate::bitcoin::Wallet,
|
||||
cancel_timelock: CancelTimelock,
|
||||
lock_tx_id: ::bitcoin::Txid,
|
||||
) -> Result<()>
|
||||
where
|
||||
W: WatchForRawTransaction + TransactionBlockHeight + GetBlockHeight,
|
||||
{
|
||||
) -> Result<()> {
|
||||
let tx_lock_height = bitcoin_wallet.transaction_block_height(lock_tx_id).await?;
|
||||
|
||||
poll_until_block_height_is_gte(bitcoin_wallet, tx_lock_height + cancel_timelock).await?;
|
||||
|
@ -1,14 +1,9 @@
|
||||
use crate::{
|
||||
bitcoin::{
|
||||
timelocks::BlockHeight, Address, Amount, BroadcastSignedTransaction, GetBlockHeight,
|
||||
GetRawTransaction, SignTxLock, Transaction, TransactionBlockHeight, TxLock,
|
||||
WaitForTransactionFinality, WatchForRawTransaction,
|
||||
},
|
||||
bitcoin::{timelocks::BlockHeight, Address, Amount, Transaction},
|
||||
execution_params::ExecutionParams,
|
||||
};
|
||||
use ::bitcoin::{util::psbt::PartiallySignedTransaction, Txid};
|
||||
use anyhow::{anyhow, bail, Context, Result};
|
||||
use async_trait::async_trait;
|
||||
use backoff::{backoff::Constant as ConstantBackoff, future::retry};
|
||||
use bdk::{
|
||||
blockchain::{noop_progress, Blockchain, ElectrumBlockchain},
|
||||
@ -152,43 +147,43 @@ impl Wallet {
|
||||
self.inner.lock().await.network()
|
||||
}
|
||||
|
||||
/// Selects an appropriate [`FeeRate`] to be used for getting transactions
|
||||
/// confirmed within a reasonable amount of time.
|
||||
fn select_feerate(&self) -> FeeRate {
|
||||
// TODO: This should obviously not be a const :)
|
||||
FeeRate::from_sat_per_vb(5.0)
|
||||
}
|
||||
}
|
||||
/// Broadcast the given transaction to the network and emit a log statement
|
||||
/// if done so successfully.
|
||||
pub async fn broadcast(&self, transaction: Transaction, kind: &str) -> Result<Txid> {
|
||||
let txid = transaction.txid();
|
||||
|
||||
#[async_trait]
|
||||
impl SignTxLock for Wallet {
|
||||
async fn sign_tx_lock(&self, tx_lock: TxLock) -> Result<Transaction> {
|
||||
let txid = tx_lock.txid();
|
||||
tracing::debug!("signing tx lock: {}", txid);
|
||||
let psbt = PartiallySignedTransaction::from(tx_lock);
|
||||
self.inner
|
||||
.lock()
|
||||
.await
|
||||
.broadcast(transaction)
|
||||
.with_context(|| {
|
||||
format!("failed to broadcast Bitcoin {} transaction {}", kind, txid)
|
||||
})?;
|
||||
|
||||
tracing::info!("Published Bitcoin {} transaction as {}", txid, kind);
|
||||
|
||||
Ok(txid)
|
||||
}
|
||||
|
||||
pub async fn sign_and_finalize(&self, psbt: PartiallySignedTransaction) -> Result<Transaction> {
|
||||
let (signed_psbt, finalized) = self.inner.lock().await.sign(psbt, None)?;
|
||||
|
||||
if !finalized {
|
||||
bail!("Could not finalize TxLock psbt")
|
||||
bail!("PSBT is not finalized")
|
||||
}
|
||||
|
||||
let tx = signed_psbt.extract_tx();
|
||||
tracing::debug!("signed tx lock: {}", txid);
|
||||
|
||||
Ok(tx)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl BroadcastSignedTransaction for Wallet {
|
||||
async fn broadcast_signed_transaction(&self, transaction: Transaction) -> Result<Txid> {
|
||||
tracing::debug!("attempting to broadcast tx: {}", transaction.txid());
|
||||
self.inner.lock().await.broadcast(transaction.clone())?;
|
||||
tracing::info!("Bitcoin tx broadcasted! TXID = {}", transaction.txid());
|
||||
Ok(transaction.txid())
|
||||
pub async fn get_raw_transaction(&self, txid: Txid) -> Result<Transaction> {
|
||||
self.get_tx(txid)
|
||||
.await?
|
||||
.ok_or_else(|| anyhow!("Could not get raw tx with id: {}", txid))
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WatchForRawTransaction for Wallet {
|
||||
async fn watch_for_raw_transaction(&self, txid: Txid) -> Result<Transaction> {
|
||||
pub async fn watch_for_raw_transaction(&self, txid: Txid) -> Result<Transaction> {
|
||||
tracing::debug!("watching for tx: {}", txid);
|
||||
let tx = retry(ConstantBackoff::new(Duration::from_secs(1)), || async {
|
||||
let client = Client::new(self.rpc_url.as_ref())
|
||||
@ -209,20 +204,8 @@ impl WatchForRawTransaction for Wallet {
|
||||
|
||||
Ok(tx)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl GetRawTransaction for Wallet {
|
||||
async fn get_raw_transaction(&self, txid: Txid) -> Result<Transaction> {
|
||||
self.get_tx(txid)
|
||||
.await?
|
||||
.ok_or_else(|| anyhow!("Could not get raw tx with id: {}", txid))
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl GetBlockHeight for Wallet {
|
||||
async fn get_block_height(&self) -> Result<BlockHeight> {
|
||||
pub async fn get_block_height(&self) -> Result<BlockHeight> {
|
||||
let url = blocks_tip_height_url(&self.http_url)?;
|
||||
let height = retry(ConstantBackoff::new(Duration::from_secs(1)), || async {
|
||||
let height = reqwest::Client::new()
|
||||
@ -242,11 +225,8 @@ impl GetBlockHeight for Wallet {
|
||||
|
||||
Ok(BlockHeight::new(height))
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl TransactionBlockHeight for Wallet {
|
||||
async fn transaction_block_height(&self, txid: Txid) -> Result<BlockHeight> {
|
||||
pub async fn transaction_block_height(&self, txid: Txid) -> Result<BlockHeight> {
|
||||
let url = tx_status_url(txid, &self.http_url)?;
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
struct TransactionStatus {
|
||||
@ -276,11 +256,8 @@ impl TransactionBlockHeight for Wallet {
|
||||
|
||||
Ok(BlockHeight::new(height))
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WaitForTransactionFinality for Wallet {
|
||||
async fn wait_for_transaction_finality(
|
||||
pub async fn wait_for_transaction_finality(
|
||||
&self,
|
||||
txid: Txid,
|
||||
execution_params: ExecutionParams,
|
||||
@ -310,6 +287,13 @@ impl WaitForTransactionFinality for Wallet {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Selects an appropriate [`FeeRate`] to be used for getting transactions
|
||||
/// confirmed within a reasonable amount of time.
|
||||
fn select_feerate(&self) -> FeeRate {
|
||||
// TODO: This should obviously not be a const :)
|
||||
FeeRate::from_sat_per_vb(5.0)
|
||||
}
|
||||
}
|
||||
|
||||
fn tx_status_url(txid: Txid, base_url: &Url) -> Result<Url> {
|
||||
|
@ -14,6 +14,9 @@ pub struct Arguments {
|
||||
)]
|
||||
pub config: Option<PathBuf>,
|
||||
|
||||
#[structopt(long, help = "Activate debug logging.")]
|
||||
pub debug: bool,
|
||||
|
||||
#[structopt(subcommand)]
|
||||
pub cmd: Option<Command>,
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ use std::{
|
||||
ffi::OsStr,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
use tracing::info;
|
||||
use tracing::debug;
|
||||
use url::Url;
|
||||
|
||||
pub const DEFAULT_ELECTRUM_HTTP_URL: &str = "https://blockstream.info/testnet/api/";
|
||||
@ -66,7 +66,7 @@ pub struct ConfigNotInitialized {}
|
||||
|
||||
pub fn read_config(config_path: PathBuf) -> Result<Result<Config, ConfigNotInitialized>> {
|
||||
if config_path.exists() {
|
||||
info!(
|
||||
debug!(
|
||||
"Using config file at default path: {}",
|
||||
config_path.display()
|
||||
);
|
||||
|
@ -190,7 +190,7 @@ pub trait Transfer {
|
||||
public_spend_key: PublicKey,
|
||||
public_view_key: PublicViewKey,
|
||||
amount: Amount,
|
||||
) -> Result<(TransferProof, Amount)>;
|
||||
) -> Result<TransferProof>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
|
@ -12,11 +12,7 @@ use monero_rpc::{
|
||||
wallet,
|
||||
wallet::{BlockHeight, Refreshed},
|
||||
};
|
||||
use std::{
|
||||
str::FromStr,
|
||||
sync::{atomic::Ordering, Arc},
|
||||
time::Duration,
|
||||
};
|
||||
use std::{str::FromStr, sync::atomic::Ordering, time::Duration};
|
||||
use tokio::sync::Mutex;
|
||||
use tracing::info;
|
||||
use url::Url;
|
||||
@ -82,7 +78,7 @@ impl Transfer for Wallet {
|
||||
public_spend_key: PublicKey,
|
||||
public_view_key: PublicViewKey,
|
||||
amount: Amount,
|
||||
) -> Result<(TransferProof, Amount)> {
|
||||
) -> Result<TransferProof> {
|
||||
let destination_address =
|
||||
Address::standard(self.network, public_spend_key, public_view_key.into());
|
||||
|
||||
@ -93,16 +89,17 @@ impl Transfer for Wallet {
|
||||
.transfer(0, amount.as_piconero(), &destination_address.to_string())
|
||||
.await?;
|
||||
|
||||
let tx_hash = TxHash(res.tx_hash);
|
||||
tracing::info!("Monero tx broadcasted!, tx hash: {:?}", tx_hash);
|
||||
let tx_key = PrivateKey::from_str(&res.tx_key)?;
|
||||
tracing::debug!(
|
||||
"sent transfer of {} to {} in {}",
|
||||
amount,
|
||||
public_spend_key,
|
||||
res.tx_hash
|
||||
);
|
||||
|
||||
let fee = Amount::from_piconero(res.fee);
|
||||
|
||||
let transfer_proof = TransferProof::new(tx_hash, tx_key);
|
||||
tracing::debug!(" Transfer proof: {:?}", transfer_proof);
|
||||
|
||||
Ok((transfer_proof, fee))
|
||||
Ok(TransferProof::new(
|
||||
TxHash(res.tx_hash),
|
||||
PrivateKey::from_str(&res.tx_key)?,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@ -203,7 +200,7 @@ impl WatchForTransfer for Wallet {
|
||||
|
||||
let address = Address::standard(self.network, public_spend_key, public_view_key.into());
|
||||
|
||||
let confirmations = Arc::new(AtomicU32::new(0u32));
|
||||
let confirmations = AtomicU32::new(0u32);
|
||||
|
||||
let res = retry(ConstantBackoff::new(Duration::from_secs(1)), || async {
|
||||
// NOTE: Currently, this is conflicting IO errors with the transaction not being
|
||||
|
@ -1,8 +1,9 @@
|
||||
use ::monero::Network;
|
||||
use anyhow::{Context, Result};
|
||||
use async_compression::tokio::bufread::BzDecoder;
|
||||
use big_bytes::BigByte;
|
||||
use futures::{StreamExt, TryStreamExt};
|
||||
use reqwest::Url;
|
||||
use reqwest::{header::CONTENT_LENGTH, Url};
|
||||
use std::{
|
||||
io::ErrorKind,
|
||||
path::{Path, PathBuf},
|
||||
@ -71,8 +72,19 @@ impl WalletRpc {
|
||||
.open(monero_wallet_rpc.tar_path())
|
||||
.await?;
|
||||
|
||||
let byte_stream = reqwest::get(DOWNLOAD_URL)
|
||||
.await?
|
||||
let response = reqwest::get(DOWNLOAD_URL).await?;
|
||||
|
||||
let content_length = response.headers()[CONTENT_LENGTH]
|
||||
.to_str()
|
||||
.context("failed to convert content-length to string")?
|
||||
.parse::<u64>()?;
|
||||
|
||||
tracing::info!(
|
||||
"Downloading monero-wallet-rpc ({})",
|
||||
content_length.big_byte(2)
|
||||
);
|
||||
|
||||
let byte_stream = response
|
||||
.bytes_stream()
|
||||
.map_err(|err| std::io::Error::new(ErrorKind::Other, err));
|
||||
|
||||
@ -119,6 +131,8 @@ impl WalletRpc {
|
||||
.local_addr()?
|
||||
.port();
|
||||
|
||||
tracing::debug!("Starting monero-wallet-rpc on port {}", port);
|
||||
|
||||
let mut child = Command::new(self.exec_path())
|
||||
.stdout(Stdio::piped())
|
||||
.kill_on_drop(true)
|
||||
@ -148,6 +162,7 @@ impl WalletRpc {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(WalletRpcProcess {
|
||||
_child: child,
|
||||
port,
|
||||
|
@ -10,7 +10,7 @@ use crate::{
|
||||
};
|
||||
use anyhow::{Error, Result};
|
||||
use libp2p::{request_response::ResponseChannel, NetworkBehaviour, PeerId};
|
||||
use tracing::{debug, info};
|
||||
use tracing::debug;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum OutEvent {
|
||||
@ -121,7 +121,6 @@ impl Behaviour {
|
||||
quote_response: QuoteResponse,
|
||||
) -> Result<()> {
|
||||
self.quote_response.send(channel, quote_response)?;
|
||||
info!("Sent quote response");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -59,7 +59,10 @@ impl From<RequestResponseEvent<QuoteRequest, QuoteResponse>> for OutEvent {
|
||||
RequestResponseEvent::OutboundFailure { error, .. } => {
|
||||
OutEvent::Failure(anyhow!("Outbound failure: {:?}", error))
|
||||
}
|
||||
RequestResponseEvent::ResponseSent { .. } => OutEvent::ResponseSent,
|
||||
RequestResponseEvent::ResponseSent { peer, .. } => {
|
||||
tracing::debug!("successfully sent quote response to {}", peer);
|
||||
OutEvent::ResponseSent
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -82,7 +85,9 @@ impl Behaviour {
|
||||
) -> Result<()> {
|
||||
self.rr
|
||||
.send_response(channel, msg)
|
||||
.map_err(|_| anyhow!("Sending quote response failed"))
|
||||
.map_err(|_| anyhow!("failed to send quote response"))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,8 +2,7 @@ use crate::{
|
||||
bitcoin,
|
||||
bitcoin::{
|
||||
current_epoch, wait_for_cancel_timelock_to_expire, CancelTimelock, ExpiredTimelocks,
|
||||
GetBlockHeight, PunishTimelock, TransactionBlockHeight, TxCancel, TxRefund,
|
||||
WatchForRawTransaction,
|
||||
PunishTimelock, TxCancel, TxRefund,
|
||||
},
|
||||
execution_params::ExecutionParams,
|
||||
monero,
|
||||
@ -325,10 +324,10 @@ pub struct State3 {
|
||||
}
|
||||
|
||||
impl State3 {
|
||||
pub async fn wait_for_cancel_timelock_to_expire<W>(&self, bitcoin_wallet: &W) -> Result<()>
|
||||
where
|
||||
W: WatchForRawTransaction + TransactionBlockHeight + GetBlockHeight,
|
||||
{
|
||||
pub async fn wait_for_cancel_timelock_to_expire(
|
||||
&self,
|
||||
bitcoin_wallet: &bitcoin::Wallet,
|
||||
) -> Result<()> {
|
||||
wait_for_cancel_timelock_to_expire(
|
||||
bitcoin_wallet,
|
||||
self.cancel_timelock,
|
||||
@ -337,10 +336,10 @@ impl State3 {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn expired_timelocks<W>(&self, bitcoin_wallet: &W) -> Result<ExpiredTimelocks>
|
||||
where
|
||||
W: WatchForRawTransaction + TransactionBlockHeight + GetBlockHeight,
|
||||
{
|
||||
pub async fn expired_timelocks(
|
||||
&self,
|
||||
bitcoin_wallet: &bitcoin::Wallet,
|
||||
) -> Result<ExpiredTimelocks> {
|
||||
current_epoch(
|
||||
bitcoin_wallet,
|
||||
self.cancel_timelock,
|
||||
|
@ -1,10 +1,8 @@
|
||||
use crate::{
|
||||
bitcoin,
|
||||
bitcoin::{
|
||||
poll_until_block_height_is_gte, BlockHeight, BroadcastSignedTransaction, CancelTimelock,
|
||||
EncryptedSignature, GetBlockHeight, GetRawTransaction, PunishTimelock,
|
||||
TransactionBlockHeight, TxCancel, TxLock, TxRefund, WaitForTransactionFinality,
|
||||
WatchForRawTransaction,
|
||||
poll_until_block_height_is_gte, BlockHeight, CancelTimelock, EncryptedSignature,
|
||||
PunishTimelock, TxCancel, TxLock, TxRefund,
|
||||
},
|
||||
execution_params::ExecutionParams,
|
||||
monero,
|
||||
@ -27,18 +25,14 @@ use libp2p::PeerId;
|
||||
use sha2::Sha256;
|
||||
use std::sync::Arc;
|
||||
use tokio::time::timeout;
|
||||
use tracing::info;
|
||||
|
||||
// TODO(Franck): Use helper functions from xmr-btc instead of re-writing them
|
||||
// here
|
||||
pub async fn wait_for_locked_bitcoin<W>(
|
||||
pub async fn wait_for_locked_bitcoin(
|
||||
lock_bitcoin_txid: bitcoin::Txid,
|
||||
bitcoin_wallet: Arc<W>,
|
||||
bitcoin_wallet: &bitcoin::Wallet,
|
||||
execution_params: ExecutionParams,
|
||||
) -> Result<()>
|
||||
where
|
||||
W: WatchForRawTransaction + WaitForTransactionFinality,
|
||||
{
|
||||
) -> Result<()> {
|
||||
// We assume we will see Bob's transaction in the mempool first.
|
||||
timeout(
|
||||
execution_params.bob_time_to_act,
|
||||
@ -69,7 +63,7 @@ where
|
||||
let public_spend_key = S_a + state3.S_b_monero;
|
||||
let public_view_key = state3.v.public();
|
||||
|
||||
let (transfer_proof, _) = monero_wallet
|
||||
let transfer_proof = monero_wallet
|
||||
.transfer(public_spend_key, public_view_key, state3.xmr)
|
||||
.await?;
|
||||
|
||||
@ -130,32 +124,14 @@ pub fn build_bitcoin_redeem_transaction(
|
||||
Ok(tx)
|
||||
}
|
||||
|
||||
pub async fn publish_bitcoin_redeem_transaction<W>(
|
||||
redeem_tx: bitcoin::Transaction,
|
||||
bitcoin_wallet: Arc<W>,
|
||||
) -> Result<::bitcoin::Txid>
|
||||
where
|
||||
W: BroadcastSignedTransaction + WaitForTransactionFinality,
|
||||
{
|
||||
info!("Attempting to publish bitcoin redeem txn");
|
||||
let txid = bitcoin_wallet
|
||||
.broadcast_signed_transaction(redeem_tx)
|
||||
.await?;
|
||||
|
||||
Ok(txid)
|
||||
}
|
||||
|
||||
pub async fn publish_cancel_transaction<W>(
|
||||
pub async fn publish_cancel_transaction(
|
||||
tx_lock: TxLock,
|
||||
a: bitcoin::SecretKey,
|
||||
B: bitcoin::PublicKey,
|
||||
cancel_timelock: CancelTimelock,
|
||||
tx_cancel_sig_bob: bitcoin::Signature,
|
||||
bitcoin_wallet: Arc<W>,
|
||||
) -> Result<bitcoin::TxCancel>
|
||||
where
|
||||
W: GetRawTransaction + TransactionBlockHeight + GetBlockHeight + BroadcastSignedTransaction,
|
||||
{
|
||||
bitcoin_wallet: Arc<bitcoin::Wallet>,
|
||||
) -> Result<bitcoin::TxCancel> {
|
||||
// First wait for cancel timelock to expire
|
||||
let tx_lock_height = bitcoin_wallet
|
||||
.transaction_block_height(tx_lock.txid())
|
||||
@ -183,9 +159,7 @@ where
|
||||
.expect("sig_{a,b} to be valid signatures for tx_cancel");
|
||||
|
||||
// TODO(Franck): Error handling is delicate, why can't we broadcast?
|
||||
bitcoin_wallet
|
||||
.broadcast_signed_transaction(tx_cancel)
|
||||
.await?;
|
||||
bitcoin_wallet.broadcast(tx_cancel, "cancel").await?;
|
||||
|
||||
// TODO(Franck): Wait until transaction is mined and returned mined
|
||||
// block height
|
||||
@ -194,18 +168,15 @@ where
|
||||
Ok(tx_cancel)
|
||||
}
|
||||
|
||||
pub async fn wait_for_bitcoin_refund<W>(
|
||||
pub async fn wait_for_bitcoin_refund(
|
||||
tx_cancel: &TxCancel,
|
||||
cancel_tx_height: BlockHeight,
|
||||
punish_timelock: PunishTimelock,
|
||||
refund_address: &bitcoin::Address,
|
||||
bitcoin_wallet: Arc<W>,
|
||||
) -> Result<(bitcoin::TxRefund, Option<bitcoin::Transaction>)>
|
||||
where
|
||||
W: GetBlockHeight + WatchForRawTransaction,
|
||||
{
|
||||
bitcoin_wallet: &bitcoin::Wallet,
|
||||
) -> Result<(bitcoin::TxRefund, Option<bitcoin::Transaction>)> {
|
||||
let punish_timelock_expired =
|
||||
poll_until_block_height_is_gte(bitcoin_wallet.as_ref(), cancel_tx_height + punish_timelock);
|
||||
poll_until_block_height_is_gte(bitcoin_wallet, cancel_tx_height + punish_timelock);
|
||||
|
||||
let tx_refund = bitcoin::TxRefund::new(tx_cancel, refund_address);
|
||||
|
||||
@ -266,22 +237,3 @@ pub fn build_bitcoin_punish_transaction(
|
||||
|
||||
Ok(signed_tx_punish)
|
||||
}
|
||||
|
||||
pub async fn publish_bitcoin_punish_transaction<W>(
|
||||
punish_tx: bitcoin::Transaction,
|
||||
bitcoin_wallet: Arc<W>,
|
||||
execution_params: ExecutionParams,
|
||||
) -> Result<bitcoin::Txid>
|
||||
where
|
||||
W: BroadcastSignedTransaction + WaitForTransactionFinality,
|
||||
{
|
||||
let txid = bitcoin_wallet
|
||||
.broadcast_signed_transaction(punish_tx)
|
||||
.await?;
|
||||
|
||||
bitcoin_wallet
|
||||
.wait_for_transaction_finality(txid, execution_params)
|
||||
.await?;
|
||||
|
||||
Ok(txid)
|
||||
}
|
||||
|
@ -2,10 +2,7 @@
|
||||
//! Alice holds XMR and wishes receive BTC.
|
||||
use crate::{
|
||||
bitcoin,
|
||||
bitcoin::{
|
||||
ExpiredTimelocks, TransactionBlockHeight, WaitForTransactionFinality,
|
||||
WatchForRawTransaction,
|
||||
},
|
||||
bitcoin::ExpiredTimelocks,
|
||||
database,
|
||||
database::Database,
|
||||
execution_params::ExecutionParams,
|
||||
@ -18,8 +15,7 @@ use crate::{
|
||||
event_loop::EventLoopHandle,
|
||||
steps::{
|
||||
build_bitcoin_punish_transaction, build_bitcoin_redeem_transaction,
|
||||
extract_monero_private_key, lock_xmr, publish_bitcoin_punish_transaction,
|
||||
publish_bitcoin_redeem_transaction, publish_cancel_transaction,
|
||||
extract_monero_private_key, lock_xmr, publish_cancel_transaction,
|
||||
wait_for_bitcoin_encrypted_signature, wait_for_bitcoin_refund,
|
||||
wait_for_locked_bitcoin,
|
||||
},
|
||||
@ -98,7 +94,7 @@ async fn run_until_internal(
|
||||
} => {
|
||||
let _ = wait_for_locked_bitcoin(
|
||||
state3.tx_lock.txid(),
|
||||
bitcoin_wallet.clone(),
|
||||
&bitcoin_wallet,
|
||||
execution_params,
|
||||
)
|
||||
.await?;
|
||||
@ -222,37 +218,31 @@ async fn run_until_internal(
|
||||
state3.B,
|
||||
&state3.redeem_address,
|
||||
) {
|
||||
Ok(tx) => {
|
||||
match publish_bitcoin_redeem_transaction(tx, bitcoin_wallet.clone())
|
||||
.await
|
||||
{
|
||||
Ok(txid) => {
|
||||
let publishded_redeem_tx = bitcoin_wallet
|
||||
.wait_for_transaction_finality(txid, execution_params)
|
||||
.await;
|
||||
Ok(tx) => match bitcoin_wallet.broadcast(tx, "redeem").await {
|
||||
Ok(txid) => {
|
||||
let publishded_redeem_tx = bitcoin_wallet
|
||||
.wait_for_transaction_finality(txid, execution_params)
|
||||
.await;
|
||||
|
||||
match publishded_redeem_tx {
|
||||
Ok(_) => AliceState::BtcRedeemed,
|
||||
Err(e) => {
|
||||
bail!("Waiting for Bitcoin transaction finality failed with {}! The redeem transaction was published, but it is not ensured that the transaction was included! You're screwed.", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Publishing the redeem transaction failed with {}, attempting to wait for cancellation now. If you restart the application before the timelock is expired publishing the redeem transaction will be retried.", e);
|
||||
state3
|
||||
.wait_for_cancel_timelock_to_expire(
|
||||
bitcoin_wallet.as_ref(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
AliceState::CancelTimelockExpired {
|
||||
state3,
|
||||
monero_wallet_restore_blockheight,
|
||||
match publishded_redeem_tx {
|
||||
Ok(_) => AliceState::BtcRedeemed,
|
||||
Err(e) => {
|
||||
bail!("Waiting for Bitcoin transaction finality failed with {}! The redeem transaction was published, but it is not ensured that the transaction was included! You're screwed.", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Publishing the redeem transaction failed with {}, attempting to wait for cancellation now. If you restart the application before the timelock is expired publishing the redeem transaction will be retried.", e);
|
||||
state3
|
||||
.wait_for_cancel_timelock_to_expire(bitcoin_wallet.as_ref())
|
||||
.await?;
|
||||
|
||||
AliceState::CancelTimelockExpired {
|
||||
state3,
|
||||
monero_wallet_restore_blockheight,
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
error!("Constructing the redeem transaction failed with {}, attempting to wait for cancellation now.", e);
|
||||
state3
|
||||
@ -335,7 +325,7 @@ async fn run_until_internal(
|
||||
tx_cancel_height,
|
||||
state3.punish_timelock,
|
||||
&state3.refund_address,
|
||||
bitcoin_wallet.clone(),
|
||||
&bitcoin_wallet,
|
||||
)
|
||||
.await?;
|
||||
|
||||
@ -430,11 +420,15 @@ async fn run_until_internal(
|
||||
state3.B,
|
||||
)?;
|
||||
|
||||
let punish_tx_finalised = publish_bitcoin_punish_transaction(
|
||||
signed_tx_punish,
|
||||
bitcoin_wallet.clone(),
|
||||
execution_params,
|
||||
);
|
||||
let punish_tx_finalised = async {
|
||||
let txid = bitcoin_wallet.broadcast(signed_tx_punish, "punish").await?;
|
||||
|
||||
bitcoin_wallet
|
||||
.wait_for_transaction_finality(txid, execution_params)
|
||||
.await?;
|
||||
|
||||
Result::<_, anyhow::Error>::Ok(txid)
|
||||
};
|
||||
|
||||
let refund_tx_seen = bitcoin_wallet.watch_for_raw_transaction(tx_refund.txid());
|
||||
|
||||
|
@ -15,7 +15,7 @@ use crate::{
|
||||
use anyhow::{bail, Error, Result};
|
||||
use libp2p::{core::Multiaddr, identity::Keypair, NetworkBehaviour, PeerId};
|
||||
use std::sync::Arc;
|
||||
use tracing::{debug, info};
|
||||
use tracing::debug;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub use self::{
|
||||
@ -259,8 +259,7 @@ pub struct Behaviour {
|
||||
impl Behaviour {
|
||||
/// Sends a quote request to Alice to retrieve the rate.
|
||||
pub fn send_quote_request(&mut self, alice: PeerId, quote_request: QuoteRequest) {
|
||||
let _id = self.quote_request.send(alice, quote_request);
|
||||
info!("Requesting quote from: {}", alice);
|
||||
let _ = self.quote_request.send(alice, quote_request);
|
||||
}
|
||||
|
||||
pub fn start_execution_setup(
|
||||
@ -271,10 +270,8 @@ impl Behaviour {
|
||||
) {
|
||||
self.execution_setup
|
||||
.run(alice_peer_id, state0, bitcoin_wallet);
|
||||
info!("Start execution setup with {}", alice_peer_id);
|
||||
}
|
||||
|
||||
/// Sends Bob's fourth message to Alice.
|
||||
pub fn send_encrypted_signature(
|
||||
&mut self,
|
||||
alice: PeerId,
|
||||
|
@ -7,12 +7,12 @@ use crate::{
|
||||
bob::{Behaviour, OutEvent, QuoteRequest, State0, State2},
|
||||
},
|
||||
};
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use anyhow::{anyhow, bail, Context, Result};
|
||||
use futures::FutureExt;
|
||||
use libp2p::{core::Multiaddr, PeerId};
|
||||
use std::{convert::Infallible, sync::Arc};
|
||||
use tokio::sync::mpsc::{Receiver, Sender};
|
||||
use tracing::{debug, error, info};
|
||||
use tracing::{debug, error, trace};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Channels<T> {
|
||||
@ -72,7 +72,6 @@ impl EventLoopHandle {
|
||||
/// Dials other party and wait for the connection to be established.
|
||||
/// Do nothing if we are already connected
|
||||
pub async fn dial(&mut self) -> Result<()> {
|
||||
debug!("Attempt to dial Alice");
|
||||
let _ = self.dial_alice.send(()).await?;
|
||||
|
||||
self.conn_established
|
||||
@ -201,15 +200,11 @@ impl EventLoop {
|
||||
if option.is_some() {
|
||||
let peer_id = self.alice_peer_id;
|
||||
if self.swarm.pt.is_connected(&peer_id) {
|
||||
debug!("Already connected to Alice: {}", peer_id);
|
||||
trace!("Already connected to Alice at {}", peer_id);
|
||||
let _ = self.conn_established.send(peer_id).await;
|
||||
} else {
|
||||
info!("dialing alice: {}", peer_id);
|
||||
if let Err(err) = libp2p::Swarm::dial(&mut self.swarm, &peer_id) {
|
||||
error!("Could not dial alice: {}", err);
|
||||
// TODO(Franck): If Dial fails then we should report it.
|
||||
}
|
||||
|
||||
debug!("Dialing alice at {}", peer_id);
|
||||
libp2p::Swarm::dial(&mut self.swarm, &peer_id).context("failed to dial alice")?;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -72,6 +72,8 @@ impl Behaviour {
|
||||
) {
|
||||
self.inner
|
||||
.do_protocol_dialer(alice, move |mut substream| async move {
|
||||
tracing::debug!("Starting execution setup with {}", alice);
|
||||
|
||||
substream
|
||||
.write_message(
|
||||
&serde_cbor::to_vec(&state0.next_message())
|
||||
|
@ -36,6 +36,8 @@ pub struct Behaviour {
|
||||
|
||||
impl Behaviour {
|
||||
pub fn send(&mut self, alice: PeerId, quote_request: QuoteRequest) -> Result<RequestId> {
|
||||
debug!("Requesting quote for {}", quote_request.btc_amount);
|
||||
|
||||
let id = self.rr.send_request(&alice, quote_request);
|
||||
|
||||
Ok(id)
|
||||
@ -67,13 +69,9 @@ impl From<RequestResponseEvent<QuoteRequest, QuoteResponse>> for OutEvent {
|
||||
..
|
||||
} => OutEvent::Failure(anyhow!("Bob should never get a request from Alice")),
|
||||
RequestResponseEvent::Message {
|
||||
peer,
|
||||
message: RequestResponseMessage::Response { response, .. },
|
||||
..
|
||||
} => {
|
||||
debug!("Received quote response from {}", peer);
|
||||
OutEvent::MsgReceived(response)
|
||||
}
|
||||
} => OutEvent::MsgReceived(response),
|
||||
RequestResponseEvent::InboundFailure { error, .. } => {
|
||||
OutEvent::Failure(anyhow!("Inbound failure: {:?}", error))
|
||||
}
|
||||
|
@ -1,8 +1,7 @@
|
||||
use crate::{
|
||||
bitcoin::{
|
||||
self, current_epoch, wait_for_cancel_timelock_to_expire, BroadcastSignedTransaction,
|
||||
CancelTimelock, ExpiredTimelocks, GetBlockHeight, GetRawTransaction, PunishTimelock,
|
||||
Transaction, TransactionBlockHeight, TxCancel, Txid, WatchForRawTransaction,
|
||||
self, current_epoch, wait_for_cancel_timelock_to_expire, CancelTimelock, ExpiredTimelocks,
|
||||
PunishTimelock, Transaction, TxCancel, Txid,
|
||||
},
|
||||
execution_params::ExecutionParams,
|
||||
monero,
|
||||
@ -14,7 +13,7 @@ use crate::{
|
||||
CROSS_CURVE_PROOF_SYSTEM,
|
||||
},
|
||||
};
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use anyhow::{anyhow, bail, Context, Result};
|
||||
use ecdsa_fun::{
|
||||
adaptor::{Adaptor, HashTranscript},
|
||||
nonce::Deterministic,
|
||||
@ -269,16 +268,13 @@ impl State2 {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn lock_btc<W>(self, bitcoin_wallet: &W) -> Result<State3>
|
||||
where
|
||||
W: bitcoin::SignTxLock + bitcoin::BroadcastSignedTransaction,
|
||||
{
|
||||
let signed_tx_lock = bitcoin_wallet.sign_tx_lock(self.tx_lock.clone()).await?;
|
||||
pub async fn lock_btc(self, bitcoin_wallet: &bitcoin::Wallet) -> Result<State3> {
|
||||
let signed_tx = bitcoin_wallet
|
||||
.sign_and_finalize(self.tx_lock.clone().into())
|
||||
.await
|
||||
.context("failed to sign Bitcoin lock transaction")?;
|
||||
|
||||
tracing::info!("{}", self.tx_lock.txid());
|
||||
let _ = bitcoin_wallet
|
||||
.broadcast_signed_transaction(signed_tx_lock)
|
||||
.await?;
|
||||
let _ = bitcoin_wallet.broadcast(signed_tx, "lock").await?;
|
||||
|
||||
Ok(State3 {
|
||||
A: self.A,
|
||||
@ -363,10 +359,10 @@ impl State3 {
|
||||
}))
|
||||
}
|
||||
|
||||
pub async fn wait_for_cancel_timelock_to_expire<W>(&self, bitcoin_wallet: &W) -> Result<()>
|
||||
where
|
||||
W: WatchForRawTransaction + TransactionBlockHeight + GetBlockHeight,
|
||||
{
|
||||
pub async fn wait_for_cancel_timelock_to_expire(
|
||||
&self,
|
||||
bitcoin_wallet: &bitcoin::Wallet,
|
||||
) -> Result<()> {
|
||||
wait_for_cancel_timelock_to_expire(
|
||||
bitcoin_wallet,
|
||||
self.cancel_timelock,
|
||||
@ -399,10 +395,10 @@ impl State3 {
|
||||
self.tx_lock.txid()
|
||||
}
|
||||
|
||||
pub async fn current_epoch<W>(&self, bitcoin_wallet: &W) -> Result<ExpiredTimelocks>
|
||||
where
|
||||
W: WatchForRawTransaction + TransactionBlockHeight + GetBlockHeight,
|
||||
{
|
||||
pub async fn current_epoch(
|
||||
&self,
|
||||
bitcoin_wallet: &bitcoin::Wallet,
|
||||
) -> Result<ExpiredTimelocks> {
|
||||
current_epoch(
|
||||
bitcoin_wallet,
|
||||
self.cancel_timelock,
|
||||
@ -443,10 +439,10 @@ impl State4 {
|
||||
self.b.encsign(self.S_a_bitcoin, tx_redeem.digest())
|
||||
}
|
||||
|
||||
pub async fn check_for_tx_cancel<W>(&self, bitcoin_wallet: &W) -> Result<Transaction>
|
||||
where
|
||||
W: GetRawTransaction,
|
||||
{
|
||||
pub async fn check_for_tx_cancel(
|
||||
&self,
|
||||
bitcoin_wallet: &bitcoin::Wallet,
|
||||
) -> Result<Transaction> {
|
||||
let tx_cancel =
|
||||
bitcoin::TxCancel::new(&self.tx_lock, self.cancel_timelock, self.A, self.b.public());
|
||||
|
||||
@ -466,10 +462,7 @@ impl State4 {
|
||||
Ok(tx)
|
||||
}
|
||||
|
||||
pub async fn submit_tx_cancel<W>(&self, bitcoin_wallet: &W) -> Result<Txid>
|
||||
where
|
||||
W: BroadcastSignedTransaction,
|
||||
{
|
||||
pub async fn submit_tx_cancel(&self, bitcoin_wallet: &bitcoin::Wallet) -> Result<Txid> {
|
||||
let tx_cancel =
|
||||
bitcoin::TxCancel::new(&self.tx_lock, self.cancel_timelock, self.A, self.b.public());
|
||||
|
||||
@ -484,16 +477,12 @@ impl State4 {
|
||||
tx_cancel",
|
||||
);
|
||||
|
||||
let tx_id = bitcoin_wallet
|
||||
.broadcast_signed_transaction(tx_cancel)
|
||||
.await?;
|
||||
let tx_id = bitcoin_wallet.broadcast(tx_cancel, "cancel").await?;
|
||||
|
||||
Ok(tx_id)
|
||||
}
|
||||
|
||||
pub async fn watch_for_redeem_btc<W>(&self, bitcoin_wallet: &W) -> Result<State5>
|
||||
where
|
||||
W: WatchForRawTransaction,
|
||||
{
|
||||
pub async fn watch_for_redeem_btc(&self, bitcoin_wallet: &bitcoin::Wallet) -> Result<State5> {
|
||||
let tx_redeem = bitcoin::TxRedeem::new(&self.tx_lock, &self.redeem_address);
|
||||
let tx_redeem_encsig = self.b.encsign(self.S_a_bitcoin, tx_redeem.digest());
|
||||
|
||||
@ -515,10 +504,10 @@ impl State4 {
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn wait_for_cancel_timelock_to_expire<W>(&self, bitcoin_wallet: &W) -> Result<()>
|
||||
where
|
||||
W: WatchForRawTransaction + TransactionBlockHeight + GetBlockHeight,
|
||||
{
|
||||
pub async fn wait_for_cancel_timelock_to_expire(
|
||||
&self,
|
||||
bitcoin_wallet: &bitcoin::Wallet,
|
||||
) -> Result<()> {
|
||||
wait_for_cancel_timelock_to_expire(
|
||||
bitcoin_wallet,
|
||||
self.cancel_timelock,
|
||||
@ -527,10 +516,10 @@ impl State4 {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn expired_timelock<W>(&self, bitcoin_wallet: &W) -> Result<ExpiredTimelocks>
|
||||
where
|
||||
W: WatchForRawTransaction + TransactionBlockHeight + GetBlockHeight,
|
||||
{
|
||||
pub async fn expired_timelock(
|
||||
&self,
|
||||
bitcoin_wallet: &bitcoin::Wallet,
|
||||
) -> Result<ExpiredTimelocks> {
|
||||
current_epoch(
|
||||
bitcoin_wallet,
|
||||
self.cancel_timelock,
|
||||
@ -540,14 +529,11 @@ impl State4 {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn refund_btc<W>(
|
||||
pub async fn refund_btc(
|
||||
&self,
|
||||
bitcoin_wallet: &W,
|
||||
bitcoin_wallet: &bitcoin::Wallet,
|
||||
execution_params: ExecutionParams,
|
||||
) -> Result<()>
|
||||
where
|
||||
W: bitcoin::BroadcastSignedTransaction + bitcoin::WaitForTransactionFinality,
|
||||
{
|
||||
) -> Result<()> {
|
||||
let tx_cancel =
|
||||
bitcoin::TxCancel::new(&self.tx_lock, self.cancel_timelock, self.A, self.b.public());
|
||||
let tx_refund = bitcoin::TxRefund::new(&tx_cancel, &self.refund_address);
|
||||
@ -561,9 +547,7 @@ impl State4 {
|
||||
let signed_tx_refund =
|
||||
tx_refund.add_signatures((self.A, sig_a), (self.b.public(), sig_b))?;
|
||||
|
||||
let txid = bitcoin_wallet
|
||||
.broadcast_signed_transaction(signed_tx_refund)
|
||||
.await?;
|
||||
let txid = bitcoin_wallet.broadcast(signed_tx_refund, "refund").await?;
|
||||
|
||||
bitcoin_wallet
|
||||
.wait_for_transaction_finality(txid, execution_params)
|
||||
|
@ -12,7 +12,7 @@ use async_recursion::async_recursion;
|
||||
use rand::rngs::OsRng;
|
||||
use std::sync::Arc;
|
||||
use tokio::select;
|
||||
use tracing::info;
|
||||
use tracing::{trace, warn};
|
||||
use uuid::Uuid;
|
||||
|
||||
pub fn is_complete(state: &BobState) -> bool {
|
||||
@ -30,7 +30,6 @@ pub async fn run(swap: bob::Swap) -> Result<BobState> {
|
||||
run_until(swap, is_complete).await
|
||||
}
|
||||
|
||||
#[tracing::instrument(name = "swap", skip(swap,is_target_state), fields(id = %swap.swap_id))]
|
||||
pub async fn run_until(
|
||||
swap: bob::Swap,
|
||||
is_target_state: fn(&BobState) -> bool,
|
||||
@ -61,7 +60,7 @@ async fn run_until_internal(
|
||||
swap_id: Uuid,
|
||||
execution_params: ExecutionParams,
|
||||
) -> Result<BobState> {
|
||||
info!("Current state: {}", state);
|
||||
trace!("Current state: {}", state);
|
||||
if is_target_state(&state) {
|
||||
Ok(state)
|
||||
} else {
|
||||
@ -186,7 +185,7 @@ async fn run_until_internal(
|
||||
match state4? {
|
||||
Ok(state4) => BobState::XmrLocked(state4),
|
||||
Err(InsufficientFunds {..}) => {
|
||||
info!("The other party has locked insufficient Monero funds! Waiting for refund...");
|
||||
warn!("The other party has locked insufficient Monero funds! Waiting for refund...");
|
||||
state.wait_for_cancel_timelock_to_expire(bitcoin_wallet.as_ref()).await?;
|
||||
let state4 = state.cancel();
|
||||
BobState::CancelTimelockExpired(state4)
|
||||
@ -389,12 +388,14 @@ pub async fn request_quote_and_setup(
|
||||
.send_quote_request(QuoteRequest { btc_amount })
|
||||
.await?;
|
||||
|
||||
let quote_response = event_loop_handle.recv_quote_response().await?;
|
||||
let xmr_amount = event_loop_handle.recv_quote_response().await?.xmr_amount;
|
||||
|
||||
tracing::info!("Quote for {} is {}", btc_amount, xmr_amount);
|
||||
|
||||
let state0 = State0::new(
|
||||
&mut OsRng,
|
||||
btc_amount,
|
||||
quote_response.xmr_amount,
|
||||
xmr_amount,
|
||||
execution_params.bitcoin_cancel_timelock,
|
||||
execution_params.bitcoin_punish_timelock,
|
||||
bitcoin_refund_address,
|
||||
|
@ -45,7 +45,7 @@ impl Seed {
|
||||
return Self::from_file(&file_path);
|
||||
}
|
||||
|
||||
tracing::info!("No seed file found, creating at: {}", file_path.display());
|
||||
tracing::debug!("No seed file found, creating at: {}", file_path.display());
|
||||
|
||||
let random_seed = Seed::random()?;
|
||||
random_seed.write_to(file_path.to_path_buf())?;
|
||||
@ -61,7 +61,7 @@ impl Seed {
|
||||
let contents = fs::read_to_string(file)?;
|
||||
let pem = pem::parse(contents)?;
|
||||
|
||||
tracing::info!("Read in seed from file: {}", file.display());
|
||||
tracing::trace!("Read in seed from {}", file.display());
|
||||
|
||||
Self::from_pem(pem)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user