diff --git a/swap/src/bitcoin.rs b/swap/src/bitcoin.rs index 7e833ee4..61092574 100644 --- a/swap/src/bitcoin.rs +++ b/swap/src/bitcoin.rs @@ -1,6 +1,5 @@ pub mod wallet; -mod timelocks; mod cancel; mod lock; mod punish; @@ -9,18 +8,18 @@ mod refund; mod timelocks; pub use crate::bitcoin::{ - cancel::TxCancel, + cancel::{CancelTimelock, PunishTimelock, TxCancel}, lock::TxLock, punish::TxPunish, redeem::TxRedeem, refund::TxRefund, - timelocks::Timelock, + timelocks::{BlockHeight, ExpiredTimelocks}, }; 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::{bitcoin::timelocks::BlockHeight, execution_params::ExecutionParams}; +use crate::execution_params::ExecutionParams; use ::bitcoin::{ hashes::{hex::ToHex, Hash}, secp256k1, @@ -35,7 +34,6 @@ use rand::{CryptoRng, RngCore}; use serde::{Deserialize, Serialize}; use sha2::Sha256; use std::str::FromStr; -use timelocks::ExpiredTimelocks; // TODO: Configurable tx-fee (note: parties have to agree prior to swapping) // Current reasoning: @@ -272,8 +270,8 @@ where pub async fn current_epoch( bitcoin_wallet: &W, - cancel_timelock: Timelock, - punish_timelock: Timelock, + cancel_timelock: CancelTimelock, + punish_timelock: PunishTimelock, lock_tx_id: ::bitcoin::Txid, ) -> anyhow::Result where @@ -296,7 +294,7 @@ where pub async fn wait_for_cancel_timelock_to_expire( bitcoin_wallet: &W, - cancel_timelock: Timelock, + cancel_timelock: CancelTimelock, lock_tx_id: ::bitcoin::Txid, ) -> Result<()> where diff --git a/swap/src/bitcoin/cancel.rs b/swap/src/bitcoin/cancel.rs index f814ea25..72b719ad 100644 --- a/swap/src/bitcoin/cancel.rs +++ b/swap/src/bitcoin/cancel.rs @@ -1,13 +1,57 @@ use crate::bitcoin::{ - build_shared_output_descriptor, - timelocks::{CancelTimelock, Timelock}, - Address, Amount, PublicKey, Transaction, TxLock, TX_FEE, + build_shared_output_descriptor, Address, Amount, BlockHeight, PublicKey, Transaction, TxLock, + TX_FEE, }; use ::bitcoin::{util::bip143::SigHashCache, OutPoint, SigHash, SigHashType, TxIn, TxOut, Txid}; use anyhow::Result; use ecdsa_fun::Signature; use miniscript::{Descriptor, NullCtx}; -use std::collections::HashMap; +use serde::{Deserialize, Serialize}; +use std::{collections::HashMap, ops::Add}; + +/// Represent a timelock, expressed in relative block height as defined in +/// [BIP68](https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki). +/// E.g. The timelock expires 10 blocks after the reference transaction is +/// mined. +#[derive(Debug, Copy, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[serde(transparent)] +pub struct CancelTimelock(u32); + +impl CancelTimelock { + pub const fn new(number_of_blocks: u32) -> Self { + Self(number_of_blocks) + } +} + +impl Add for BlockHeight { + type Output = BlockHeight; + + fn add(self, rhs: CancelTimelock) -> Self::Output { + self + rhs.0 + } +} + +/// Represent a timelock, expressed in relative block height as defined in +/// [BIP68](https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki). +/// E.g. The timelock expires 10 blocks after the reference transaction is +/// mined. +#[derive(Debug, Copy, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[serde(transparent)] +pub struct PunishTimelock(u32); + +impl PunishTimelock { + pub const fn new(number_of_blocks: u32) -> Self { + Self(number_of_blocks) + } +} + +impl Add for BlockHeight { + type Output = BlockHeight; + + fn add(self, rhs: PunishTimelock) -> Self::Output { + self + rhs.0 + } +} #[derive(Debug, Clone)] pub struct TxCancel { @@ -28,7 +72,7 @@ impl TxCancel { let tx_in = TxIn { previous_output: tx_lock.as_outpoint(), script_sig: Default::default(), - sequence: cancel_timelock.into(), + sequence: cancel_timelock.0, witness: Vec::new(), }; @@ -110,14 +154,14 @@ impl TxCancel { pub fn build_spend_transaction( &self, spend_address: &Address, - sequence: Option, + sequence: Option, ) -> Transaction { let previous_output = self.as_outpoint(); let tx_in = TxIn { previous_output, script_sig: Default::default(), - sequence: sequence.map(Into::into).unwrap_or(0xFFFF_FFFF), + sequence: sequence.map(|seq| seq.0).unwrap_or(0xFFFF_FFFF), witness: Vec::new(), }; diff --git a/swap/src/bitcoin/punish.rs b/swap/src/bitcoin/punish.rs index 6e0a208f..79322ce1 100644 --- a/swap/src/bitcoin/punish.rs +++ b/swap/src/bitcoin/punish.rs @@ -1,4 +1,4 @@ -use crate::bitcoin::{timelocks::PunishTimelock, Address, PublicKey, Transaction, TxCancel}; +use crate::bitcoin::{Address, PublicKey, PunishTimelock, Transaction, TxCancel}; use ::bitcoin::{util::bip143::SigHashCache, SigHash, SigHashType}; use anyhow::Result; use ecdsa_fun::Signature; @@ -17,8 +17,7 @@ impl TxPunish { punish_address: &Address, punish_timelock: PunishTimelock, ) -> Self { - let tx_punish = - tx_cancel.build_spend_transaction(punish_address, Some(punish_timelock.into())); + let tx_punish = tx_cancel.build_spend_transaction(punish_address, Some(punish_timelock)); let digest = SigHashCache::new(&tx_punish).signature_hash( 0, // Only one input: cancel transaction diff --git a/swap/src/bitcoin/timelocks.rs b/swap/src/bitcoin/timelocks.rs index a4dc332c..cbde97a4 100644 --- a/swap/src/bitcoin/timelocks.rs +++ b/swap/src/bitcoin/timelocks.rs @@ -1,26 +1,5 @@ -use std::ops::Add; - use serde::{Deserialize, Serialize}; - -/// Represent a timelock, expressed in relative block height as defined in -/// [BIP68](https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki). -/// E.g. The timelock expires 10 blocks after the reference transaction is -/// mined. -#[derive(Debug, Copy, Clone, Serialize, Deserialize, Eq, PartialEq)] -#[serde(transparent)] -pub struct Timelock(u32); - -impl Timelock { - pub const fn new(number_of_blocks: u32) -> Self { - Self(number_of_blocks) - } -} - -impl From for u32 { - fn from(timelock: Timelock) -> Self { - timelock.0 - } -} +use std::ops::Add; /// Represent a block height, or block number, expressed in absolute block /// count. E.g. The transaction was included in block #655123, 655123 block @@ -41,11 +20,11 @@ impl BlockHeight { } } -impl Add for BlockHeight { +impl Add for BlockHeight { type Output = BlockHeight; - fn add(self, rhs: Timelock) -> Self::Output { - BlockHeight(self.0 + rhs.0) + fn add(self, rhs: u32) -> Self::Output { + BlockHeight(self.0 + rhs) } } diff --git a/swap/src/execution_params.rs b/swap/src/execution_params.rs index 836a580d..ba3ae21e 100644 --- a/swap/src/execution_params.rs +++ b/swap/src/execution_params.rs @@ -1,4 +1,4 @@ -use crate::bitcoin::Timelock; +use crate::bitcoin::{CancelTimelock, PunishTimelock}; use conquer_once::Lazy; use std::time::Duration; @@ -8,8 +8,8 @@ pub struct ExecutionParams { pub bitcoin_finality_confirmations: u32, pub bitcoin_avg_block_time: Duration, pub monero_finality_confirmations: u32, - pub bitcoin_cancel_timelock: Timelock, - pub bitcoin_punish_timelock: Timelock, + pub bitcoin_cancel_timelock: CancelTimelock, + pub bitcoin_punish_timelock: PunishTimelock, } pub trait GetExecutionParams { @@ -77,8 +77,8 @@ mod mainnet { pub static MONERO_FINALITY_CONFIRMATIONS: u32 = 15; // Set to 12 hours, arbitrary value to be reviewed properly - pub static BITCOIN_CANCEL_TIMELOCK: Timelock = Timelock::new(72); - pub static BITCOIN_PUNISH_TIMELOCK: Timelock = Timelock::new(72); + pub static BITCOIN_CANCEL_TIMELOCK: CancelTimelock = CancelTimelock::new(72); + pub static BITCOIN_PUNISH_TIMELOCK: PunishTimelock = PunishTimelock::new(72); } mod testnet { @@ -95,8 +95,8 @@ mod testnet { pub static MONERO_FINALITY_CONFIRMATIONS: u32 = 5; // This does not reflect recommended values for mainnet! - pub static BITCOIN_CANCEL_TIMELOCK: Timelock = Timelock::new(12); - pub static BITCOIN_PUNISH_TIMELOCK: Timelock = Timelock::new(6); + pub static BITCOIN_CANCEL_TIMELOCK: CancelTimelock = CancelTimelock::new(12); + pub static BITCOIN_PUNISH_TIMELOCK: PunishTimelock = PunishTimelock::new(6); } mod regtest { @@ -111,7 +111,7 @@ mod regtest { pub static MONERO_FINALITY_CONFIRMATIONS: u32 = 1; - pub static BITCOIN_CANCEL_TIMELOCK: Timelock = Timelock::new(100); + pub static BITCOIN_CANCEL_TIMELOCK: CancelTimelock = CancelTimelock::new(100); - pub static BITCOIN_PUNISH_TIMELOCK: Timelock = Timelock::new(50); + pub static BITCOIN_PUNISH_TIMELOCK: PunishTimelock = PunishTimelock::new(50); } diff --git a/swap/src/protocol/alice/state.rs b/swap/src/protocol/alice/state.rs index 9905a069..cee4a0e6 100644 --- a/swap/src/protocol/alice/state.rs +++ b/swap/src/protocol/alice/state.rs @@ -1,10 +1,9 @@ use crate::{ bitcoin, bitcoin::{ - current_epoch, - timelocks::{ExpiredTimelocks, Timelock}, - wait_for_cancel_timelock_to_expire, GetBlockHeight, TransactionBlockHeight, TxCancel, - TxRefund, WatchForRawTransaction, + current_epoch, wait_for_cancel_timelock_to_expire, CancelTimelock, ExpiredTimelocks, + GetBlockHeight, PunishTimelock, TransactionBlockHeight, TxCancel, TxRefund, + WatchForRawTransaction, }, execution_params::ExecutionParams, monero, @@ -90,8 +89,8 @@ pub struct State0 { #[serde(with = "::bitcoin::util::amount::serde::as_sat")] pub btc: bitcoin::Amount, pub xmr: monero::Amount, - pub cancel_timelock: Timelock, - pub punish_timelock: Timelock, + pub cancel_timelock: CancelTimelock, + pub punish_timelock: PunishTimelock, pub redeem_address: bitcoin::Address, pub punish_address: bitcoin::Address, } @@ -172,8 +171,8 @@ pub struct State1 { #[serde(with = "::bitcoin::util::amount::serde::as_sat")] btc: bitcoin::Amount, xmr: monero::Amount, - cancel_timelock: Timelock, - punish_timelock: Timelock, + cancel_timelock: CancelTimelock, + punish_timelock: PunishTimelock, refund_address: bitcoin::Address, redeem_address: bitcoin::Address, punish_address: bitcoin::Address, @@ -225,8 +224,8 @@ pub struct State2 { #[serde(with = "::bitcoin::util::amount::serde::as_sat")] btc: bitcoin::Amount, xmr: monero::Amount, - cancel_timelock: Timelock, - punish_timelock: Timelock, + cancel_timelock: CancelTimelock, + punish_timelock: PunishTimelock, refund_address: bitcoin::Address, redeem_address: bitcoin::Address, punish_address: bitcoin::Address, @@ -295,8 +294,8 @@ pub struct State3 { #[serde(with = "::bitcoin::util::amount::serde::as_sat")] pub btc: bitcoin::Amount, pub xmr: monero::Amount, - pub cancel_timelock: Timelock, - pub punish_timelock: Timelock, + pub cancel_timelock: CancelTimelock, + pub punish_timelock: PunishTimelock, pub refund_address: bitcoin::Address, pub redeem_address: bitcoin::Address, pub punish_address: bitcoin::Address, @@ -341,8 +340,8 @@ pub struct State4 { S_b_bitcoin: bitcoin::PublicKey, v: monero::PrivateViewKey, xmr: monero::Amount, - cancel_timelock: Timelock, - punish_timelock: Timelock, + cancel_timelock: CancelTimelock, + punish_timelock: PunishTimelock, refund_address: bitcoin::Address, redeem_address: bitcoin::Address, punish_address: bitcoin::Address, @@ -433,8 +432,8 @@ pub struct State5 { S_b_monero: monero::PublicKey, S_b_bitcoin: bitcoin::PublicKey, v: monero::PrivateViewKey, - cancel_timelock: Timelock, - punish_timelock: Timelock, + cancel_timelock: CancelTimelock, + punish_timelock: PunishTimelock, refund_address: bitcoin::Address, redeem_address: bitcoin::Address, punish_address: bitcoin::Address, @@ -483,8 +482,8 @@ pub struct State6 { S_b_monero: monero::PublicKey, S_b_bitcoin: bitcoin::PublicKey, v: monero::PrivateViewKey, - cancel_timelock: Timelock, - punish_timelock: Timelock, + cancel_timelock: CancelTimelock, + punish_timelock: PunishTimelock, refund_address: bitcoin::Address, redeem_address: bitcoin::Address, punish_address: bitcoin::Address, diff --git a/swap/src/protocol/alice/steps.rs b/swap/src/protocol/alice/steps.rs index 2e437339..d8b29c87 100644 --- a/swap/src/protocol/alice/steps.rs +++ b/swap/src/protocol/alice/steps.rs @@ -1,9 +1,8 @@ use crate::{ bitcoin, bitcoin::{ - poll_until_block_height_is_gte, - timelocks::{BlockHeight, Timelock}, - BroadcastSignedTransaction, EncryptedSignature, GetBlockHeight, GetRawTransaction, + poll_until_block_height_is_gte, BlockHeight, BroadcastSignedTransaction, CancelTimelock, + EncryptedSignature, GetBlockHeight, GetRawTransaction, PunishTimelock, TransactionBlockHeight, TxCancel, TxLock, TxRefund, WaitForTransactionFinality, WatchForRawTransaction, }, @@ -151,7 +150,7 @@ pub async fn publish_cancel_transaction( tx_lock: TxLock, a: bitcoin::SecretKey, B: bitcoin::PublicKey, - cancel_timelock: Timelock, + cancel_timelock: CancelTimelock, tx_cancel_sig_bob: bitcoin::Signature, bitcoin_wallet: Arc, ) -> Result @@ -198,7 +197,7 @@ where pub async fn wait_for_bitcoin_refund( tx_cancel: &TxCancel, cancel_tx_height: BlockHeight, - punish_timelock: Timelock, + punish_timelock: PunishTimelock, refund_address: &bitcoin::Address, bitcoin_wallet: Arc, ) -> Result<(bitcoin::TxRefund, Option)> @@ -250,9 +249,9 @@ pub fn extract_monero_private_key( pub fn build_bitcoin_punish_transaction( tx_lock: &TxLock, - cancel_timelock: Timelock, + cancel_timelock: CancelTimelock, punish_address: &bitcoin::Address, - punish_timelock: Timelock, + punish_timelock: PunishTimelock, tx_punish_sig_bob: bitcoin::Signature, a: bitcoin::SecretKey, B: bitcoin::PublicKey, diff --git a/swap/src/protocol/alice/swap.rs b/swap/src/protocol/alice/swap.rs index 4bd6ef6a..d5a5aef2 100644 --- a/swap/src/protocol/alice/swap.rs +++ b/swap/src/protocol/alice/swap.rs @@ -3,7 +3,7 @@ use crate::{ bitcoin, bitcoin::{ - timelocks::ExpiredTimelocks, TransactionBlockHeight, WaitForTransactionFinality, + ExpiredTimelocks, TransactionBlockHeight, WaitForTransactionFinality, WatchForRawTransaction, }, database, diff --git a/swap/src/protocol/bob/cancel.rs b/swap/src/protocol/bob/cancel.rs index 0c1cb0fe..ccce6361 100644 --- a/swap/src/protocol/bob/cancel.rs +++ b/swap/src/protocol/bob/cancel.rs @@ -1,5 +1,5 @@ use crate::{ - bitcoin::{timelocks::ExpiredTimelocks, Txid, Wallet}, + bitcoin::{ExpiredTimelocks, Txid, Wallet}, database::{Database, Swap}, protocol::bob::BobState, }; diff --git a/swap/src/protocol/bob/state.rs b/swap/src/protocol/bob/state.rs index 66c8c4eb..038033f2 100644 --- a/swap/src/protocol/bob/state.rs +++ b/swap/src/protocol/bob/state.rs @@ -1,10 +1,9 @@ use crate::{ bitcoin::{ - self, current_epoch, - timelocks::{ExpiredTimelocks, Timelock}, - wait_for_cancel_timelock_to_expire, BroadcastSignedTransaction, BuildTxLockPsbt, - GetBlockHeight, GetNetwork, GetRawTransaction, Transaction, TransactionBlockHeight, - TxCancel, Txid, WatchForRawTransaction, + self, current_epoch, wait_for_cancel_timelock_to_expire, BroadcastSignedTransaction, + BuildTxLockPsbt, CancelTimelock, ExpiredTimelocks, GetBlockHeight, GetNetwork, + GetRawTransaction, PunishTimelock, Transaction, TransactionBlockHeight, TxCancel, Txid, + WatchForRawTransaction, }, execution_params::ExecutionParams, monero, @@ -82,8 +81,8 @@ pub struct State0 { #[serde(with = "::bitcoin::util::amount::serde::as_sat")] btc: bitcoin::Amount, xmr: monero::Amount, - cancel_timelock: Timelock, - punish_timelock: Timelock, + cancel_timelock: CancelTimelock, + punish_timelock: PunishTimelock, refund_address: bitcoin::Address, min_monero_confirmations: u32, } @@ -93,8 +92,8 @@ impl State0 { rng: &mut R, btc: bitcoin::Amount, xmr: monero::Amount, - cancel_timelock: Timelock, - punish_timelock: Timelock, + cancel_timelock: CancelTimelock, + punish_timelock: PunishTimelock, refund_address: bitcoin::Address, min_monero_confirmations: u32, ) -> Self { @@ -177,8 +176,8 @@ pub struct State1 { #[serde(with = "::bitcoin::util::amount::serde::as_sat")] btc: bitcoin::Amount, xmr: monero::Amount, - cancel_timelock: Timelock, - punish_timelock: Timelock, + cancel_timelock: CancelTimelock, + punish_timelock: PunishTimelock, refund_address: bitcoin::Address, redeem_address: bitcoin::Address, punish_address: bitcoin::Address, @@ -238,8 +237,8 @@ pub struct State2 { #[serde(with = "::bitcoin::util::amount::serde::as_sat")] btc: bitcoin::Amount, pub xmr: monero::Amount, - pub cancel_timelock: Timelock, - pub punish_timelock: Timelock, + pub cancel_timelock: CancelTimelock, + pub punish_timelock: PunishTimelock, pub refund_address: bitcoin::Address, pub redeem_address: bitcoin::Address, pub punish_address: bitcoin::Address, @@ -307,8 +306,8 @@ pub struct State3 { #[serde(with = "::bitcoin::util::amount::serde::as_sat")] btc: bitcoin::Amount, xmr: monero::Amount, - pub cancel_timelock: Timelock, - punish_timelock: Timelock, + pub cancel_timelock: CancelTimelock, + punish_timelock: PunishTimelock, pub refund_address: bitcoin::Address, redeem_address: bitcoin::Address, punish_address: bitcoin::Address, @@ -427,8 +426,8 @@ pub struct State4 { #[serde(with = "::bitcoin::util::amount::serde::as_sat")] btc: bitcoin::Amount, xmr: monero::Amount, - pub cancel_timelock: Timelock, - punish_timelock: Timelock, + pub cancel_timelock: CancelTimelock, + punish_timelock: PunishTimelock, pub refund_address: bitcoin::Address, pub redeem_address: bitcoin::Address, punish_address: bitcoin::Address, @@ -614,8 +613,8 @@ pub struct State5 { #[serde(with = "::bitcoin::util::amount::serde::as_sat")] btc: bitcoin::Amount, xmr: monero::Amount, - cancel_timelock: Timelock, - punish_timelock: Timelock, + cancel_timelock: CancelTimelock, + punish_timelock: PunishTimelock, refund_address: bitcoin::Address, pub redeem_address: bitcoin::Address, punish_address: bitcoin::Address, diff --git a/swap/src/protocol/bob/swap.rs b/swap/src/protocol/bob/swap.rs index 95a6647b..7aec3404 100644 --- a/swap/src/protocol/bob/swap.rs +++ b/swap/src/protocol/bob/swap.rs @@ -1,6 +1,6 @@ use crate::{ bitcoin, - bitcoin::timelocks::ExpiredTimelocks, + bitcoin::ExpiredTimelocks, database::{Database, Swap}, execution_params::ExecutionParams, monero, diff --git a/swap/tests/testutils/mod.rs b/swap/tests/testutils/mod.rs index 444f4b9c..ea0384f4 100644 --- a/swap/tests/testutils/mod.rs +++ b/swap/tests/testutils/mod.rs @@ -7,7 +7,7 @@ use monero_harness::{image, Monero}; use std::{path::PathBuf, sync::Arc}; use swap::{ bitcoin, - bitcoin::Timelock, + bitcoin::{CancelTimelock, PunishTimelock}, database::Database, execution_params, execution_params::{ExecutionParams, GetExecutionParams}, @@ -484,7 +484,7 @@ pub struct SlowCancelConfig; impl GetExecutionParams for SlowCancelConfig { fn get_execution_params() -> ExecutionParams { ExecutionParams { - bitcoin_cancel_timelock: Timelock::new(180), + bitcoin_cancel_timelock: CancelTimelock::new(180), ..execution_params::Regtest::get_execution_params() } } @@ -495,7 +495,7 @@ pub struct FastCancelConfig; impl GetExecutionParams for FastCancelConfig { fn get_execution_params() -> ExecutionParams { ExecutionParams { - bitcoin_cancel_timelock: Timelock::new(1), + bitcoin_cancel_timelock: CancelTimelock::new(1), ..execution_params::Regtest::get_execution_params() } } @@ -506,8 +506,8 @@ pub struct FastPunishConfig; impl GetExecutionParams for FastPunishConfig { fn get_execution_params() -> ExecutionParams { ExecutionParams { - bitcoin_cancel_timelock: Timelock::new(1), - bitcoin_punish_timelock: Timelock::new(1), + bitcoin_cancel_timelock: CancelTimelock::new(1), + bitcoin_punish_timelock: PunishTimelock::new(1), ..execution_params::Regtest::get_execution_params() } }