Insert latest state and call run_until only once

Instead of calling this function in all the branches, we can simply
make the whole match statement evaluate to the new state and perform
this functionality at the very end.
pull/325/head
Thomas Eizinger 3 years ago
parent 0d8962762a
commit b1affe3ecf
No known key found for this signature in database
GPG Key ID: 651AC83A6C6C8B96

@ -73,7 +73,7 @@ async fn run_until_internal(
return Ok(state);
}
match state {
let new_state = match state {
AliceState::Started { state3 } => {
timeout(
env_config.bob_time_to_act,
@ -88,22 +88,7 @@ async fn run_until_internal(
})
.await?;
let state = AliceState::BtcLocked { state3 };
let db_state = (&state).into();
db.insert_latest_state(swap_id, database::Swap::Alice(db_state))
.await?;
run_until_internal(
state,
is_target_state,
event_loop_handle,
bitcoin_wallet,
monero_wallet,
env_config,
swap_id,
db,
)
.await
AliceState::BtcLocked { state3 }
}
AliceState::BtcLocked { state3 } => {
// Record the current monero wallet block height so we don't have to scan from
@ -123,105 +108,60 @@ async fn run_until_internal(
.send_transfer_proof(transfer_proof)
.await?;
let state = AliceState::XmrLocked {
AliceState::XmrLocked {
state3,
monero_wallet_restore_blockheight,
};
let db_state = (&state).into();
db.insert_latest_state(swap_id, database::Swap::Alice(db_state))
.await?;
run_until_internal(
state,
is_target_state,
event_loop_handle,
bitcoin_wallet,
monero_wallet,
env_config,
swap_id,
db,
)
.await
}
}
AliceState::XmrLocked {
state3,
monero_wallet_restore_blockheight,
} => {
let state = match state3.expired_timelocks(bitcoin_wallet.as_ref()).await? {
ExpiredTimelocks::None => {
select! {
_ = state3.wait_for_cancel_timelock_to_expire(bitcoin_wallet.as_ref()) => {
AliceState::CancelTimelockExpired {
state3,
monero_wallet_restore_blockheight,
}
} => match state3.expired_timelocks(bitcoin_wallet.as_ref()).await? {
ExpiredTimelocks::None => {
select! {
_ = state3.wait_for_cancel_timelock_to_expire(bitcoin_wallet.as_ref()) => {
AliceState::CancelTimelockExpired {
state3,
monero_wallet_restore_blockheight,
}
enc_sig = event_loop_handle.recv_encrypted_signature() => {
tracing::info!("Received encrypted signature");
}
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,
}
AliceState::EncSigLearned {
state3,
encrypted_signature: Box::new(enc_sig?),
monero_wallet_restore_blockheight,
}
}
}
_ => AliceState::CancelTimelockExpired {
state3,
monero_wallet_restore_blockheight,
},
};
let db_state = (&state).into();
db.insert_latest_state(swap_id, database::Swap::Alice(db_state))
.await?;
run_until_internal(
state,
is_target_state,
event_loop_handle,
bitcoin_wallet.clone(),
monero_wallet,
env_config,
swap_id,
db,
)
.await
}
}
_ => AliceState::CancelTimelockExpired {
state3,
monero_wallet_restore_blockheight,
},
},
AliceState::EncSigLearned {
state3,
encrypted_signature,
monero_wallet_restore_blockheight,
} => {
let state = match state3.expired_timelocks(bitcoin_wallet.as_ref()).await? {
ExpiredTimelocks::None => {
match TxRedeem::new(&state3.tx_lock, &state3.redeem_address).complete(
*encrypted_signature,
state3.a.clone(),
state3.s_a.to_secpfun_scalar(),
state3.B,
) {
Ok(tx) => match bitcoin_wallet.broadcast(tx, "redeem").await {
Ok((_, finality)) => match finality.await {
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)
}
},
} => match state3.expired_timelocks(bitcoin_wallet.as_ref()).await? {
ExpiredTimelocks::None => {
match TxRedeem::new(&state3.tx_lock, &state3.redeem_address).complete(
*encrypted_signature,
state3.a.clone(),
state3.s_a.to_secpfun_scalar(),
state3.B,
) {
Ok(tx) => match bitcoin_wallet.broadcast(tx, "redeem").await {
Ok((_, finality)) => match finality.await {
Ok(_) => AliceState::BtcRedeemed,
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,
}
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!("Constructing the redeem transaction failed with {}, attempting to wait for cancellation now.", 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?;
@ -231,29 +171,25 @@ async fn run_until_internal(
monero_wallet_restore_blockheight,
}
}
},
Err(e) => {
error!("Constructing the redeem transaction failed with {}, attempting to wait for cancellation now.", e);
state3
.wait_for_cancel_timelock_to_expire(bitcoin_wallet.as_ref())
.await?;
AliceState::CancelTimelockExpired {
state3,
monero_wallet_restore_blockheight,
}
}
}
_ => AliceState::CancelTimelockExpired {
state3,
monero_wallet_restore_blockheight,
},
};
let db_state = (&state).into();
db.insert_latest_state(swap_id, database::Swap::Alice(db_state))
.await?;
run_until_internal(
state,
is_target_state,
event_loop_handle,
bitcoin_wallet,
monero_wallet,
env_config,
swap_id,
db,
)
.await
}
}
_ => AliceState::CancelTimelockExpired {
state3,
monero_wallet_restore_blockheight,
},
},
AliceState::CancelTimelockExpired {
state3,
monero_wallet_restore_blockheight,
@ -281,24 +217,10 @@ async fn run_until_internal(
// returned mined block height
}
let state = AliceState::BtcCancelled {
AliceState::BtcCancelled {
state3,
monero_wallet_restore_blockheight,
};
let db_state = (&state).into();
db.insert_latest_state(swap_id, database::Swap::Alice(db_state))
.await?;
run_until_internal(
state,
is_target_state,
event_loop_handle,
bitcoin_wallet,
monero_wallet,
env_config,
swap_id,
db,
)
.await
}
}
AliceState::BtcCancelled {
state3,
@ -314,7 +236,7 @@ async fn run_until_internal(
status.is_confirmed_with(state3.punish_timelock)
});
let state = tokio::select! {
select! {
seen_refund = seen_refund_tx => {
seen_refund.context("Failed to monitor refund transaction")?;
let published_refund_tx = bitcoin_wallet.get_raw_transaction(tx_refund.txid()).await?;
@ -338,23 +260,7 @@ async fn run_until_internal(
monero_wallet_restore_blockheight,
}
}
};
let db_state = (&state).into();
db.insert_latest_state(swap_id, database::Swap::Alice(db_state))
.await?;
run_until_internal(
state,
is_target_state,
event_loop_handle,
bitcoin_wallet.clone(),
monero_wallet,
env_config,
swap_id,
db,
)
.await
}
}
AliceState::BtcRefunded {
spend_key,
@ -367,11 +273,7 @@ async fn run_until_internal(
.create_from(spend_key, view_key, monero_wallet_restore_blockheight)
.await?;
let state = AliceState::XmrRefunded;
let db_state = (&state).into();
db.insert_latest_state(swap_id, database::Swap::Alice(db_state))
.await?;
Ok(state)
AliceState::XmrRefunded
}
AliceState::BtcPunishable {
state3,
@ -409,51 +311,36 @@ async fn run_until_internal(
state3.a.clone(),
state3.S_b_bitcoin,
)?;
let state = AliceState::BtcRefunded {
AliceState::BtcRefunded {
spend_key,
state3,
monero_wallet_restore_blockheight,
};
let db_state = (&state).into();
db.insert_latest_state(swap_id, database::Swap::Alice(db_state))
.await?;
run_until_internal(
state,
is_target_state,
event_loop_handle,
bitcoin_wallet.clone(),
monero_wallet,
env_config,
swap_id,
db,
)
.await
}
}
Either::Left((Err(e), _)) => {
bail!(e.context("Failed to monitor refund transaction"))
}
Either::Right(_) => {
let state = AliceState::BtcPunished;
let db_state = (&state).into();
db.insert_latest_state(swap_id, database::Swap::Alice(db_state))
.await?;
run_until_internal(
state,
is_target_state,
event_loop_handle,
bitcoin_wallet.clone(),
monero_wallet,
env_config,
swap_id,
db,
)
.await
}
Either::Right(_) => AliceState::BtcPunished,
}
}
AliceState::XmrRefunded => Ok(AliceState::XmrRefunded),
AliceState::BtcRedeemed => Ok(AliceState::BtcRedeemed),
AliceState::BtcPunished => Ok(AliceState::BtcPunished),
AliceState::SafelyAborted => Ok(AliceState::SafelyAborted),
}
AliceState::XmrRefunded => AliceState::XmrRefunded,
AliceState::BtcRedeemed => AliceState::BtcRedeemed,
AliceState::BtcPunished => AliceState::BtcPunished,
AliceState::SafelyAborted => AliceState::SafelyAborted,
};
let db_state = (&new_state).into();
db.insert_latest_state(swap_id, database::Swap::Alice(db_state))
.await?;
run_until_internal(
new_state,
is_target_state,
event_loop_handle,
bitcoin_wallet,
monero_wallet,
env_config,
swap_id,
db,
)
.await
}

@ -66,7 +66,7 @@ async fn run_until_internal(
return Ok(state);
}
match state {
let new_state = match state {
BobState::Started { btc_amount } => {
let bitcoin_refund_address = bitcoin_wallet.new_address().await?;
@ -80,21 +80,7 @@ async fn run_until_internal(
)
.await?;
let state = BobState::ExecutionSetupDone(state2);
let db_state = state.clone().into();
db.insert_latest_state(swap_id, Swap::Bob(db_state)).await?;
run_until_internal(
state,
is_target_state,
event_loop_handle,
db,
bitcoin_wallet,
monero_wallet,
swap_id,
env_config,
receive_monero_address,
)
.await
BobState::ExecutionSetupDone(state2)
}
BobState::ExecutionSetupDone(state2) => {
// Do not lock Bitcoin if not connected to Alice.
@ -107,28 +93,12 @@ async fn run_until_internal(
.context("Failed to sign Bitcoin lock transaction")?;
let (..) = bitcoin_wallet.broadcast(signed_tx, "lock").await?;
let state = BobState::BtcLocked(state3);
let db_state = state.clone().into();
db.insert_latest_state(swap_id, Swap::Bob(db_state)).await?;
run_until_internal(
state,
is_target_state,
event_loop_handle,
db,
bitcoin_wallet,
monero_wallet,
swap_id,
env_config,
receive_monero_address,
)
.await
BobState::BtcLocked(state3)
}
// Bob has locked Btc
// Watch for Alice to Lock Xmr or for cancel timelock to elapse
BobState::BtcLocked(state3) => {
let state = if let ExpiredTimelocks::None =
state3.current_epoch(bitcoin_wallet.as_ref()).await?
{
if let ExpiredTimelocks::None = state3.current_epoch(bitcoin_wallet.as_ref()).await? {
event_loop_handle.dial().await?;
let transfer_proof_watcher = event_loop_handle.recv_transfer_proof();
@ -163,30 +133,14 @@ async fn run_until_internal(
} else {
let state4 = state3.cancel();
BobState::CancelTimelockExpired(state4)
};
let db_state = state.clone().into();
db.insert_latest_state(swap_id, Swap::Bob(db_state)).await?;
run_until_internal(
state,
is_target_state,
event_loop_handle,
db,
bitcoin_wallet,
monero_wallet,
swap_id,
env_config,
receive_monero_address,
)
.await
}
}
BobState::XmrLockProofReceived {
state,
lock_transfer_proof,
monero_wallet_restore_blockheight,
} => {
let state = if let ExpiredTimelocks::None =
state.current_epoch(bitcoin_wallet.as_ref()).await?
{
if let ExpiredTimelocks::None = state.current_epoch(bitcoin_wallet.as_ref()).await? {
event_loop_handle.dial().await?;
let xmr_lock_watcher = state.clone().watch_for_lock_xmr(
@ -217,27 +171,10 @@ async fn run_until_internal(
} else {
let state4 = state.cancel();
BobState::CancelTimelockExpired(state4)
};
let db_state = state.clone().into();
db.insert_latest_state(swap_id, Swap::Bob(db_state)).await?;
run_until_internal(
state,
is_target_state,
event_loop_handle,
db,
bitcoin_wallet,
monero_wallet,
swap_id,
env_config,
receive_monero_address,
)
.await
}
}
BobState::XmrLocked(state) => {
let state = if let ExpiredTimelocks::None =
state.expired_timelock(bitcoin_wallet.as_ref()).await?
{
if let ExpiredTimelocks::None = state.expired_timelock(bitcoin_wallet.as_ref()).await? {
event_loop_handle.dial().await?;
// Alice has locked Xmr
// Bob sends Alice his key
@ -261,26 +198,10 @@ async fn run_until_internal(
}
} else {
BobState::CancelTimelockExpired(state)
};
let db_state = state.clone().into();
db.insert_latest_state(swap_id, Swap::Bob(db_state)).await?;
run_until_internal(
state,
is_target_state,
event_loop_handle,
db,
bitcoin_wallet,
monero_wallet,
swap_id,
env_config,
receive_monero_address,
)
.await
}
}
BobState::EncSigSent(state) => {
let state = if let ExpiredTimelocks::None =
state.expired_timelock(bitcoin_wallet.as_ref()).await?
{
if let ExpiredTimelocks::None = state.expired_timelock(bitcoin_wallet.as_ref()).await? {
let state_clone = state.clone();
let redeem_watcher = state_clone.watch_for_redeem_btc(bitcoin_wallet.as_ref());
let cancel_timelock_expires =
@ -296,22 +217,7 @@ async fn run_until_internal(
}
} else {
BobState::CancelTimelockExpired(state)
};
let db_state = state.clone().into();
db.insert_latest_state(swap_id, Swap::Bob(db_state)).await?;
run_until_internal(
state,
is_target_state,
event_loop_handle,
db,
bitcoin_wallet.clone(),
monero_wallet,
swap_id,
env_config,
receive_monero_address,
)
.await
}
}
BobState::BtcRedeemed(state) => {
// Bob redeems XMR using revealed s_a
@ -326,23 +232,9 @@ async fn run_until_internal(
tracing::info!("Sent XMR to {} in tx {}", receive_monero_address, tx_hash.0);
}
let state = BobState::XmrRedeemed {
BobState::XmrRedeemed {
tx_lock_id: state.tx_lock_id(),
};
let db_state = state.clone().into();
db.insert_latest_state(swap_id, Swap::Bob(db_state)).await?;
run_until_internal(
state,
is_target_state,
event_loop_handle,
db,
bitcoin_wallet,
monero_wallet,
swap_id,
env_config,
receive_monero_address,
)
.await
}
}
BobState::CancelTimelockExpired(state4) => {
if state4
@ -353,26 +245,11 @@ async fn run_until_internal(
state4.submit_tx_cancel(bitcoin_wallet.as_ref()).await?;
}
let state = BobState::BtcCancelled(state4);
db.insert_latest_state(swap_id, Swap::Bob(state.clone().into()))
.await?;
run_until_internal(
state,
is_target_state,
event_loop_handle,
db,
bitcoin_wallet,
monero_wallet,
swap_id,
env_config,
receive_monero_address,
)
.await
BobState::BtcCancelled(state4)
}
BobState::BtcCancelled(state) => {
// Bob has cancelled the swap
let state = match state.expired_timelock(bitcoin_wallet.as_ref()).await? {
match state.expired_timelock(bitcoin_wallet.as_ref()).await? {
ExpiredTimelocks::None => {
bail!(
"Internal error: canceled state reached before cancel timelock was expired"
@ -385,28 +262,28 @@ async fn run_until_internal(
ExpiredTimelocks::Punish => BobState::BtcPunished {
tx_lock_id: state.tx_lock_id(),
},
};
let db_state = state.clone().into();
db.insert_latest_state(swap_id, Swap::Bob(db_state)).await?;
run_until_internal(
state,
is_target_state,
event_loop_handle,
db,
bitcoin_wallet,
monero_wallet,
swap_id,
env_config,
receive_monero_address,
)
.await
}
}
BobState::BtcRefunded(state4) => Ok(BobState::BtcRefunded(state4)),
BobState::BtcPunished { tx_lock_id } => Ok(BobState::BtcPunished { tx_lock_id }),
BobState::SafelyAborted => Ok(BobState::SafelyAborted),
BobState::XmrRedeemed { tx_lock_id } => Ok(BobState::XmrRedeemed { tx_lock_id }),
}
BobState::BtcRefunded(state4) => BobState::BtcRefunded(state4),
BobState::BtcPunished { tx_lock_id } => BobState::BtcPunished { tx_lock_id },
BobState::SafelyAborted => BobState::SafelyAborted,
BobState::XmrRedeemed { tx_lock_id } => BobState::XmrRedeemed { tx_lock_id },
};
let db_state = new_state.clone().into();
db.insert_latest_state(swap_id, Swap::Bob(db_state)).await?;
run_until_internal(
new_state,
is_target_state,
event_loop_handle,
db,
bitcoin_wallet,
monero_wallet,
swap_id,
env_config,
receive_monero_address,
)
.await
}
pub async fn request_price_and_setup(

Loading…
Cancel
Save