Skip to content

Commit 2580661

Browse files
ffranrguggero
authored andcommitted
invoicesrpc: add HtlcModifier RPC endpoint and modifier RPC server
This commit introduces a singleton invoice HTLC modifier RPC server and an endpoint to activate it. The server interfaces with the internal invoice HTLC modifier interpreter, handling the marshalling between RPC types and internal formats.
1 parent 73f52c8 commit 2580661

File tree

11 files changed

+2162
-1342
lines changed

11 files changed

+2162
-1342
lines changed

lnrpc/invoicesrpc/htlc_modifier.go

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
package invoicesrpc
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/btcsuite/btcd/chaincfg"
7+
"github.com/lightningnetwork/lnd/invoices"
8+
"github.com/lightningnetwork/lnd/lnwire"
9+
)
10+
11+
// htlcModifierConfig contains the configuration for an RPC invoice HTLC
12+
// modifier server.
13+
type htlcModifierConfig struct {
14+
// chainParams is required to properly marshall an invoice for RPC.
15+
chainParams *chaincfg.Params
16+
17+
// serverStream is a bidirectional RPC server stream to send invoices to
18+
// a client and receive accept responses from the client.
19+
serverStream Invoices_HtlcModifierServer
20+
21+
// modificationInterceptor is the HTLC modification interceptor that
22+
// will be used to intercept and resolve invoice HTLCs.
23+
modificationInterceptor invoices.HtlcModifier
24+
}
25+
26+
// htlcModifier is a helper struct that handles the lifecycle of an RPC invoice
27+
// HTLC modifier server instance.
28+
//
29+
// This struct handles passing send and receive RPC messages between the client
30+
// and the invoice service.
31+
type htlcModifier struct {
32+
// cfg contains the configuration for the invoice HTLC modifier.
33+
cfg htlcModifierConfig
34+
}
35+
36+
// newHtlcModifier creates a new RPC invoice HTLC modifier handler.
37+
func newHtlcModifier(cfg htlcModifierConfig) *htlcModifier {
38+
return &htlcModifier{
39+
cfg: cfg,
40+
}
41+
}
42+
43+
// run sends the intercepted invoice HTLCs to the client and receives the
44+
// corresponding responses.
45+
func (r *htlcModifier) run() error {
46+
// Register our invoice modifier.
47+
r.cfg.modificationInterceptor.SetClientCallback(r.onIntercept)
48+
defer r.cfg.modificationInterceptor.SetClientCallback(nil)
49+
50+
// Listen for a response from the client in a loop.
51+
for {
52+
resp, err := r.cfg.serverStream.Recv()
53+
if err != nil {
54+
return err
55+
}
56+
57+
log.Tracef("Received invoice HTLC modifier response %v", resp)
58+
59+
if err := r.resolveFromClient(resp); err != nil {
60+
return err
61+
}
62+
}
63+
}
64+
65+
// onIntercept is called when an invoice HTLC is intercepted by the invoice HTLC
66+
// modifier. This method sends the invoice and the current HTLC to the client.
67+
func (r *htlcModifier) onIntercept(req invoices.HtlcModifyRequest) error {
68+
// Convert the circuit key to an RPC circuit key.
69+
rpcCircuitKey := &CircuitKey{
70+
ChanId: req.ExitHtlcCircuitKey.ChanID.ToUint64(),
71+
HtlcId: req.ExitHtlcCircuitKey.HtlcID,
72+
}
73+
74+
// Convert the invoice to an RPC invoice.
75+
rpcInvoice, err := CreateRPCInvoice(&req.Invoice, r.cfg.chainParams)
76+
if err != nil {
77+
return err
78+
}
79+
80+
return r.cfg.serverStream.Send(&HtlcModifyRequest{
81+
Invoice: rpcInvoice,
82+
ExitHtlcCircuitKey: rpcCircuitKey,
83+
ExitHtlcAmt: uint64(req.ExitHtlcAmt),
84+
ExitHtlcExpiry: req.ExitHtlcExpiry,
85+
CurrentHeight: req.CurrentHeight,
86+
ExitHtlcWireCustomRecords: req.WireCustomRecords,
87+
})
88+
}
89+
90+
// resolveFromClient handles an invoice HTLC modification received from the
91+
// client.
92+
func (r *htlcModifier) resolveFromClient(
93+
in *HtlcModifyResponse) error {
94+
95+
log.Tracef("Resolving invoice HTLC modifier response %v", in)
96+
97+
if in.CircuitKey == nil {
98+
return fmt.Errorf("missing circuit key")
99+
}
100+
101+
circuitKey := invoices.CircuitKey{
102+
ChanID: lnwire.NewShortChanIDFromInt(in.CircuitKey.ChanId),
103+
HtlcID: in.CircuitKey.HtlcId,
104+
}
105+
106+
// Pass the resolution to the modifier.
107+
return r.cfg.modificationInterceptor.Modify(
108+
circuitKey, lnwire.MilliSatoshi(in.AmtPaid),
109+
)
110+
}

0 commit comments

Comments
 (0)