mirror of
https://github.com/comit-network/xmr-btc-swap.git
synced 2024-12-25 23:49:31 -05:00
Make as many fields of Alice's states private as possible
To achieve this, we need to add some pure helpers to the state structs. This has the added benefit that we can reduce the amount of code within the swap function.
This commit is contained in:
parent
7f5715e147
commit
e130448200
@ -4,6 +4,7 @@ use crate::bitcoin::{
|
|||||||
use crate::env::Config;
|
use crate::env::Config;
|
||||||
use crate::monero::wallet::{TransferRequest, WatchRequest};
|
use crate::monero::wallet::{TransferRequest, WatchRequest};
|
||||||
use crate::monero::TransferProof;
|
use crate::monero::TransferProof;
|
||||||
|
use crate::monero_ext::ScalarExt;
|
||||||
use crate::protocol::alice::{Message1, Message3};
|
use crate::protocol::alice::{Message1, Message3};
|
||||||
use crate::protocol::bob::{Message0, Message2, Message4};
|
use crate::protocol::bob::{Message0, Message2, Message4};
|
||||||
use crate::protocol::CROSS_CURVE_PROOF_SYSTEM;
|
use crate::protocol::CROSS_CURVE_PROOF_SYSTEM;
|
||||||
@ -76,18 +77,18 @@ impl fmt::Display for AliceState {
|
|||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct State0 {
|
pub struct State0 {
|
||||||
pub a: bitcoin::SecretKey,
|
a: bitcoin::SecretKey,
|
||||||
pub s_a: monero::Scalar,
|
s_a: monero::Scalar,
|
||||||
pub v_a: monero::PrivateViewKey,
|
v_a: monero::PrivateViewKey,
|
||||||
pub(crate) S_a_monero: monero::PublicKey,
|
S_a_monero: monero::PublicKey,
|
||||||
pub(crate) S_a_bitcoin: bitcoin::PublicKey,
|
S_a_bitcoin: bitcoin::PublicKey,
|
||||||
pub dleq_proof_s_a: CrossCurveDLEQProof,
|
dleq_proof_s_a: CrossCurveDLEQProof,
|
||||||
pub btc: bitcoin::Amount,
|
btc: bitcoin::Amount,
|
||||||
pub xmr: monero::Amount,
|
xmr: monero::Amount,
|
||||||
pub cancel_timelock: CancelTimelock,
|
cancel_timelock: CancelTimelock,
|
||||||
pub punish_timelock: PunishTimelock,
|
punish_timelock: PunishTimelock,
|
||||||
pub redeem_address: bitcoin::Address,
|
redeem_address: bitcoin::Address,
|
||||||
pub punish_address: bitcoin::Address,
|
punish_address: bitcoin::Address,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State0 {
|
impl State0 {
|
||||||
@ -292,23 +293,23 @@ impl State2 {
|
|||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
|
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
|
||||||
pub struct State3 {
|
pub struct State3 {
|
||||||
pub a: bitcoin::SecretKey,
|
a: bitcoin::SecretKey,
|
||||||
pub B: bitcoin::PublicKey,
|
B: bitcoin::PublicKey,
|
||||||
pub s_a: monero::Scalar,
|
s_a: monero::Scalar,
|
||||||
pub S_b_monero: monero::PublicKey,
|
S_b_monero: monero::PublicKey,
|
||||||
pub S_b_bitcoin: bitcoin::PublicKey,
|
S_b_bitcoin: bitcoin::PublicKey,
|
||||||
pub v: monero::PrivateViewKey,
|
pub v: monero::PrivateViewKey,
|
||||||
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
|
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
|
||||||
pub btc: bitcoin::Amount,
|
btc: bitcoin::Amount,
|
||||||
pub xmr: monero::Amount,
|
xmr: monero::Amount,
|
||||||
pub cancel_timelock: CancelTimelock,
|
pub cancel_timelock: CancelTimelock,
|
||||||
pub punish_timelock: PunishTimelock,
|
pub punish_timelock: PunishTimelock,
|
||||||
pub refund_address: bitcoin::Address,
|
refund_address: bitcoin::Address,
|
||||||
pub redeem_address: bitcoin::Address,
|
redeem_address: bitcoin::Address,
|
||||||
pub punish_address: bitcoin::Address,
|
punish_address: bitcoin::Address,
|
||||||
pub tx_lock: bitcoin::TxLock,
|
pub tx_lock: bitcoin::TxLock,
|
||||||
pub tx_punish_sig_bob: bitcoin::Signature,
|
tx_punish_sig_bob: bitcoin::Signature,
|
||||||
pub tx_cancel_sig_bob: bitcoin::Signature,
|
tx_cancel_sig_bob: bitcoin::Signature,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State3 {
|
impl State3 {
|
||||||
@ -364,15 +365,48 @@ impl State3 {
|
|||||||
TxCancel::new(&self.tx_lock, self.cancel_timelock, self.a.public(), self.B)
|
TxCancel::new(&self.tx_lock, self.cancel_timelock, self.a.public(), self.B)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tx_punish(&self) -> TxPunish {
|
pub fn tx_refund(&self) -> TxRefund {
|
||||||
|
bitcoin::TxRefund::new(&self.tx_cancel(), &self.refund_address)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn extract_monero_private_key(
|
||||||
|
&self,
|
||||||
|
published_refund_tx: bitcoin::Transaction,
|
||||||
|
) -> Result<monero::PrivateKey> {
|
||||||
|
self.tx_refund().extract_monero_private_key(
|
||||||
|
published_refund_tx,
|
||||||
|
self.s_a,
|
||||||
|
self.a.clone(),
|
||||||
|
self.S_b_bitcoin,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn signed_redeem_transaction(
|
||||||
|
&self,
|
||||||
|
sig: bitcoin::EncryptedSignature,
|
||||||
|
) -> Result<bitcoin::Transaction> {
|
||||||
|
bitcoin::TxRedeem::new(&self.tx_lock, &self.redeem_address)
|
||||||
|
.complete(sig, self.a.clone(), self.s_a.to_secpfun_scalar(), self.B)
|
||||||
|
.context("Failed to complete Bitcoin redeem transaction")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn signed_cancel_transaction(&self) -> Result<bitcoin::Transaction> {
|
||||||
|
self.tx_cancel()
|
||||||
|
.complete_as_alice(self.a.clone(), self.B, self.tx_cancel_sig_bob.clone())
|
||||||
|
.context("Failed to complete Bitcoin cancel transaction")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn signed_punish_transaction(&self) -> Result<bitcoin::Transaction> {
|
||||||
|
self.tx_punish()
|
||||||
|
.complete(self.tx_punish_sig_bob.clone(), self.a.clone(), self.B)
|
||||||
|
.context("Failed to complete Bitcoin punish transaction")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tx_punish(&self) -> TxPunish {
|
||||||
bitcoin::TxPunish::new(
|
bitcoin::TxPunish::new(
|
||||||
&self.tx_cancel(),
|
&self.tx_cancel(),
|
||||||
&self.punish_address,
|
&self.punish_address,
|
||||||
self.punish_timelock,
|
self.punish_timelock,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tx_refund(&self) -> TxRefund {
|
|
||||||
bitcoin::TxRefund::new(&self.tx_cancel(), &self.refund_address)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
//! Run an XMR/BTC swap in the role of Alice.
|
//! Run an XMR/BTC swap in the role of Alice.
|
||||||
//! Alice holds XMR and wishes receive BTC.
|
//! Alice holds XMR and wishes receive BTC.
|
||||||
use crate::bitcoin::{ExpiredTimelocks, TxRedeem};
|
use crate::bitcoin::ExpiredTimelocks;
|
||||||
use crate::env::Config;
|
use crate::env::Config;
|
||||||
use crate::monero_ext::ScalarExt;
|
|
||||||
use crate::protocol::alice;
|
use crate::protocol::alice;
|
||||||
use crate::protocol::alice::event_loop::EventLoopHandle;
|
use crate::protocol::alice::event_loop::EventLoopHandle;
|
||||||
use crate::protocol::alice::AliceState;
|
use crate::protocol::alice::AliceState;
|
||||||
@ -158,12 +157,7 @@ async fn next_state(
|
|||||||
} => match state3.expired_timelocks(bitcoin_wallet).await? {
|
} => match state3.expired_timelocks(bitcoin_wallet).await? {
|
||||||
ExpiredTimelocks::None => {
|
ExpiredTimelocks::None => {
|
||||||
let tx_lock_status = bitcoin_wallet.subscribe_to(state3.tx_lock.clone()).await;
|
let tx_lock_status = bitcoin_wallet.subscribe_to(state3.tx_lock.clone()).await;
|
||||||
match TxRedeem::new(&state3.tx_lock, &state3.redeem_address).complete(
|
match state3.signed_redeem_transaction(*encrypted_signature) {
|
||||||
*encrypted_signature,
|
|
||||||
state3.a.clone(),
|
|
||||||
state3.s_a.to_secpfun_scalar(),
|
|
||||||
state3.B,
|
|
||||||
) {
|
|
||||||
Ok(tx) => match bitcoin_wallet.broadcast(tx, "redeem").await {
|
Ok(tx) => match bitcoin_wallet.broadcast(tx, "redeem").await {
|
||||||
Ok((_, subscription)) => match subscription.wait_until_final().await {
|
Ok((_, subscription)) => match subscription.wait_until_final().await {
|
||||||
Ok(_) => AliceState::BtcRedeemed,
|
Ok(_) => AliceState::BtcRedeemed,
|
||||||
@ -205,18 +199,14 @@ async fn next_state(
|
|||||||
state3,
|
state3,
|
||||||
monero_wallet_restore_blockheight,
|
monero_wallet_restore_blockheight,
|
||||||
} => {
|
} => {
|
||||||
let tx_cancel = state3.tx_cancel();
|
let transaction = state3.signed_cancel_transaction()?;
|
||||||
|
|
||||||
// If Bob hasn't yet broadcasted the tx cancel, we do it
|
// If Bob hasn't yet broadcasted the tx cancel, we do it
|
||||||
if bitcoin_wallet
|
if bitcoin_wallet
|
||||||
.get_raw_transaction(tx_cancel.txid())
|
.get_raw_transaction(transaction.txid())
|
||||||
.await
|
.await
|
||||||
.is_err()
|
.is_err()
|
||||||
{
|
{
|
||||||
let transaction = tx_cancel
|
|
||||||
.complete_as_alice(state3.a.clone(), state3.B, state3.tx_cancel_sig_bob.clone())
|
|
||||||
.context("Failed to complete Bitcoin cancel transaction")?;
|
|
||||||
|
|
||||||
if let Err(e) = bitcoin_wallet.broadcast(transaction, "cancel").await {
|
if let Err(e) = bitcoin_wallet.broadcast(transaction, "cancel").await {
|
||||||
tracing::debug!(
|
tracing::debug!(
|
||||||
"Assuming transaction is already broadcasted because: {:#}",
|
"Assuming transaction is already broadcasted because: {:#}",
|
||||||
@ -243,14 +233,9 @@ async fn next_state(
|
|||||||
select! {
|
select! {
|
||||||
seen_refund = tx_refund_status.wait_until_seen() => {
|
seen_refund = tx_refund_status.wait_until_seen() => {
|
||||||
seen_refund.context("Failed to monitor refund transaction")?;
|
seen_refund.context("Failed to monitor refund transaction")?;
|
||||||
let published_refund_tx = bitcoin_wallet.get_raw_transaction(state3.tx_refund().txid()).await?;
|
|
||||||
|
|
||||||
let spend_key = state3.tx_refund().extract_monero_private_key(
|
let published_refund_tx = bitcoin_wallet.get_raw_transaction(state3.tx_refund().txid()).await?;
|
||||||
published_refund_tx,
|
let spend_key = state3.extract_monero_private_key(published_refund_tx)?;
|
||||||
state3.s_a,
|
|
||||||
state3.a.clone(),
|
|
||||||
state3.S_b_bitcoin,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
AliceState::BtcRefunded {
|
AliceState::BtcRefunded {
|
||||||
spend_key,
|
spend_key,
|
||||||
@ -283,11 +268,7 @@ async fn next_state(
|
|||||||
state3,
|
state3,
|
||||||
monero_wallet_restore_blockheight,
|
monero_wallet_restore_blockheight,
|
||||||
} => {
|
} => {
|
||||||
let signed_tx_punish = state3.tx_punish().complete(
|
let signed_tx_punish = state3.signed_punish_transaction()?;
|
||||||
state3.tx_punish_sig_bob.clone(),
|
|
||||||
state3.a.clone(),
|
|
||||||
state3.B,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let punish = async {
|
let punish = async {
|
||||||
let (txid, subscription) =
|
let (txid, subscription) =
|
||||||
@ -313,16 +294,11 @@ async fn next_state(
|
|||||||
// because a punish tx failure is not recoverable (besides re-trying) if the
|
// because a punish tx failure is not recoverable (besides re-trying) if the
|
||||||
// refund tx was not included.
|
// refund tx was not included.
|
||||||
|
|
||||||
let tx_refund = state3.tx_refund();
|
let published_refund_tx = bitcoin_wallet
|
||||||
let published_refund_tx =
|
.get_raw_transaction(state3.tx_refund().txid())
|
||||||
bitcoin_wallet.get_raw_transaction(tx_refund.txid()).await?;
|
.await?;
|
||||||
|
|
||||||
let spend_key = tx_refund.extract_monero_private_key(
|
let spend_key = state3.extract_monero_private_key(published_refund_tx)?;
|
||||||
published_refund_tx,
|
|
||||||
state3.s_a,
|
|
||||||
state3.a.clone(),
|
|
||||||
state3.S_b_bitcoin,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
AliceState::BtcRefunded {
|
AliceState::BtcRefunded {
|
||||||
spend_key,
|
spend_key,
|
||||||
|
Loading…
Reference in New Issue
Block a user