invoicesrpc: add InvoiceAcceptor RPC endpoint and acceptor RPC server

This commit introduces a singleton invoice acceptor RPC server and
an endpoint to activate it. The server interfaces with the internal
invoice settlement interpreter, handling the marshalling between RPC
types and internal formats.

Named "acceptor," it allows clients to accept invoice settlements, but
not to reject them.
This commit is contained in:
ffranr 2024-04-23 14:58:29 +01:00 committed by Oliver Gugger
parent 260b7a7af4
commit 3b8a3fac10
No known key found for this signature in database
GPG Key ID: 8E4256593F177720
6 changed files with 651 additions and 55 deletions

View File

@ -0,0 +1,111 @@
package invoicesrpc
import (
"github.com/btcsuite/btcd/chaincfg"
"github.com/lightningnetwork/lnd/invoices"
"github.com/lightningnetwork/lnd/lntypes"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
// invoiceAcceptorConfig contains the configuration for an RPC invoice acceptor
// server.
type invoiceAcceptorConfig struct {
// chainParams is required to properly marshall an invoice for RPC.
chainParams *chaincfg.Params
// rpcServer is a bidirectional RPC server to send invoices to a client
// and receive accept responses from the client.
rpcServer Invoices_InvoiceAcceptorServer
// interceptor is the invoice interceptor that will be used to intercept
// and resolve invoices.
interceptor invoices.SettlementInterceptorInterface
}
// invoiceAcceptor is a helper struct that handles the lifecycle of an RPC
// invoice acceptor server instance.
//
// This struct handles passing send and receive RPC messages between the client
// and the invoice service.
type invoiceAcceptor struct {
// cfg contains the configuration for the invoice acceptor.
cfg invoiceAcceptorConfig
}
// newInvoiceAcceptor creates a new RPC invoice acceptor handler.
func newInvoiceAcceptor(cfg invoiceAcceptorConfig) *invoiceAcceptor {
return &invoiceAcceptor{
cfg: cfg,
}
}
// run sends the intercepted invoices to the client and receives the
// corresponding responses.
func (r *invoiceAcceptor) run() error {
// Register our invoice interceptor.
r.cfg.interceptor.SetClientCallback(r.onIntercept)
defer r.cfg.interceptor.SetClientCallback(nil)
// Listen for a response from the client in a loop.
for {
resp, err := r.cfg.rpcServer.Recv()
if err != nil {
return err
}
if err := r.resolveFromClient(resp); err != nil {
return err
}
}
}
// onIntercept is called when an invoice is intercepted by the invoice
// interceptor. This method sends the invoice to the client.
func (r *invoiceAcceptor) onIntercept(
req invoices.InterceptClientRequest) 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.cfg.chainParams)
if err != nil {
return err
}
return r.cfg.rpcServer.Send(&InvoiceAcceptorRequest{
Invoice: rpcInvoice,
ExitHtlcCircuitKey: rpcCircuitKey,
ExitHtlcAmt: uint64(req.ExitHtlcAmt),
ExitHtlcExpiry: req.ExitHtlcExpiry,
CurrentHeight: req.CurrentHeight,
})
}
// resolveFromClient handles an invoice resolution received from the client.
func (r *invoiceAcceptor) resolveFromClient(
in *InvoiceAcceptorResponse) error {
log.Tracef("Resolving invoice acceptor response %v", in)
// Parse the invoice preimage from the response.
if len(in.Preimage) != lntypes.HashSize {
return status.Errorf(codes.InvalidArgument,
"Preimage has invalid length: %d", len(in.Preimage))
}
preimage, err := lntypes.MakePreimage(in.Preimage)
if err != nil {
return status.Errorf(codes.InvalidArgument,
"Preimage is invalid: %v", err)
}
// Derive the payment hash from the preimage.
paymentHash := preimage.Hash()
// Pass the resolution to the interceptor.
return r.cfg.interceptor.Resolve(paymentHash, in.SkipAmountCheck)
}

View File

@ -617,6 +617,212 @@ func (*LookupInvoiceMsg_PaymentAddr) isLookupInvoiceMsg_InvoiceRef() {}
func (*LookupInvoiceMsg_SetId) isLookupInvoiceMsg_InvoiceRef() {}
// CircuitKey is a unique identifier for an HTLC.
type CircuitKey struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// / The id of the channel that the is part of this circuit.
ChanId uint64 `protobuf:"varint,1,opt,name=chan_id,json=chanId,proto3" json:"chan_id,omitempty"`
// / The index of the incoming htlc in the incoming channel.
HtlcId uint64 `protobuf:"varint,2,opt,name=htlc_id,json=htlcId,proto3" json:"htlc_id,omitempty"`
}
func (x *CircuitKey) Reset() {
*x = CircuitKey{}
if protoimpl.UnsafeEnabled {
mi := &file_invoicesrpc_invoices_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *CircuitKey) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CircuitKey) ProtoMessage() {}
func (x *CircuitKey) ProtoReflect() protoreflect.Message {
mi := &file_invoicesrpc_invoices_proto_msgTypes[8]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CircuitKey.ProtoReflect.Descriptor instead.
func (*CircuitKey) Descriptor() ([]byte, []int) {
return file_invoicesrpc_invoices_proto_rawDescGZIP(), []int{8}
}
func (x *CircuitKey) GetChanId() uint64 {
if x != nil {
return x.ChanId
}
return 0
}
func (x *CircuitKey) GetHtlcId() uint64 {
if x != nil {
return x.HtlcId
}
return 0
}
// InvoiceAcceptorRequest is a message that the server sends to the client to
// request the client to accept an invoice.
type InvoiceAcceptorRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// invoice is the invoice that the client should consider accepting.
Invoice *lnrpc.Invoice `protobuf:"bytes,1,opt,name=invoice,proto3" json:"invoice,omitempty"`
// exit_htlc_circuit_key is the key of the HTLC for which we is involved in
// the invoice settlement attempt.
ExitHtlcCircuitKey *CircuitKey `protobuf:"bytes,2,opt,name=exit_htlc_circuit_key,json=exitHtlcCircuitKey,proto3" json:"exit_htlc_circuit_key,omitempty"`
// exit_htlc_amt is the amount (millisats) that the client should consider
// accepting.
ExitHtlcAmt uint64 `protobuf:"varint,3,opt,name=exit_htlc_amt,json=exitHtlcAmt,proto3" json:"exit_htlc_amt,omitempty"`
// exit_htlc_expiry is the expiry time of the exit HTLC.
ExitHtlcExpiry uint32 `protobuf:"varint,4,opt,name=exit_htlc_expiry,json=exitHtlcExpiry,proto3" json:"exit_htlc_expiry,omitempty"`
// current_height is the current block height.
CurrentHeight uint32 `protobuf:"varint,5,opt,name=current_height,json=currentHeight,proto3" json:"current_height,omitempty"`
}
func (x *InvoiceAcceptorRequest) Reset() {
*x = InvoiceAcceptorRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_invoicesrpc_invoices_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *InvoiceAcceptorRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*InvoiceAcceptorRequest) ProtoMessage() {}
func (x *InvoiceAcceptorRequest) ProtoReflect() protoreflect.Message {
mi := &file_invoicesrpc_invoices_proto_msgTypes[9]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use InvoiceAcceptorRequest.ProtoReflect.Descriptor instead.
func (*InvoiceAcceptorRequest) Descriptor() ([]byte, []int) {
return file_invoicesrpc_invoices_proto_rawDescGZIP(), []int{9}
}
func (x *InvoiceAcceptorRequest) GetInvoice() *lnrpc.Invoice {
if x != nil {
return x.Invoice
}
return nil
}
func (x *InvoiceAcceptorRequest) GetExitHtlcCircuitKey() *CircuitKey {
if x != nil {
return x.ExitHtlcCircuitKey
}
return nil
}
func (x *InvoiceAcceptorRequest) GetExitHtlcAmt() uint64 {
if x != nil {
return x.ExitHtlcAmt
}
return 0
}
func (x *InvoiceAcceptorRequest) GetExitHtlcExpiry() uint32 {
if x != nil {
return x.ExitHtlcExpiry
}
return 0
}
func (x *InvoiceAcceptorRequest) GetCurrentHeight() uint32 {
if x != nil {
return x.CurrentHeight
}
return 0
}
// InvoiceAcceptorResponse is a message that the client sends to the server to
// indicate whether it accepts the invoice or not.
type InvoiceAcceptorResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// preimage is the preimage of the invoice.
Preimage []byte `protobuf:"bytes,1,opt,name=preimage,proto3" json:"preimage,omitempty"`
// skip_amount_check is a flag that indicates whether the client wants to
// skip the amount check during the invoice settlement process.
SkipAmountCheck bool `protobuf:"varint,2,opt,name=skip_amount_check,json=skipAmountCheck,proto3" json:"skip_amount_check,omitempty"`
}
func (x *InvoiceAcceptorResponse) Reset() {
*x = InvoiceAcceptorResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_invoicesrpc_invoices_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *InvoiceAcceptorResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*InvoiceAcceptorResponse) ProtoMessage() {}
func (x *InvoiceAcceptorResponse) ProtoReflect() protoreflect.Message {
mi := &file_invoicesrpc_invoices_proto_msgTypes[10]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use InvoiceAcceptorResponse.ProtoReflect.Descriptor instead.
func (*InvoiceAcceptorResponse) Descriptor() ([]byte, []int) {
return file_invoicesrpc_invoices_proto_rawDescGZIP(), []int{10}
}
func (x *InvoiceAcceptorResponse) GetPreimage() []byte {
if x != nil {
return x.Preimage
}
return nil
}
func (x *InvoiceAcceptorResponse) GetSkipAmountCheck() bool {
if x != nil {
return x.SkipAmountCheck
}
return false
}
var File_invoicesrpc_invoices_proto protoreflect.FileDescriptor
var file_invoicesrpc_invoices_proto_rawDesc = []byte{
@ -678,41 +884,73 @@ var file_invoicesrpc_invoices_proto_rawDesc = []byte{
0x73, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x4d, 0x6f, 0x64, 0x69, 0x66,
0x69, 0x65, 0x72, 0x52, 0x0e, 0x6c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x4d, 0x6f, 0x64, 0x69, 0x66,
0x69, 0x65, 0x72, 0x42, 0x0d, 0x0a, 0x0b, 0x69, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x5f, 0x72,
0x65, 0x66, 0x2a, 0x44, 0x0a, 0x0e, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x4d, 0x6f, 0x64, 0x69,
0x66, 0x69, 0x65, 0x72, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10,
0x00, 0x12, 0x11, 0x0a, 0x0d, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x53, 0x45, 0x54, 0x5f, 0x4f, 0x4e,
0x4c, 0x59, 0x10, 0x01, 0x12, 0x12, 0x0a, 0x0e, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x53, 0x45, 0x54,
0x5f, 0x42, 0x4c, 0x41, 0x4e, 0x4b, 0x10, 0x02, 0x32, 0x9b, 0x03, 0x0a, 0x08, 0x49, 0x6e, 0x76,
0x6f, 0x69, 0x63, 0x65, 0x73, 0x12, 0x56, 0x0a, 0x16, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69,
0x62, 0x65, 0x53, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x12,
0x2a, 0x2e, 0x69, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x73, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75,
0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x53, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x49, 0x6e, 0x76,
0x6f, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x6c, 0x6e,
0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x30, 0x01, 0x12, 0x4e, 0x0a,
0x0d, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x12, 0x1d,
0x2e, 0x69, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x73, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x61, 0x6e,
0x63, 0x65, 0x6c, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x4d, 0x73, 0x67, 0x1a, 0x1e, 0x2e,
0x69, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x73, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x61, 0x6e, 0x63,
0x65, 0x6c, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x55, 0x0a,
0x0e, 0x41, 0x64, 0x64, 0x48, 0x6f, 0x6c, 0x64, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x12,
0x22, 0x2e, 0x69, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x73, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64,
0x64, 0x48, 0x6f, 0x6c, 0x64, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x69, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x73, 0x72, 0x70,
0x63, 0x2e, 0x41, 0x64, 0x64, 0x48, 0x6f, 0x6c, 0x64, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65,
0x52, 0x65, 0x73, 0x70, 0x12, 0x4e, 0x0a, 0x0d, 0x53, 0x65, 0x74, 0x74, 0x6c, 0x65, 0x49, 0x6e,
0x76, 0x6f, 0x69, 0x63, 0x65, 0x12, 0x1d, 0x2e, 0x69, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x73,
0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x74, 0x74, 0x6c, 0x65, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63,
0x65, 0x4d, 0x73, 0x67, 0x1a, 0x1e, 0x2e, 0x69, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x73, 0x72,
0x70, 0x63, 0x2e, 0x53, 0x65, 0x74, 0x74, 0x6c, 0x65, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65,
0x52, 0x65, 0x73, 0x70, 0x12, 0x40, 0x0a, 0x0f, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x49, 0x6e,
0x76, 0x6f, 0x69, 0x63, 0x65, 0x56, 0x32, 0x12, 0x1d, 0x2e, 0x69, 0x6e, 0x76, 0x6f, 0x69, 0x63,
0x65, 0x73, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x49, 0x6e, 0x76, 0x6f,
0x69, 0x63, 0x65, 0x4d, 0x73, 0x67, 0x1a, 0x0e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49,
0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x42, 0x33, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x6e, 0x65,
0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x6c, 0x6e, 0x64, 0x2f, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2f,
0x69, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x73, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x33,
0x65, 0x66, 0x22, 0x3e, 0x0a, 0x0a, 0x43, 0x69, 0x72, 0x63, 0x75, 0x69, 0x74, 0x4b, 0x65, 0x79,
0x12, 0x17, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
0x04, 0x52, 0x06, 0x63, 0x68, 0x61, 0x6e, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x68, 0x74, 0x6c,
0x63, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x68, 0x74, 0x6c, 0x63,
0x49, 0x64, 0x22, 0x83, 0x02, 0x0a, 0x16, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x41, 0x63,
0x63, 0x65, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a,
0x07, 0x69, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e,
0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x52, 0x07,
0x69, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x12, 0x4a, 0x0a, 0x15, 0x65, 0x78, 0x69, 0x74, 0x5f,
0x68, 0x74, 0x6c, 0x63, 0x5f, 0x63, 0x69, 0x72, 0x63, 0x75, 0x69, 0x74, 0x5f, 0x6b, 0x65, 0x79,
0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x69, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65,
0x73, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x69, 0x72, 0x63, 0x75, 0x69, 0x74, 0x4b, 0x65, 0x79, 0x52,
0x12, 0x65, 0x78, 0x69, 0x74, 0x48, 0x74, 0x6c, 0x63, 0x43, 0x69, 0x72, 0x63, 0x75, 0x69, 0x74,
0x4b, 0x65, 0x79, 0x12, 0x22, 0x0a, 0x0d, 0x65, 0x78, 0x69, 0x74, 0x5f, 0x68, 0x74, 0x6c, 0x63,
0x5f, 0x61, 0x6d, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x65, 0x78, 0x69, 0x74,
0x48, 0x74, 0x6c, 0x63, 0x41, 0x6d, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x65, 0x78, 0x69, 0x74, 0x5f,
0x68, 0x74, 0x6c, 0x63, 0x5f, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28,
0x0d, 0x52, 0x0e, 0x65, 0x78, 0x69, 0x74, 0x48, 0x74, 0x6c, 0x63, 0x45, 0x78, 0x70, 0x69, 0x72,
0x79, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x68, 0x65, 0x69,
0x67, 0x68, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x63, 0x75, 0x72, 0x72, 0x65,
0x6e, 0x74, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x22, 0x61, 0x0a, 0x17, 0x49, 0x6e, 0x76, 0x6f,
0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x65, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18,
0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x70, 0x72, 0x65, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x12,
0x2a, 0x0a, 0x11, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x63,
0x68, 0x65, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x73, 0x6b, 0x69, 0x70,
0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x2a, 0x44, 0x0a, 0x0e, 0x4c,
0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x0b, 0x0a,
0x07, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x48, 0x54,
0x4c, 0x43, 0x5f, 0x53, 0x45, 0x54, 0x5f, 0x4f, 0x4e, 0x4c, 0x59, 0x10, 0x01, 0x12, 0x12, 0x0a,
0x0e, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x53, 0x45, 0x54, 0x5f, 0x42, 0x4c, 0x41, 0x4e, 0x4b, 0x10,
0x02, 0x32, 0xfd, 0x03, 0x0a, 0x08, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x73, 0x12, 0x56,
0x0a, 0x16, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x53, 0x69, 0x6e, 0x67, 0x6c,
0x65, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x12, 0x2a, 0x2e, 0x69, 0x6e, 0x76, 0x6f, 0x69,
0x63, 0x65, 0x73, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65,
0x53, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76,
0x6f, 0x69, 0x63, 0x65, 0x30, 0x01, 0x12, 0x4e, 0x0a, 0x0d, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c,
0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x12, 0x1d, 0x2e, 0x69, 0x6e, 0x76, 0x6f, 0x69, 0x63,
0x65, 0x73, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x49, 0x6e, 0x76, 0x6f,
0x69, 0x63, 0x65, 0x4d, 0x73, 0x67, 0x1a, 0x1e, 0x2e, 0x69, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65,
0x73, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x49, 0x6e, 0x76, 0x6f, 0x69,
0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x55, 0x0a, 0x0e, 0x41, 0x64, 0x64, 0x48, 0x6f, 0x6c,
0x64, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x12, 0x22, 0x2e, 0x69, 0x6e, 0x76, 0x6f, 0x69,
0x63, 0x65, 0x73, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x48, 0x6f, 0x6c, 0x64, 0x49, 0x6e,
0x76, 0x6f, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x69,
0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x73, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x48, 0x6f,
0x6c, 0x64, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x4e, 0x0a,
0x0d, 0x53, 0x65, 0x74, 0x74, 0x6c, 0x65, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x12, 0x1d,
0x2e, 0x69, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x73, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x74,
0x74, 0x6c, 0x65, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x4d, 0x73, 0x67, 0x1a, 0x1e, 0x2e,
0x69, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x73, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x74, 0x74,
0x6c, 0x65, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x40, 0x0a,
0x0f, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x56, 0x32,
0x12, 0x1d, 0x2e, 0x69, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x73, 0x72, 0x70, 0x63, 0x2e, 0x4c,
0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x4d, 0x73, 0x67, 0x1a,
0x0e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x12,
0x60, 0x0a, 0x0f, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74,
0x6f, 0x72, 0x12, 0x24, 0x2e, 0x69, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x73, 0x72, 0x70, 0x63,
0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x6f, 0x72,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x1a, 0x23, 0x2e, 0x69, 0x6e, 0x76, 0x6f, 0x69,
0x63, 0x65, 0x73, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x41, 0x63,
0x63, 0x65, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x28, 0x01, 0x30,
0x01, 0x42, 0x33, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
0x6c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b,
0x2f, 0x6c, 0x6e, 0x64, 0x2f, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2f, 0x69, 0x6e, 0x76, 0x6f, 0x69,
0x63, 0x65, 0x73, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@ -728,7 +966,7 @@ func file_invoicesrpc_invoices_proto_rawDescGZIP() []byte {
}
var file_invoicesrpc_invoices_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_invoicesrpc_invoices_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
var file_invoicesrpc_invoices_proto_msgTypes = make([]protoimpl.MessageInfo, 11)
var file_invoicesrpc_invoices_proto_goTypes = []interface{}{
(LookupModifier)(0), // 0: invoicesrpc.LookupModifier
(*CancelInvoiceMsg)(nil), // 1: invoicesrpc.CancelInvoiceMsg
@ -739,27 +977,34 @@ var file_invoicesrpc_invoices_proto_goTypes = []interface{}{
(*SettleInvoiceResp)(nil), // 6: invoicesrpc.SettleInvoiceResp
(*SubscribeSingleInvoiceRequest)(nil), // 7: invoicesrpc.SubscribeSingleInvoiceRequest
(*LookupInvoiceMsg)(nil), // 8: invoicesrpc.LookupInvoiceMsg
(*lnrpc.RouteHint)(nil), // 9: lnrpc.RouteHint
(*lnrpc.Invoice)(nil), // 10: lnrpc.Invoice
(*CircuitKey)(nil), // 9: invoicesrpc.CircuitKey
(*InvoiceAcceptorRequest)(nil), // 10: invoicesrpc.InvoiceAcceptorRequest
(*InvoiceAcceptorResponse)(nil), // 11: invoicesrpc.InvoiceAcceptorResponse
(*lnrpc.RouteHint)(nil), // 12: lnrpc.RouteHint
(*lnrpc.Invoice)(nil), // 13: lnrpc.Invoice
}
var file_invoicesrpc_invoices_proto_depIdxs = []int32{
9, // 0: invoicesrpc.AddHoldInvoiceRequest.route_hints:type_name -> lnrpc.RouteHint
12, // 0: invoicesrpc.AddHoldInvoiceRequest.route_hints:type_name -> lnrpc.RouteHint
0, // 1: invoicesrpc.LookupInvoiceMsg.lookup_modifier:type_name -> invoicesrpc.LookupModifier
7, // 2: invoicesrpc.Invoices.SubscribeSingleInvoice:input_type -> invoicesrpc.SubscribeSingleInvoiceRequest
1, // 3: invoicesrpc.Invoices.CancelInvoice:input_type -> invoicesrpc.CancelInvoiceMsg
3, // 4: invoicesrpc.Invoices.AddHoldInvoice:input_type -> invoicesrpc.AddHoldInvoiceRequest
5, // 5: invoicesrpc.Invoices.SettleInvoice:input_type -> invoicesrpc.SettleInvoiceMsg
8, // 6: invoicesrpc.Invoices.LookupInvoiceV2:input_type -> invoicesrpc.LookupInvoiceMsg
10, // 7: invoicesrpc.Invoices.SubscribeSingleInvoice:output_type -> lnrpc.Invoice
2, // 8: invoicesrpc.Invoices.CancelInvoice:output_type -> invoicesrpc.CancelInvoiceResp
4, // 9: invoicesrpc.Invoices.AddHoldInvoice:output_type -> invoicesrpc.AddHoldInvoiceResp
6, // 10: invoicesrpc.Invoices.SettleInvoice:output_type -> invoicesrpc.SettleInvoiceResp
10, // 11: invoicesrpc.Invoices.LookupInvoiceV2:output_type -> lnrpc.Invoice
7, // [7:12] is the sub-list for method output_type
2, // [2:7] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
13, // 2: invoicesrpc.InvoiceAcceptorRequest.invoice:type_name -> lnrpc.Invoice
9, // 3: invoicesrpc.InvoiceAcceptorRequest.exit_htlc_circuit_key:type_name -> invoicesrpc.CircuitKey
7, // 4: invoicesrpc.Invoices.SubscribeSingleInvoice:input_type -> invoicesrpc.SubscribeSingleInvoiceRequest
1, // 5: invoicesrpc.Invoices.CancelInvoice:input_type -> invoicesrpc.CancelInvoiceMsg
3, // 6: invoicesrpc.Invoices.AddHoldInvoice:input_type -> invoicesrpc.AddHoldInvoiceRequest
5, // 7: invoicesrpc.Invoices.SettleInvoice:input_type -> invoicesrpc.SettleInvoiceMsg
8, // 8: invoicesrpc.Invoices.LookupInvoiceV2:input_type -> invoicesrpc.LookupInvoiceMsg
11, // 9: invoicesrpc.Invoices.InvoiceAcceptor:input_type -> invoicesrpc.InvoiceAcceptorResponse
13, // 10: invoicesrpc.Invoices.SubscribeSingleInvoice:output_type -> lnrpc.Invoice
2, // 11: invoicesrpc.Invoices.CancelInvoice:output_type -> invoicesrpc.CancelInvoiceResp
4, // 12: invoicesrpc.Invoices.AddHoldInvoice:output_type -> invoicesrpc.AddHoldInvoiceResp
6, // 13: invoicesrpc.Invoices.SettleInvoice:output_type -> invoicesrpc.SettleInvoiceResp
13, // 14: invoicesrpc.Invoices.LookupInvoiceV2:output_type -> lnrpc.Invoice
10, // 15: invoicesrpc.Invoices.InvoiceAcceptor:output_type -> invoicesrpc.InvoiceAcceptorRequest
10, // [10:16] is the sub-list for method output_type
4, // [4:10] is the sub-list for method input_type
4, // [4:4] is the sub-list for extension type_name
4, // [4:4] is the sub-list for extension extendee
0, // [0:4] is the sub-list for field type_name
}
func init() { file_invoicesrpc_invoices_proto_init() }
@ -864,6 +1109,42 @@ func file_invoicesrpc_invoices_proto_init() {
return nil
}
}
file_invoicesrpc_invoices_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*CircuitKey); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_invoicesrpc_invoices_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*InvoiceAcceptorRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_invoicesrpc_invoices_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*InvoiceAcceptorResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
file_invoicesrpc_invoices_proto_msgTypes[7].OneofWrappers = []interface{}{
(*LookupInvoiceMsg_PaymentHash)(nil),
@ -876,7 +1157,7 @@ func file_invoicesrpc_invoices_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_invoicesrpc_invoices_proto_rawDesc,
NumEnums: 1,
NumMessages: 8,
NumMessages: 11,
NumExtensions: 0,
NumServices: 1,
},

View File

@ -59,6 +59,14 @@ service Invoices {
using either its payment hash, payment address, or set ID.
*/
rpc LookupInvoiceV2 (LookupInvoiceMsg) returns (lnrpc.Invoice);
/*
InvoiceAcceptor is a bi-directional streaming RPC that allows a client to
accept invoices. The server will send invoices to the client and the client
can respond with whether it accepts the invoice or not.
*/
rpc InvoiceAcceptor (stream InvoiceAcceptorResponse)
returns (stream InvoiceAcceptorRequest);
}
message CancelInvoiceMsg {
@ -192,3 +200,44 @@ message LookupInvoiceMsg {
LookupModifier lookup_modifier = 4;
}
// CircuitKey is a unique identifier for an HTLC.
message CircuitKey {
/// The id of the channel that the is part of this circuit.
uint64 chan_id = 1;
/// The index of the incoming htlc in the incoming channel.
uint64 htlc_id = 2;
}
// InvoiceAcceptorRequest is a message that the server sends to the client to
// request the client to accept an invoice.
message InvoiceAcceptorRequest {
// invoice is the invoice that the client should consider accepting.
lnrpc.Invoice invoice = 1;
// exit_htlc_circuit_key is the key of the HTLC for which we is involved in
// the invoice settlement attempt.
CircuitKey exit_htlc_circuit_key = 2;
// exit_htlc_amt is the amount (millisats) that the client should consider
// accepting.
uint64 exit_htlc_amt = 3;
// exit_htlc_expiry is the expiry time of the exit HTLC.
uint32 exit_htlc_expiry = 4;
// current_height is the current block height.
uint32 current_height = 5;
}
// InvoiceAcceptorResponse is a message that the client sends to the server to
// indicate whether it accepts the invoice or not.
message InvoiceAcceptorResponse {
// preimage is the preimage of the invoice.
bytes preimage = 1;
// skip_amount_check is a flag that indicates whether the client wants to
// skip the amount check during the invoice settlement process.
bool skip_amount_check = 2;
}

View File

@ -317,6 +317,51 @@
"invoicesrpcCancelInvoiceResp": {
"type": "object"
},
"invoicesrpcCircuitKey": {
"type": "object",
"properties": {
"chan_id": {
"type": "string",
"format": "uint64",
"description": "/ The id of the channel that the is part of this circuit."
},
"htlc_id": {
"type": "string",
"format": "uint64",
"description": "/ The index of the incoming htlc in the incoming channel."
}
},
"description": "CircuitKey is a unique identifier for an HTLC."
},
"invoicesrpcInvoiceAcceptorRequest": {
"type": "object",
"properties": {
"invoice": {
"$ref": "#/definitions/lnrpcInvoice",
"description": "invoice is the invoice that the client should consider accepting."
},
"exit_htlc_circuit_key": {
"$ref": "#/definitions/invoicesrpcCircuitKey",
"description": "exit_htlc_circuit_key is the key of the HTLC for which we is involved in\nthe invoice settlement attempt."
},
"exit_htlc_amt": {
"type": "string",
"format": "uint64",
"description": "exit_htlc_amt is the amount (millisats) that the client should consider\naccepting."
},
"exit_htlc_expiry": {
"type": "integer",
"format": "int64",
"description": "exit_htlc_expiry is the expiry time of the exit HTLC."
},
"current_height": {
"type": "integer",
"format": "int64",
"description": "current_height is the current block height."
}
},
"description": "InvoiceAcceptorRequest is a message that the server sends to the client to\nrequest the client to accept an invoice."
},
"invoicesrpcLookupModifier": {
"type": "string",
"enum": [

View File

@ -39,6 +39,10 @@ type InvoicesClient interface {
// LookupInvoiceV2 attempts to look up at invoice. An invoice can be refrenced
// using either its payment hash, payment address, or set ID.
LookupInvoiceV2(ctx context.Context, in *LookupInvoiceMsg, opts ...grpc.CallOption) (*lnrpc.Invoice, error)
// InvoiceAcceptor is a bi-directional streaming RPC that allows a client to
// accept invoices. The server will send invoices to the client and the client
// can respond with whether it accepts the invoice or not.
InvoiceAcceptor(ctx context.Context, opts ...grpc.CallOption) (Invoices_InvoiceAcceptorClient, error)
}
type invoicesClient struct {
@ -117,6 +121,37 @@ func (c *invoicesClient) LookupInvoiceV2(ctx context.Context, in *LookupInvoiceM
return out, nil
}
func (c *invoicesClient) InvoiceAcceptor(ctx context.Context, opts ...grpc.CallOption) (Invoices_InvoiceAcceptorClient, error) {
stream, err := c.cc.NewStream(ctx, &Invoices_ServiceDesc.Streams[1], "/invoicesrpc.Invoices/InvoiceAcceptor", opts...)
if err != nil {
return nil, err
}
x := &invoicesInvoiceAcceptorClient{stream}
return x, nil
}
type Invoices_InvoiceAcceptorClient interface {
Send(*InvoiceAcceptorResponse) error
Recv() (*InvoiceAcceptorRequest, error)
grpc.ClientStream
}
type invoicesInvoiceAcceptorClient struct {
grpc.ClientStream
}
func (x *invoicesInvoiceAcceptorClient) Send(m *InvoiceAcceptorResponse) error {
return x.ClientStream.SendMsg(m)
}
func (x *invoicesInvoiceAcceptorClient) Recv() (*InvoiceAcceptorRequest, error) {
m := new(InvoiceAcceptorRequest)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
// InvoicesServer is the server API for Invoices service.
// All implementations must embed UnimplementedInvoicesServer
// for forward compatibility
@ -141,6 +176,10 @@ type InvoicesServer interface {
// LookupInvoiceV2 attempts to look up at invoice. An invoice can be refrenced
// using either its payment hash, payment address, or set ID.
LookupInvoiceV2(context.Context, *LookupInvoiceMsg) (*lnrpc.Invoice, error)
// InvoiceAcceptor is a bi-directional streaming RPC that allows a client to
// accept invoices. The server will send invoices to the client and the client
// can respond with whether it accepts the invoice or not.
InvoiceAcceptor(Invoices_InvoiceAcceptorServer) error
mustEmbedUnimplementedInvoicesServer()
}
@ -163,6 +202,9 @@ func (UnimplementedInvoicesServer) SettleInvoice(context.Context, *SettleInvoice
func (UnimplementedInvoicesServer) LookupInvoiceV2(context.Context, *LookupInvoiceMsg) (*lnrpc.Invoice, error) {
return nil, status.Errorf(codes.Unimplemented, "method LookupInvoiceV2 not implemented")
}
func (UnimplementedInvoicesServer) InvoiceAcceptor(Invoices_InvoiceAcceptorServer) error {
return status.Errorf(codes.Unimplemented, "method InvoiceAcceptor not implemented")
}
func (UnimplementedInvoicesServer) mustEmbedUnimplementedInvoicesServer() {}
// UnsafeInvoicesServer may be embedded to opt out of forward compatibility for this service.
@ -269,6 +311,32 @@ func _Invoices_LookupInvoiceV2_Handler(srv interface{}, ctx context.Context, dec
return interceptor(ctx, in, info, handler)
}
func _Invoices_InvoiceAcceptor_Handler(srv interface{}, stream grpc.ServerStream) error {
return srv.(InvoicesServer).InvoiceAcceptor(&invoicesInvoiceAcceptorServer{stream})
}
type Invoices_InvoiceAcceptorServer interface {
Send(*InvoiceAcceptorRequest) error
Recv() (*InvoiceAcceptorResponse, error)
grpc.ServerStream
}
type invoicesInvoiceAcceptorServer struct {
grpc.ServerStream
}
func (x *invoicesInvoiceAcceptorServer) Send(m *InvoiceAcceptorRequest) error {
return x.ServerStream.SendMsg(m)
}
func (x *invoicesInvoiceAcceptorServer) Recv() (*InvoiceAcceptorResponse, error) {
m := new(InvoiceAcceptorResponse)
if err := x.ServerStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
// Invoices_ServiceDesc is the grpc.ServiceDesc for Invoices service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
@ -299,6 +367,12 @@ var Invoices_ServiceDesc = grpc.ServiceDesc{
Handler: _Invoices_SubscribeSingleInvoice_Handler,
ServerStreams: true,
},
{
StreamName: "InvoiceAcceptor",
Handler: _Invoices_InvoiceAcceptor_Handler,
ServerStreams: true,
ClientStreams: true,
},
},
Metadata: "invoicesrpc/invoices.proto",
}

View File

@ -10,6 +10,7 @@ import (
"io/ioutil"
"os"
"path/filepath"
"sync/atomic"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/lightningnetwork/lnd/invoices"
@ -31,6 +32,12 @@ const (
)
var (
// ErrInvoiceAcceptorAlreadyExists signals that an invoice acceptor
// already exists. The user must disconnect an existing invoice accptor
// prior to opening another stream.
ErrInvoiceAcceptorAlreadyExists = errors.New("interceptor already " +
"exists")
// macaroonOps are the set of capabilities that our minted macaroon (if
// it doesn't already exist) will have.
macaroonOps = []bakery.Op{
@ -66,6 +73,10 @@ var (
Entity: "invoices",
Action: "write",
}},
"/invoicesrpc.Invoices/InvoiceAcceptor": {{
Entity: "invoices",
Action: "write",
}},
}
// DefaultInvoicesMacFilename is the default name of the invoices
@ -88,6 +99,12 @@ type Server struct {
// Required by the grpc-gateway/v2 library for forward compatibility.
UnimplementedInvoicesServer
// invoiceAcceptorActive is an atomic flag that indicates whether an
// invoice acceptor RPC server is currently active. It is used to ensure
// that only one invoice acceptor RPC server instance is running at a
// time.
invoiceAcceptorActive atomic.Int32
quit chan struct{}
cfg *Config
@ -447,3 +464,22 @@ func (s *Server) LookupInvoiceV2(ctx context.Context,
return CreateRPCInvoice(&invoice, s.cfg.ChainParams)
}
// InvoiceAcceptor is a bidirectional streaming RPC that allows a client to
// inspect and optionally accept invoices.
func (s *Server) InvoiceAcceptor(
acceptorServer Invoices_InvoiceAcceptorServer) error {
// Ensure that there is only one invoice acceptor RPC server instance.
if !s.invoiceAcceptorActive.CompareAndSwap(0, 1) {
return ErrInvoiceAcceptorAlreadyExists
}
defer s.invoiceAcceptorActive.CompareAndSwap(1, 0)
// Run the invoice acceptor.
return newInvoiceAcceptor(invoiceAcceptorConfig{
chainParams: s.cfg.ChainParams,
interceptor: s.cfg.InvoiceSettlementInterceptor,
rpcServer: acceptorServer,
}).run()
}