Skip to content

Commit

Permalink
chore: allow calling settle and cancel multiple times
Browse files Browse the repository at this point in the history
  • Loading branch information
michael1011 committed Oct 18, 2024
1 parent 2e19ee2 commit 8d3d88c
Show file tree
Hide file tree
Showing 7 changed files with 317 additions and 279 deletions.
8 changes: 4 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ rcgen = { version = "0.13.1", features = ["x509-parser"] }
tokio = { version = "1.40.0", features = ["macros", "rt-multi-thread", "sync"] }
tonic = { version = "0.12.3", features = ["prost", "tls", "gzip", "zstd"] }
serde = { version = "1.0.210", features = ["derive"] }
serde_json = { version = "1.0.128", features = ["preserve_order"] }
serde_json = { version = "1.0.129", features = ["preserve_order"] }
lightning-invoice = { version = "0.32.0", features = ["std"] }
chrono = { version = "0.4.38", features = ["serde"] }
bitcoin = { version = "0.32.3", features = ["rand-std"] }
Expand All @@ -34,7 +34,7 @@ hex = "0.4.3"
tokio-util = "0.7.12"

[build-dependencies]
built = { version = "0.7.4", features = ["git2"] }
built = { version = "0.7.5", features = ["git2"] }
tonic-build = "0.12.3"

[dev-dependencies]
Expand Down
12 changes: 11 additions & 1 deletion src/database/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ impl InvoiceState {
}

pub fn validate_transition(&self, new_state: InvoiceState) -> Result<(), StateTransitionError> {
if self.is_final() {
if self.is_final() && *self != new_state {
return Err(StateTransitionError::IsFinal(*self));
}

Expand Down Expand Up @@ -320,6 +320,16 @@ mod test {
);
}

#[test]
fn invoice_state_validate_transition_final_same_state() {
assert!(InvoiceState::Paid
.validate_transition(InvoiceState::Paid)
.is_ok());
assert!(InvoiceState::Cancelled
.validate_transition(InvoiceState::Cancelled)
.is_ok());
}

#[test]
fn invoice_state_validate_transition_invalid() {
assert_eq!(
Expand Down
25 changes: 16 additions & 9 deletions src/settler.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::database::helpers::invoice_helper::InvoiceHelper;
use crate::database::model::{Invoice, InvoiceState};
use crate::database::model::{HoldInvoice, Invoice, InvoiceState};
use crate::hooks::{FailureMessage, HtlcCallbackResponse};
use anyhow::Result;
use log::{info, trace, warn};
Expand Down Expand Up @@ -147,6 +147,10 @@ where
payment_hash: &Vec<u8>,
payment_preimage: &Vec<u8>,
) -> Result<()> {
if self.get_invoice(payment_hash)?.invoice.state == InvoiceState::Paid.to_string() {
return Ok(());
}

let htlcs = match self.pending_htlcs.lock().await.remove(payment_hash) {
Some(res) => res,
None => {
Expand Down Expand Up @@ -321,14 +325,7 @@ where
payment_hash: &[u8],
state: InvoiceState,
) -> Result<(i64, String)> {
let invoice = match self.invoice_helper.get_by_payment_hash(payment_hash) {
Ok(opt) => match opt {
Some(invoice) => invoice,
None => return Err(SettleError::InvoiceNotFound.into()),
},
Err(err) => return Err(SettleError::DatabaseFetchError(err).into()),
};

let invoice = self.get_invoice(payment_hash)?;
let current_state = InvoiceState::try_from(&invoice.invoice.state)?;

if let Err(err) =
Expand All @@ -347,4 +344,14 @@ where

Ok((invoice.invoice.id, invoice.invoice.bolt11))
}

fn get_invoice(&self, payment_hash: &[u8]) -> Result<HoldInvoice> {
match self.invoice_helper.get_by_payment_hash(payment_hash) {
Ok(opt) => match opt {
Some(invoice) => Ok(invoice),
None => Err(SettleError::InvoiceNotFound.into()),
},
Err(err) => Err(SettleError::DatabaseFetchError(err).into()),
}
}
}
6 changes: 6 additions & 0 deletions tests-regtest/hold/regtest_rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ def test_settle(self) -> None:
assert len(htlcs) == 1
assert htlcs[0]["state"] == "paid"

# Settling again should not error
assert lightning("settleholdinvoice", preimage) == {}

def test_cancel(self) -> None:
(_, payment_hash) = new_preimage()
invoice = lightning("holdinvoice", payment_hash, "1000")["bolt11"]
Expand All @@ -115,3 +118,6 @@ def test_cancel(self) -> None:
htlcs = data["htlcs"]
assert len(htlcs) == 1
assert htlcs[0]["state"] == "cancelled"

# Cancelling again should not error
assert lightning("cancelholdinvoice", payment_hash) == {}
Loading

0 comments on commit 8d3d88c

Please sign in to comment.