diff --git a/daemon/src/setup_contract.rs b/daemon/src/setup_contract.rs index 940d565..21eb388 100644 --- a/daemon/src/setup_contract.rs +++ b/daemon/src/setup_contract.rs @@ -2,7 +2,7 @@ use crate::model::cfd::{Cet, Dlc, RevokedCommit, Role}; use crate::model::{Leverage, Price, Usd}; use crate::tokio_ext::FutureExt; use crate::wire::{ - Msg0, Msg1, Msg2, RollOverMsg, RollOverMsg0, RollOverMsg1, RollOverMsg2, SetupMsg, + Msg0, Msg1, Msg2, Msg3, RollOverMsg, RollOverMsg0, RollOverMsg1, RollOverMsg2, SetupMsg, }; use crate::{model, oracle, payout_curve, wallet}; use anyhow::{Context, Result}; @@ -231,6 +231,8 @@ pub async fn new( .merge(msg2.signed_lock) .context("Failed to merge lock PSBTs")?; + tracing::info!("Exchanged signed lock transaction"); + // TODO: In case we sign+send but never receive (the signed lock_tx from the other party) we // need some fallback handling (after x time) to spend the outputs in a different way so the // other party cannot hold us hostage @@ -271,7 +273,18 @@ pub async fn new( }) .collect::>>()?; - tracing::info!("Exchanged signed lock transaction"); + // TODO: Remove send- and receiving ACK messages once we are able to handle incomplete DLC + // monitoring + sink.send(SetupMsg::Msg3(Msg3)) + .await + .context("Failed to send Msg3")?; + let _ = stream + .select_next_some() + .timeout(Duration::from_secs(60)) + .await + .context("Expected Msg3 within 60 seconds")? + .try_into_msg3() + .context("Failed to read Msg3")?; Ok(Dlc { identity: sk, diff --git a/daemon/src/wire.rs b/daemon/src/wire.rs index 8979dd1..da4272f 100644 --- a/daemon/src/wire.rs +++ b/daemon/src/wire.rs @@ -209,6 +209,13 @@ pub enum SetupMsg { /// Upon receiving this message from the other party we merge our signature and then the lock /// tx is fully signed and can be published on chain. Msg2(Msg2), + /// Message acknowledging that we received everything + /// + /// Simple ACK message used at the end of the message exchange to ensure that both parties sent + /// and received everything and we did not run into timeouts on the other side. + /// This is used to avoid one party publishing the lock transaction while the other party ran + /// into a timeout. + Msg3(Msg3), } impl SetupMsg { @@ -235,6 +242,14 @@ impl SetupMsg { bail!("Not Msg2") } } + + pub fn try_into_msg3(self) -> Result { + if let Self::Msg3(v) = self { + Ok(v) + } else { + bail!("Not Msg3") + } + } } #[derive(Debug, Serialize, Deserialize)] @@ -334,6 +349,9 @@ pub struct Msg2 { pub signed_lock: PartiallySignedTransaction, // TODO: Use binary representation } +#[derive(Debug, Serialize, Deserialize)] +pub struct Msg3; + #[derive(Debug, Serialize, Deserialize)] #[serde(tag = "type", content = "payload")] pub enum RollOverMsg {