lnd/lnrpc/invoicesrpc/htlc_modifier.go
ffranr 1975fa60e2
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.
2024-09-19 09:21:37 +02:00

87 lines
2.4 KiB
Go

package invoicesrpc
import (
"fmt"
"github.com/btcsuite/btcd/chaincfg"
"github.com/lightningnetwork/lnd/invoices"
"github.com/lightningnetwork/lnd/lnwire"
)
// htlcModifier is a helper struct that handles the lifecycle of an RPC invoice
// HTLC modifier server instance.
//
// This struct handles passing send and receive RPC messages between the client
// and the invoice service.
type htlcModifier struct {
// chainParams is required to properly marshall an invoice for RPC.
chainParams *chaincfg.Params
// serverStream is a bidirectional RPC server stream to send invoices to
// a client and receive accept responses from the client.
serverStream Invoices_HtlcModifierServer
}
// newHtlcModifier creates a new RPC invoice HTLC modifier handler.
func newHtlcModifier(params *chaincfg.Params,
serverStream Invoices_HtlcModifierServer) *htlcModifier {
return &htlcModifier{
chainParams: params,
serverStream: serverStream,
}
}
// onIntercept is called when an invoice HTLC is intercepted by the invoice HTLC
// modifier. This method sends the invoice and the current HTLC to the client.
func (r *htlcModifier) onIntercept(
req invoices.HtlcModifyRequest) (*invoices.HtlcModifyResponse, error) {
// Convert the circuit key to an RPC circuit key.
rpcCircuitKey := &CircuitKey{
ChanId: req.ExitHtlcCircuitKey.ChanID.ToUint64(),
HtlcId: req.ExitHtlcCircuitKey.HtlcID,
}
// Convert the invoice to an RPC invoice.
rpcInvoice, err := CreateRPCInvoice(&req.Invoice, r.chainParams)
if err != nil {
return nil, err
}
// Send the modification request to the client.
err = r.serverStream.Send(&HtlcModifyRequest{
Invoice: rpcInvoice,
ExitHtlcCircuitKey: rpcCircuitKey,
ExitHtlcAmt: uint64(req.ExitHtlcAmt),
ExitHtlcExpiry: req.ExitHtlcExpiry,
CurrentHeight: req.CurrentHeight,
ExitHtlcWireCustomRecords: req.WireCustomRecords,
})
if err != nil {
return nil, err
}
// Then wait for the client to respond.
resp, err := r.serverStream.Recv()
if err != nil {
return nil, err
}
if resp.CircuitKey == nil {
return nil, fmt.Errorf("missing circuit key")
}
log.Tracef("Resolving invoice HTLC modifier response %v", resp)
// Pass the resolution to the modifier.
var amtPaid lnwire.MilliSatoshi
if resp.AmtPaid != nil {
amtPaid = lnwire.MilliSatoshi(*resp.AmtPaid)
}
return &invoices.HtlcModifyResponse{
AmountPaid: amtPaid,
}, nil
}