Await 10 confirmations of lock tx in refund

Awaiting the confirmations in an earlier state can cause trouble with resuming
swaps with short cancel expiries (test scenarios).
Since it is the responsibility of the refund state to ensure that the XMR can
be sweeped, we now ensure that the lock transaction has 10 confirmations before
refunding the XMR using generate_from_keys.
This commit is contained in:
Daniel Karzel 2021-03-30 11:53:21 +11:00 committed by Thomas Eizinger
parent 1c129d58c4
commit bc442bcad3
No known key found for this signature in database
GPG Key ID: 651AC83A6C6C8B96
3 changed files with 90 additions and 38 deletions

View File

@ -30,27 +30,33 @@ pub enum Alice {
},
XmrLockTransferProofSent {
monero_wallet_restore_blockheight: BlockHeight,
transfer_proof: TransferProof,
state3: alice::State3,
},
EncSigLearned {
monero_wallet_restore_blockheight: BlockHeight,
transfer_proof: TransferProof,
encrypted_signature: EncryptedSignature,
state3: alice::State3,
},
CancelTimelockExpired {
monero_wallet_restore_blockheight: BlockHeight,
transfer_proof: TransferProof,
state3: alice::State3,
},
BtcCancelled {
monero_wallet_restore_blockheight: BlockHeight,
transfer_proof: TransferProof,
state3: alice::State3,
},
BtcPunishable {
monero_wallet_restore_blockheight: BlockHeight,
transfer_proof: TransferProof,
state3: alice::State3,
},
BtcRefunded {
monero_wallet_restore_blockheight: BlockHeight,
transfer_proof: TransferProof,
state3: alice::State3,
#[serde(with = "monero_private_key")]
spend_key: monero::PrivateKey,
@ -95,52 +101,62 @@ impl From<&AliceState> for Alice {
},
AliceState::XmrLockTransferProofSent {
monero_wallet_restore_blockheight,
transfer_proof,
state3,
} => Alice::XmrLockTransferProofSent {
monero_wallet_restore_blockheight: *monero_wallet_restore_blockheight,
transfer_proof: transfer_proof.clone(),
state3: state3.as_ref().clone(),
},
AliceState::EncSigLearned {
monero_wallet_restore_blockheight,
transfer_proof,
state3,
encrypted_signature,
} => Alice::EncSigLearned {
monero_wallet_restore_blockheight: *monero_wallet_restore_blockheight,
transfer_proof: transfer_proof.clone(),
state3: state3.as_ref().clone(),
encrypted_signature: *encrypted_signature.clone(),
},
AliceState::BtcRedeemed => Alice::Done(AliceEndState::BtcRedeemed),
AliceState::BtcCancelled {
monero_wallet_restore_blockheight,
transfer_proof,
state3,
..
} => Alice::BtcCancelled {
monero_wallet_restore_blockheight: *monero_wallet_restore_blockheight,
transfer_proof: transfer_proof.clone(),
state3: state3.as_ref().clone(),
},
AliceState::BtcRefunded {
monero_wallet_restore_blockheight,
transfer_proof,
spend_key,
state3,
} => Alice::BtcRefunded {
monero_wallet_restore_blockheight: *monero_wallet_restore_blockheight,
transfer_proof: transfer_proof.clone(),
spend_key: *spend_key,
state3: state3.as_ref().clone(),
},
AliceState::BtcPunishable {
monero_wallet_restore_blockheight,
transfer_proof,
state3,
..
} => Alice::BtcPunishable {
monero_wallet_restore_blockheight: *monero_wallet_restore_blockheight,
transfer_proof: transfer_proof.clone(),
state3: state3.as_ref().clone(),
},
AliceState::XmrRefunded => Alice::Done(AliceEndState::XmrRefunded),
AliceState::CancelTimelockExpired {
monero_wallet_restore_blockheight,
transfer_proof,
state3,
} => Alice::CancelTimelockExpired {
monero_wallet_restore_blockheight: *monero_wallet_restore_blockheight,
transfer_proof: transfer_proof.clone(),
state3: state3.as_ref().clone(),
},
AliceState::BtcPunished => Alice::Done(AliceEndState::BtcPunished),
@ -178,48 +194,60 @@ impl From<Alice> for AliceState {
},
Alice::XmrLockTransferProofSent {
monero_wallet_restore_blockheight,
transfer_proof,
state3,
} => AliceState::XmrLockTransferProofSent {
monero_wallet_restore_blockheight,
transfer_proof,
state3: Box::new(state3),
},
Alice::EncSigLearned {
monero_wallet_restore_blockheight,
transfer_proof,
state3: state,
encrypted_signature,
} => AliceState::EncSigLearned {
monero_wallet_restore_blockheight,
transfer_proof,
state3: Box::new(state),
encrypted_signature: Box::new(encrypted_signature),
},
Alice::CancelTimelockExpired {
monero_wallet_restore_blockheight,
transfer_proof,
state3,
} => AliceState::CancelTimelockExpired {
monero_wallet_restore_blockheight,
transfer_proof,
state3: Box::new(state3),
},
Alice::BtcCancelled {
monero_wallet_restore_blockheight,
transfer_proof,
state3,
} => AliceState::BtcCancelled {
monero_wallet_restore_blockheight,
transfer_proof,
state3: Box::new(state3),
},
Alice::BtcPunishable {
monero_wallet_restore_blockheight,
transfer_proof,
state3,
} => AliceState::BtcPunishable {
monero_wallet_restore_blockheight,
transfer_proof,
state3: Box::new(state3),
},
Alice::BtcRefunded {
monero_wallet_restore_blockheight,
state3,
transfer_proof,
spend_key,
state3,
} => AliceState::BtcRefunded {
monero_wallet_restore_blockheight,
transfer_proof,
spend_key,
state3: Box::new(state3),
},

View File

@ -34,30 +34,36 @@ pub enum AliceState {
},
XmrLockTransferProofSent {
monero_wallet_restore_blockheight: BlockHeight,
transfer_proof: TransferProof,
state3: Box<State3>,
},
EncSigLearned {
monero_wallet_restore_blockheight: BlockHeight,
transfer_proof: TransferProof,
encrypted_signature: Box<bitcoin::EncryptedSignature>,
state3: Box<State3>,
},
BtcRedeemed,
BtcCancelled {
monero_wallet_restore_blockheight: BlockHeight,
transfer_proof: TransferProof,
state3: Box<State3>,
},
BtcRefunded {
monero_wallet_restore_blockheight: BlockHeight,
transfer_proof: TransferProof,
spend_key: monero::PrivateKey,
state3: Box<State3>,
},
BtcPunishable {
monero_wallet_restore_blockheight: BlockHeight,
transfer_proof: TransferProof,
state3: Box<State3>,
},
XmrRefunded,
CancelTimelockExpired {
monero_wallet_restore_blockheight: BlockHeight,
transfer_proof: TransferProof,
state3: Box<State3>,
},
BtcPunished,

View File

@ -101,9 +101,9 @@ async fn next_state(
.await?;
AliceState::XmrLockTransactionSent {
state3,
transfer_proof,
monero_wallet_restore_blockheight,
transfer_proof,
state3,
}
}
_ => AliceState::SafelyAborted,
@ -120,47 +120,44 @@ async fn next_state(
.await?;
AliceState::XmrLocked {
state3,
monero_wallet_restore_blockheight,
transfer_proof,
state3,
}
}
_ => AliceState::CancelTimelockExpired {
state3,
monero_wallet_restore_blockheight,
transfer_proof,
state3,
},
},
AliceState::XmrLocked {
state3,
transfer_proof,
monero_wallet_restore_blockheight,
transfer_proof,
state3,
} => match state3.expired_timelocks(bitcoin_wallet).await? {
ExpiredTimelocks::None => {
event_loop_handle
.send_transfer_proof(transfer_proof.clone())
.await?;
// TODO: Handle this upon refund instead.
// Make sure that the balance of the created wallet is unlocked instead of
// watching for transfer.
monero_wallet
.watch_for_transfer(state3.lock_xmr_watch_request(transfer_proof, 10))
.await?;
XmrLockTransferProofSent {
state3,
monero_wallet_restore_blockheight,
transfer_proof,
state3,
}
}
_ => AliceState::CancelTimelockExpired {
state3,
monero_wallet_restore_blockheight,
transfer_proof,
state3,
},
},
AliceState::XmrLockTransferProofSent {
state3,
monero_wallet_restore_blockheight,
transfer_proof,
state3,
} => {
let tx_lock_status = bitcoin_wallet.subscribe_to(state3.tx_lock.clone()).await;
@ -168,32 +165,36 @@ async fn next_state(
ExpiredTimelocks::None => {
select! {
_ = tx_lock_status.wait_until_confirmed_with(state3.cancel_timelock) => {
AliceState::CancelTimelockExpired {
state3,
monero_wallet_restore_blockheight,
AliceState::CancelTimelockExpired {
monero_wallet_restore_blockheight,
transfer_proof,
state3,
}
}
enc_sig = event_loop_handle.recv_encrypted_signature() => {
tracing::info!("Received encrypted signature");
AliceState::EncSigLearned {
state3,
encrypted_signature: Box::new(enc_sig?),
monero_wallet_restore_blockheight,
transfer_proof,
encrypted_signature: Box::new(enc_sig?),
state3,
}
}
}
}
_ => AliceState::CancelTimelockExpired {
state3,
monero_wallet_restore_blockheight,
transfer_proof,
state3,
},
}
}
AliceState::EncSigLearned {
state3,
encrypted_signature,
monero_wallet_restore_blockheight,
transfer_proof,
encrypted_signature,
state3,
} => match state3.expired_timelocks(bitcoin_wallet).await? {
ExpiredTimelocks::None => {
let tx_lock_status = bitcoin_wallet.subscribe_to(state3.tx_lock.clone()).await;
@ -212,8 +213,9 @@ async fn next_state(
.await?;
AliceState::CancelTimelockExpired {
state3,
monero_wallet_restore_blockheight,
transfer_proof,
state3,
}
}
},
@ -224,20 +226,23 @@ async fn next_state(
.await?;
AliceState::CancelTimelockExpired {
state3,
monero_wallet_restore_blockheight,
transfer_proof,
state3,
}
}
}
}
_ => AliceState::CancelTimelockExpired {
state3,
monero_wallet_restore_blockheight,
transfer_proof,
state3,
},
},
AliceState::CancelTimelockExpired {
state3,
monero_wallet_restore_blockheight,
transfer_proof,
state3,
} => {
let transaction = state3.signed_cancel_transaction()?;
@ -259,13 +264,15 @@ async fn next_state(
}
AliceState::BtcCancelled {
state3,
monero_wallet_restore_blockheight,
transfer_proof,
state3,
}
}
AliceState::BtcCancelled {
state3,
monero_wallet_restore_blockheight,
transfer_proof,
state3,
} => {
let tx_refund_status = bitcoin_wallet.subscribe_to(state3.tx_refund()).await;
let tx_cancel_status = bitcoin_wallet.subscribe_to(state3.tx_cancel()).await;
@ -278,26 +285,35 @@ async fn next_state(
let spend_key = state3.extract_monero_private_key(published_refund_tx)?;
AliceState::BtcRefunded {
monero_wallet_restore_blockheight,
transfer_proof,
spend_key,
state3,
monero_wallet_restore_blockheight,
}
}
_ = tx_cancel_status.wait_until_confirmed_with(state3.punish_timelock) => {
AliceState::BtcPunishable {
state3,
monero_wallet_restore_blockheight,
transfer_proof,
state3,
}
}
}
}
AliceState::BtcRefunded {
monero_wallet_restore_blockheight,
transfer_proof,
spend_key,
state3,
monero_wallet_restore_blockheight,
} => {
let view_key = state3.v;
// Ensure that the XMR to be refunded are spendable by awaiting 10 confirmations
// on the lock transaction
monero_wallet
.watch_for_transfer(state3.lock_xmr_watch_request(transfer_proof, 10))
.await?;
monero_wallet
.create_from(spend_key, view_key, monero_wallet_restore_blockheight)
.await?;
@ -305,8 +321,9 @@ async fn next_state(
AliceState::XmrRefunded
}
AliceState::BtcPunishable {
state3,
monero_wallet_restore_blockheight,
transfer_proof,
state3,
} => {
let signed_tx_punish = state3.signed_punish_transaction()?;
@ -341,9 +358,10 @@ async fn next_state(
let spend_key = state3.extract_monero_private_key(published_refund_tx)?;
AliceState::BtcRefunded {
monero_wallet_restore_blockheight,
transfer_proof,
spend_key,
state3,
monero_wallet_restore_blockheight,
}
}
}