Skip to content

Commit

Permalink
feat: Recover from pending offer
Browse files Browse the repository at this point in the history
  • Loading branch information
holzeis committed Jan 16, 2024
1 parent 5b5a937 commit 2c03f3c
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 10 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Feat: made sure that rollover works with dlc-channels
- Fix: correctly remember reserved utxos and don't accidentally double spend
- Feat: Allow recovering from a stuck protocol state by resending last outbound dlc message on connect
- Feat: Allow continuing from an offered dlc channel state (offered, settle offered and collab close offered)

## [1.7.4] - 2023-12-20

Expand Down
21 changes: 19 additions & 2 deletions coordinator/src/dlc_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ use bitcoin::secp256k1::PublicKey;
use diesel::r2d2::ConnectionManager;
use diesel::r2d2::Pool;
use diesel::PgConnection;
use dlc_manager::channel::signed_channel::SignedChannel;
use dlc_manager::channel::signed_channel::SignedChannelState;
use dlc_manager::channel::Channel;
use dlc_messages::Message;
use futures::future::RemoteHandle;
use futures::FutureExt;
Expand Down Expand Up @@ -99,10 +102,24 @@ impl DlcHandler {
}

pub fn on_connect(&self, peer: PublicKey) -> Result<()> {
tracing::debug!(%peer, "Connected to peer, resending last dlc message!");
if let Some(Channel::Signed(SignedChannel {
channel_id,
state: SignedChannelState::CollaborativeCloseOffered { .. },
..
})) = self.node.list_dlc_channels()?.first()
{
tracing::info!("Accepting pending dlc channel close offer.");
// Pending dlc channel close offer with the intend to close the dlc channel
// on-chain

// TODO(bonomat): we should verify that the proposed amount is acceptable
self.node
.accept_dlc_channel_collaborative_close(channel_id)?;

return Ok(());
}

let mut conn = self.pool.get()?;

let last_serialized_message = db::last_outbound_dlc_message::get(&mut conn, &peer)?;

if let Some(last_serialized_message) = last_serialized_message {
Expand Down
2 changes: 1 addition & 1 deletion coordinator/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -688,7 +688,7 @@ impl Node {

// TODO(bonomat): we should verify that the proposed amount is acceptable
self.inner
.accept_dlc_channel_collaborative_close(close_offer.channel_id)?;
.accept_dlc_channel_collaborative_close(&close_offer.channel_id)?;
}
ChannelMessage::Accept(accept_channel) => {
let channel_id_hex_string = accept_channel.temporary_channel_id.to_hex();
Expand Down
8 changes: 4 additions & 4 deletions crates/ln-dlc-node/src/node/dlc_channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,27 +266,27 @@ impl<S: TenTenOneStorage + 'static, N: LnDlcStorage + Sync + Send + 'static> Nod
.await?
}

pub fn accept_dlc_channel_collaborative_close(&self, channel_id: DlcChannelId) -> Result<()> {
pub fn accept_dlc_channel_collaborative_close(&self, channel_id: &DlcChannelId) -> Result<()> {
let channel_id_hex = hex::encode(channel_id);

tracing::info!(channel_id = %channel_id_hex, "Accepting DLC channel collaborative close offer");

let dlc_manager = self.dlc_manager.clone();
dlc_manager.accept_collaborative_close(&channel_id)?;
dlc_manager.accept_collaborative_close(channel_id)?;

Ok(())
}

pub fn accept_dlc_channel_collaborative_settlement(
&self,
channel_id: DlcChannelId,
channel_id: &DlcChannelId,
) -> Result<()> {
let channel_id_hex = hex::encode(channel_id);

tracing::info!(channel_id = %channel_id_hex, "Accepting DLC channel collaborative settlement");

let dlc_manager = self.dlc_manager.clone();
let (settle_offer, counterparty_pk) = dlc_manager.accept_settle_offer(&channel_id)?;
let (settle_offer, counterparty_pk) = dlc_manager.accept_settle_offer(channel_id)?;

self.event_handler.publish(NodeEvent::SendDlcMessage {
peer: counterparty_pk,
Expand Down
4 changes: 2 additions & 2 deletions crates/ln-dlc-node/src/tests/dlc_channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ async fn can_open_and_collaboratively_close_channel() {

tracing::debug!("Accepting collaborative close offer");

app.accept_dlc_channel_collaborative_close(coordinator_signed_channel.channel_id)
app.accept_dlc_channel_collaborative_close(&coordinator_signed_channel.channel_id)
.unwrap();

wait_until(Duration::from_secs(10), || async {
Expand Down Expand Up @@ -312,7 +312,7 @@ async fn setup_channel_with_position() -> (
.unwrap();

tracing::debug!("Accepting settle offer and waiting for being settled...");
app.accept_dlc_channel_collaborative_settlement(app_signed_channel.channel_id)
app.accept_dlc_channel_collaborative_settlement(&app_signed_channel.channel_id)
.unwrap();

wait_until(Duration::from_secs(10), || async {
Expand Down
64 changes: 64 additions & 0 deletions mobile/native/src/dlc_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ use ln_dlc_node::dlc_message::DlcMessage;
use ln_dlc_node::dlc_message::SerializedDlcMessage;
use ln_dlc_node::node::dlc_channel::send_dlc_message;
use ln_dlc_node::node::event::NodeEvent;
use ln_dlc_node::node::rust_dlc_manager::channel::offered_channel::OfferedChannel;
use ln_dlc_node::node::rust_dlc_manager::channel::signed_channel::SignedChannel;
use ln_dlc_node::node::rust_dlc_manager::channel::signed_channel::SignedChannelState;
use ln_dlc_node::node::rust_dlc_manager::channel::Channel;
use ln_dlc_node::node::Node;
use std::sync::Arc;
use tokio::sync::broadcast;
Expand Down Expand Up @@ -82,6 +86,66 @@ impl DlcHandler {
}

pub fn on_connect(&self, peer: PublicKey) -> Result<()> {
if let Some(channel) = self.node.list_dlc_channels()?.first() {
match channel {
Channel::Offered(OfferedChannel {
temporary_channel_id,
..
}) => {
tracing::info!("Accepting pending dlc channel offer.");
// Pending dlc channel offer not yet confirmed on-chain
if let Err(e) = self.node.accept_dlc_channel_offer(temporary_channel_id) {
tracing::error!("Failed to accept pending dlc channel offer. {e:#}");
tracing::warn!("Rejecting pending dlc channel offer!");
self.node.reject_dlc_channel_offer(temporary_channel_id)?;
}

return Ok(());
}
Channel::Signed(SignedChannel {
channel_id,
state: SignedChannelState::SettledOffered { .. },
..
}) => {
tracing::info!("Accepting pending dlc channel settle offer.");
// Pending dlc channel settle offer with a dlc channel already confirmed
// on-chain
self.node
.accept_dlc_channel_collaborative_settlement(channel_id)?;

return Ok(());
}
Channel::Signed(SignedChannel {
channel_id: _,
state: SignedChannelState::RenewOffered { .. },
..
}) => {
// Pending dlc channel renew (resize) offer with a dlc channel already confirmed
// on-chain

// TODO: implement with resizing a position.

return Ok(());
}
Channel::Signed(SignedChannel {
channel_id,
state: SignedChannelState::CollaborativeCloseOffered { .. },
..
}) => {
tracing::info!("Accepting pending dlc channel close offer.");
// Pending dlc channel close offer with the intend to close the dlc channel
// on-chain

// TODO(bonomat): we should verify that the proposed amount is acceptable
self.node
.accept_dlc_channel_collaborative_close(channel_id)?;

return Ok(());
}
_ => {}
}
}

let mut conn = db::connection()?;
let last_outbound_serialized_dlc_message =
db::last_outbound_dlc_messages::LastOutboundDlcMessage::get(&mut conn, &peer)?;
Expand Down
2 changes: 1 addition & 1 deletion mobile/native/src/ln_dlc/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ impl Node {
}
ChannelMessage::SettleOffer(offer) => {
self.inner
.accept_dlc_channel_collaborative_settlement(offer.channel_id)
.accept_dlc_channel_collaborative_settlement(&offer.channel_id)
.with_context(|| {
format!(
"Failed to accept DLC channel close offer for channel {}",
Expand Down

0 comments on commit 2c03f3c

Please sign in to comment.