From 57ad8a645a4a8b709ca9f425e6de56ee58d3b63b Mon Sep 17 00:00:00 2001 From: Daniel Karzel Date: Fri, 26 Nov 2021 14:21:10 +1100 Subject: [PATCH] Add acknowledge message at the end of contract setup This is to avoid going on chain in a scenario where one party sent the signed lock transaction, but did not get the signed transaction from the other party before running into the timeout. With this solution, we fail the setup (on either side) if we don't receive an acknowledgment message at the end of the setup. The acknoledge message is a temporary fix. Once we add monitoring for incomplete DLCs (special case of contract-setup / rollover / collaborative-settlement failing) the ack message should be removed. --- daemon/src/setup_contract.rs | 17 +++++++++++++++-- daemon/src/wire.rs | 18 ++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) 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 {