Skip to content

Commit

Permalink
feat: Cancel hodl invoice if dlc proposal fails
Browse files Browse the repository at this point in the history
  • Loading branch information
holzeis committed May 31, 2024
1 parent 24a27f6 commit 73164d9
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 61 deletions.
21 changes: 8 additions & 13 deletions coordinator/src/db/hodl_invoice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use diesel::AsExpression;
use diesel::ExpressionMethods;
use diesel::FromSqlRow;
use diesel::PgConnection;
use diesel::QueryDsl;
use diesel::QueryResult;
use diesel::RunQueryDsl;
use std::any::TypeId;
Expand Down Expand Up @@ -53,6 +54,13 @@ pub fn create_hodl_invoice(
Ok(())
}

pub fn get_r_hash_by_order_id(conn: &mut PgConnection, order_id: Uuid) -> QueryResult<String> {
hodl_invoices::table
.filter(hodl_invoices::order_id.eq(order_id))
.select(hodl_invoices::r_hash)
.get_result(conn)
}

pub fn update_hodl_invoice_to_accepted(
conn: &mut PgConnection,
hash: &str,
Expand Down Expand Up @@ -87,19 +95,6 @@ pub fn update_hodl_invoice_to_settled(
.get_result(conn)
}

pub fn update_hodl_invoice_to_failed(
conn: &mut PgConnection,
order_id: Uuid,
) -> QueryResult<usize> {
diesel::update(hodl_invoices::table)
.filter(hodl_invoices::order_id.eq(order_id))
.set((
hodl_invoices::updated_at.eq(OffsetDateTime::now_utc()),
hodl_invoices::invoice_state.eq(InvoiceState::Failed),
))
.execute(conn)
}

pub fn update_hodl_invoice_to_failed_by_r_hash(
conn: &mut PgConnection,
r_hash: String,
Expand Down
73 changes: 29 additions & 44 deletions coordinator/src/trade/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,17 @@ impl TradeExecutor {
if params.external_funding.is_some() {
// The channel was funded externally. We need to post process the dlc channel
// offer.
if let Err(e) = self.post_process_proposal(trader_id, order_id).await {
if let Err(e) = self.settle_invoice(trader_id, order_id).await {
tracing::error!(%trader_id, %order_id, "Failed to settle invoice with provided pre_image. Cancelling offer. Error: {e:#}");

if let Err(e) = self.cancel_offer(trader_id).await {
tracing::error!(%trader_id, %order_id, "Failed to cancel offer. Error: {e:#}");
}

if let Err(e) = self.cancel_hodl_invoice(order_id).await {
tracing::error!(%trader_id, %order_id, "Failed to cancel hodl invoice. Error: {e:#}");
}

let message = OrderbookMessage::TraderMessage {
trader_id,
message: Message::TradeError {
Expand Down Expand Up @@ -183,20 +193,8 @@ impl TradeExecutor {
tracing::error!(%trader_id, %order_id, "Failed to cancel offer. Error: {e:#}");
}

// if the order was externally funded we need to set the hodl invoice to failed.
if let Err(e) = spawn_blocking({
let pool = self.node.pool.clone();
move || {
let mut conn = pool.get()?;
db::hodl_invoice::update_hodl_invoice_to_failed(&mut conn, order_id)?;

anyhow::Ok(())
}
})
.await
.expect("task to finish")
{
tracing::error!(%trader_id, %order_id, "Failed to set hodl invoice to failed. Error: {e:#}");
if let Err(e) = self.cancel_hodl_invoice(order_id).await {
tracing::error!(%trader_id, %order_id, "Failed to cancel hodl_invoice. Error: {e:#}");
}
}

Expand All @@ -221,35 +219,6 @@ impl TradeExecutor {
};
}

async fn post_process_proposal(&self, trader: PublicKey, order_id: Uuid) -> Result<()> {
match self.settle_invoice(trader, order_id).await {
Ok(()) => Ok(()),
Err(e) => {
tracing::error!(%trader, %order_id, "Failed to settle invoice with provided pre_image. Cancelling offer. Error: {e:#}");

if let Err(e) = self.cancel_offer(trader).await {
tracing::error!(%trader, %order_id, "Failed to cancel offer. Error: {e:#}");
}

if let Err(e) = spawn_blocking({
let pool = self.node.pool.clone();
move || {
let mut conn = pool.get()?;
db::hodl_invoice::update_hodl_invoice_to_failed(&mut conn, order_id)?;

anyhow::Ok(())
}
})
.await
.expect("task to finish")
{
tracing::error!(%trader, %order_id, "Failed to set hodl invoice to failed. Error: {e:#}");
}
Err(e)
}
}
}

/// Settles the accepted invoice for the given trader
async fn settle_invoice(&self, trader: PublicKey, order_id: Uuid) -> Result<()> {
let pre_image = spawn_blocking({
Expand Down Expand Up @@ -305,6 +274,22 @@ impl TradeExecutor {
Ok(())
}

pub async fn cancel_hodl_invoice(&self, order_id: Uuid) -> Result<()> {
// if the order was externally funded we need to set the hodl invoice to failed.
let r_hash = spawn_blocking({
let pool = self.node.pool.clone();
move || {
let mut conn = pool.get()?;
let r_hash = db::hodl_invoice::get_r_hash_by_order_id(&mut conn, order_id)?;

anyhow::Ok(r_hash)
}
})
.await??;

self.node.lnd_bridge.cancel_invoice(r_hash).await
}

/// Execute a trade action according to the coordinator's current trading status with the
/// trader.
///
Expand Down
4 changes: 2 additions & 2 deletions crates/lnd-bridge/examples/cancel_invoice_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ async fn main() -> Result<()> {
let macaroon = "[enter macroon here]".to_string();
let lnd_bridge = lnd_bridge::LndBridge::new("localhost:18080".to_string(), macaroon, false);

let payment_hash = "".to_string();
lnd_bridge.cancel_invoice(payment_hash).await?;
let r_hash = "".to_string();
lnd_bridge.cancel_invoice(r_hash).await?;

Ok(())
}
6 changes: 4 additions & 2 deletions crates/lnd-bridge/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ impl LndBridge {
Ok(invoice)
}

pub async fn cancel_invoice(&self, payment_hash: String) -> Result<()> {
pub async fn cancel_invoice(&self, r_hash: String) -> Result<()> {
let builder = self.client.request(
Method::POST,
format!(
Expand All @@ -163,7 +163,9 @@ impl LndBridge {
let resp = builder
.header("content-type", "application/json")
.header("Grpc-Metadata-macaroon", self.macaroon.clone())
.json(&CancelInvoice { payment_hash })
.json(&CancelInvoice {
payment_hash: r_hash,
})
.send()
.await?;

Expand Down

0 comments on commit 73164d9

Please sign in to comment.