mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-02-22 06:21:40 +01:00
invoices: integrate settlement interceptor with invoice registry
This commit updates the invoice registry to utilize the settlement interceptor during the invoice settlement routine. It allows the interceptor to capture the invoice, providing interception clients an opportunity to determine the settlement outcome.
This commit is contained in:
parent
72abc94fe8
commit
12ad0cbf5a
4 changed files with 68 additions and 1 deletions
|
@ -1011,6 +1011,7 @@ func newMockRegistry(minDelta uint32) *mockInvoiceRegistry {
|
|||
panic(err)
|
||||
}
|
||||
|
||||
modifierMock := &invoices.MockHtlcModifier{}
|
||||
registry := invoices.NewRegistry(
|
||||
cdb,
|
||||
invoices.NewInvoiceExpiryWatcher(
|
||||
|
@ -1019,6 +1020,7 @@ func newMockRegistry(minDelta uint32) *mockInvoiceRegistry {
|
|||
),
|
||||
&invoices.RegistryConfig{
|
||||
FinalCltvRejectDelta: 5,
|
||||
HtlcModifier: modifierMock,
|
||||
},
|
||||
)
|
||||
registry.Start()
|
||||
|
|
|
@ -74,6 +74,11 @@ type RegistryConfig struct {
|
|||
// KeysendHoldTime indicates for how long we want to accept and hold
|
||||
// spontaneous keysend payments.
|
||||
KeysendHoldTime time.Duration
|
||||
|
||||
// HtlcModifier is a service that intercepts invoice HTLCs during the
|
||||
// settlement phase, enabling a subscribed client to modify certain
|
||||
// aspects of those HTLCs.
|
||||
HtlcModifier HtlcModifier
|
||||
}
|
||||
|
||||
// htlcReleaseEvent describes an htlc auto-release event. It is used to release
|
||||
|
@ -998,6 +1003,53 @@ func (i *InvoiceRegistry) notifyExitHopHtlcLocked(
|
|||
)
|
||||
|
||||
callback := func(inv *Invoice) (*InvoiceUpdateDesc, error) {
|
||||
// Provide the invoice to the settlement interceptor to allow
|
||||
// the interceptor's client an opportunity to manipulate the
|
||||
// settlement process.
|
||||
clientReq := HtlcModifyRequest{
|
||||
ExitHtlcCircuitKey: ctx.circuitKey,
|
||||
ExitHtlcAmt: ctx.amtPaid,
|
||||
ExitHtlcExpiry: ctx.expiry,
|
||||
CurrentHeight: uint32(ctx.currentHeight),
|
||||
Invoice: *inv,
|
||||
}
|
||||
interceptSession := i.cfg.HtlcModifier.Intercept(
|
||||
clientReq,
|
||||
)
|
||||
|
||||
// If the interceptor service has provided a response, we'll
|
||||
// use the interceptor session to wait for the client to respond
|
||||
// with a settlement resolution.
|
||||
var interceptErr error
|
||||
interceptSession.WhenSome(func(session InterceptSession) {
|
||||
log.Debug("Waiting for client response from invoice " +
|
||||
"HTLC interceptor session")
|
||||
|
||||
select {
|
||||
case resp := <-session.ClientResponseChannel:
|
||||
log.Debugf("Received invoice HTLC interceptor "+
|
||||
"response: %v", resp)
|
||||
|
||||
if resp.AmountPaid != 0 {
|
||||
ctx.amtPaid = resp.AmountPaid
|
||||
}
|
||||
|
||||
case err := <-session.ClientErrChannel:
|
||||
log.Errorf("Error from invoice HTLC "+
|
||||
"interceptor session: %v", err)
|
||||
|
||||
interceptErr = err
|
||||
|
||||
case <-session.Quit:
|
||||
// At this point, the interceptor session has
|
||||
// quit.
|
||||
}
|
||||
})
|
||||
if interceptErr != nil {
|
||||
return nil, fmt.Errorf("error during invoice HTLC "+
|
||||
"interception: %w", interceptErr)
|
||||
}
|
||||
|
||||
updateDesc, res, err := updateInvoice(ctx, inv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -1051,6 +1103,8 @@ func (i *InvoiceRegistry) notifyExitHopHtlcLocked(
|
|||
|
||||
var invoiceToExpire invoiceExpiry
|
||||
|
||||
log.Tracef("Settlement resolution: %T %v", resolution, resolution)
|
||||
|
||||
switch res := resolution.(type) {
|
||||
case *HtlcFailResolution:
|
||||
// Inspect latest htlc state on the invoice. If it is found,
|
||||
|
@ -1183,7 +1237,7 @@ func (i *InvoiceRegistry) notifyExitHopHtlcLocked(
|
|||
}
|
||||
|
||||
// Now that the links have been notified of any state changes to their
|
||||
// HTLCs, we'll go ahead and notify any clients wiaiting on the invoice
|
||||
// HTLCs, we'll go ahead and notify any clients waiting on the invoice
|
||||
// state changes.
|
||||
if updateSubscribers {
|
||||
// We'll add a setID onto the notification, but only if this is
|
||||
|
|
|
@ -23,6 +23,12 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var (
|
||||
// htlcModifierMock is a mock implementation of the invoice HtlcModifier
|
||||
// interface.
|
||||
htlcModifierMock = &invpkg.MockHtlcModifier{}
|
||||
)
|
||||
|
||||
// TestInvoiceRegistry is a master test which encompasses all tests using an
|
||||
// InvoiceDB instance. The purpose of this test is to be able to run all tests
|
||||
// with a custom DB instance, so that we can test the same logic with different
|
||||
|
@ -517,6 +523,7 @@ func testSettleHoldInvoice(t *testing.T,
|
|||
cfg := invpkg.RegistryConfig{
|
||||
FinalCltvRejectDelta: testFinalCltvRejectDelta,
|
||||
Clock: clock,
|
||||
HtlcModifier: htlcModifierMock,
|
||||
}
|
||||
|
||||
expiryWatcher := invpkg.NewInvoiceExpiryWatcher(
|
||||
|
@ -683,6 +690,7 @@ func testCancelHoldInvoice(t *testing.T,
|
|||
cfg := invpkg.RegistryConfig{
|
||||
FinalCltvRejectDelta: testFinalCltvRejectDelta,
|
||||
Clock: testClock,
|
||||
HtlcModifier: htlcModifierMock,
|
||||
}
|
||||
expiryWatcher := invpkg.NewInvoiceExpiryWatcher(
|
||||
cfg.Clock, 0, uint32(testCurrentHeight), nil, newMockNotifier(),
|
||||
|
@ -1200,6 +1208,7 @@ func testInvoiceExpiryWithRegistry(t *testing.T,
|
|||
cfg := invpkg.RegistryConfig{
|
||||
FinalCltvRejectDelta: testFinalCltvRejectDelta,
|
||||
Clock: testClock,
|
||||
HtlcModifier: htlcModifierMock,
|
||||
}
|
||||
|
||||
expiryWatcher := invpkg.NewInvoiceExpiryWatcher(
|
||||
|
@ -1310,6 +1319,7 @@ func testOldInvoiceRemovalOnStart(t *testing.T,
|
|||
FinalCltvRejectDelta: testFinalCltvRejectDelta,
|
||||
Clock: testClock,
|
||||
GcCanceledInvoicesOnStartup: true,
|
||||
HtlcModifier: htlcModifierMock,
|
||||
}
|
||||
|
||||
expiryWatcher := invpkg.NewInvoiceExpiryWatcher(
|
||||
|
|
|
@ -143,6 +143,7 @@ func defaultRegistryConfig() invpkg.RegistryConfig {
|
|||
return invpkg.RegistryConfig{
|
||||
FinalCltvRejectDelta: testFinalCltvRejectDelta,
|
||||
HtlcHoldDuration: 30 * time.Second,
|
||||
HtlcModifier: &invpkg.MockHtlcModifier{},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue