Skip to content

Commit

Permalink
SECURITY FIX: do not cancel hodl invoice on payment error
Browse files Browse the repository at this point in the history
Under some unusual circumstances the `PayInvoice` function can return an error when the payment has been settled.  In these cases it is extremely important not to cancel the hodl invoice since manual recovery is not possible if the hodl invoice is canceled.

Also increases the default `CltvDeltaAlpha` to allow a longer window for manual recovery in the case of an error.
  • Loading branch information
lnproxy authored Sep 13, 2023
1 parent 7ccf669 commit f8942bb
Showing 1 changed file with 9 additions and 14 deletions.
23 changes: 9 additions & 14 deletions relay.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,13 @@ func NewRelay(ln lnc.LN) *Relay {
RoutingBudgetBeta: 1_500_000,
RoutingFeeBaseMsat: 1000,
RoutingFeePPM: 1000,
CltvDeltaAlpha: 3,
CltvDeltaAlpha: 144,
CltvDeltaBeta: 1_500_000,
// Should be set to at most the node's `--max-cltv-expiry` setting (default: 2016)
MaxCltvDelta: 1800,
MinCltvDelta: 120,
// Should be set so that CltvDeltaAlpha blocks are very unlikely to be added before timeout
PaymentTimeout: 120,
PaymentTimeout: 600,
PaymentTimePreference: 0.9,
},
LN: ln,
Expand Down Expand Up @@ -194,21 +194,23 @@ func (relay *Relay) OpenCircuit(x ProxyParameters) (string, error) {
func (relay *Relay) circuitSwitch(hash []byte, invoice string, fee_budget_msat, cltv_limit uint64) {
defer relay.WaitGroup.Done()
log.Println("opened circuit for:", invoice, hex.EncodeToString(hash))
var preimage []byte
_, err := relay.LN.WatchInvoice(hash)
if err != nil {
log.Println("error while watching wrapped invoice:", hex.EncodeToString(hash), err)
goto cleanup
err = relay.LN.CancelInvoice(hash)
if err != nil {
log.Println("error while canceling invoice:", hash, err)
}
return
}
preimage, err = relay.LN.PayInvoice(lnc.PaymentParameters{
preimage, err := relay.LN.PayInvoice(lnc.PaymentParameters{
Invoice: invoice,
TimeoutSeconds: relay.PaymentTimeout,
FeeLimitMsat: fee_budget_msat,
CltvLimit: cltv_limit,
})
if err != nil {
log.Println("error paying original invoice:", hex.EncodeToString(hash), err)
goto cleanup
log.Panicln("error paying original invoice:", hex.EncodeToString(hash), err)
}
log.Println("preimage:", hex.EncodeToString(preimage), hex.EncodeToString(hash))
err = relay.LN.SettleInvoice(preimage)
Expand All @@ -217,11 +219,4 @@ func (relay *Relay) circuitSwitch(hash []byte, invoice string, fee_budget_msat,
}
log.Println("circuit settled")
return

cleanup:
err = relay.LN.CancelInvoice(hash)
if err != nil {
log.Println("error while canceling invoice:", hash, err)
}
return
}

0 comments on commit f8942bb

Please sign in to comment.