Skip to content

Commit 3f10407

Browse files
authored
Merge pull request #208 from carlaKC/lndclient-lookupinvoice
lndclient: add lookup invoice
2 parents dae3165 + a57e34c commit 3f10407

File tree

3 files changed

+136
-0
lines changed

3 files changed

+136
-0
lines changed

lndclient/lightning_client.go

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/lightningnetwork/lnd/lnrpc"
1717
"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
1818
"github.com/lightningnetwork/lnd/lntypes"
19+
"github.com/lightningnetwork/lnd/lnwire"
1920
"github.com/lightningnetwork/lnd/zpay32"
2021
"google.golang.org/grpc"
2122
"google.golang.org/grpc/codes"
@@ -38,6 +39,9 @@ type LightningClient interface {
3839
AddInvoice(ctx context.Context, in *invoicesrpc.AddInvoiceData) (
3940
lntypes.Hash, string, error)
4041

42+
// LookupInvoice looks up an invoice by hash.
43+
LookupInvoice(ctx context.Context, hash lntypes.Hash) (*Invoice, error)
44+
4145
// ListTransactions returns all known transactions of the backing lnd
4246
// node.
4347
ListTransactions(ctx context.Context) ([]*wire.MsgTx, error)
@@ -365,6 +369,103 @@ func (s *lightningClient) AddInvoice(ctx context.Context,
365369
return hash, resp.PaymentRequest, nil
366370
}
367371

372+
// Invoice represents an invoice in lnd.
373+
type Invoice struct {
374+
// Preimage is the invoice's preimage, which is set if the invoice
375+
// is settled.
376+
Preimage *lntypes.Preimage
377+
378+
// Hash is the invoice hash.
379+
Hash lntypes.Hash
380+
381+
// Memo is an optional memo field for hte invoice.
382+
Memo string
383+
384+
// PaymentRequest is the invoice's payment request.
385+
PaymentRequest string
386+
387+
// Amount is the amount of the invoice in millisatoshis.
388+
Amount lnwire.MilliSatoshi
389+
390+
// AmountPaid is the amount that was paid for the invoice. This field
391+
// will only be set if the invoice is settled.
392+
AmountPaid lnwire.MilliSatoshi
393+
394+
// CreationDate is the time the invoice was created.
395+
CreationDate time.Time
396+
397+
// SettleDate is the time the invoice was settled.
398+
SettleDate time.Time
399+
400+
// State is the invoice's current state.
401+
State channeldb.ContractState
402+
403+
// IsKeysend indicates whether the invoice was a spontaneous payment.
404+
IsKeysend bool
405+
}
406+
407+
// LookupInvoice looks up an invoice in lnd, it will error if the invoice is
408+
// not known to lnd.
409+
func (s *lightningClient) LookupInvoice(ctx context.Context,
410+
hash lntypes.Hash) (*Invoice, error) {
411+
412+
rpcCtx, cancel := context.WithTimeout(ctx, rpcTimeout)
413+
defer cancel()
414+
415+
rpcIn := &lnrpc.PaymentHash{
416+
RHash: hash[:],
417+
}
418+
419+
rpcCtx = s.adminMac.WithMacaroonAuth(rpcCtx)
420+
resp, err := s.client.LookupInvoice(rpcCtx, rpcIn)
421+
if err != nil {
422+
return nil, err
423+
}
424+
425+
invoice := &Invoice{
426+
Preimage: nil,
427+
Hash: hash,
428+
Memo: resp.Memo,
429+
PaymentRequest: resp.PaymentRequest,
430+
Amount: lnwire.MilliSatoshi(resp.ValueMsat),
431+
AmountPaid: lnwire.MilliSatoshi(resp.AmtPaidMsat),
432+
CreationDate: time.Unix(resp.CreationDate, 0),
433+
IsKeysend: resp.IsKeysend,
434+
}
435+
436+
switch resp.State {
437+
case lnrpc.Invoice_OPEN:
438+
invoice.State = channeldb.ContractOpen
439+
440+
case lnrpc.Invoice_ACCEPTED:
441+
invoice.State = channeldb.ContractAccepted
442+
443+
// If the invoice is settled, it also has a non-nil preimage, which we
444+
// can set on our invoice.
445+
case lnrpc.Invoice_SETTLED:
446+
invoice.State = channeldb.ContractSettled
447+
preimage, err := lntypes.MakePreimage(resp.RPreimage)
448+
if err != nil {
449+
return nil, err
450+
}
451+
invoice.Preimage = &preimage
452+
453+
case lnrpc.Invoice_CANCELED:
454+
invoice.State = channeldb.ContractCanceled
455+
456+
default:
457+
return nil, fmt.Errorf("unknown invoice state: %v", resp.State)
458+
}
459+
460+
// Only set settle date if it is non-zero, because 0 unix time is
461+
// not the same as a zero time struct.
462+
if resp.SettleDate != 0 {
463+
invoice.SettleDate = time.Unix(resp.SettleDate, 0)
464+
}
465+
466+
return invoice, nil
467+
}
468+
368469
// ListTransactions returns all known transactions of the backing lnd node.
369470
func (s *lightningClient) ListTransactions(ctx context.Context) ([]*wire.MsgTx, error) {
370471
rpcCtx, cancel := context.WithTimeout(ctx, rpcTimeout)

test/lightning_client_mock.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/btcsuite/btcd/wire"
1212
"github.com/btcsuite/btcutil"
1313
"github.com/lightninglabs/loop/lndclient"
14+
"github.com/lightningnetwork/lnd/channeldb"
1415
"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
1516
"github.com/lightningnetwork/lnd/lntypes"
1617
"github.com/lightningnetwork/lnd/zpay32"
@@ -125,9 +126,38 @@ func (h *mockLightningClient) AddInvoice(ctx context.Context,
125126
return lntypes.Hash{}, "", err
126127
}
127128

129+
// Add the invoice we have created to our mock's set of invoices.
130+
h.lnd.Invoices[hash] = &lndclient.Invoice{
131+
Preimage: nil,
132+
Hash: hash,
133+
PaymentRequest: payReqString,
134+
Amount: in.Value,
135+
CreationDate: creationDate,
136+
State: channeldb.ContractOpen,
137+
IsKeysend: false,
138+
}
139+
128140
return hash, payReqString, nil
129141
}
130142

143+
// LookupInvoice looks up an invoice in the mock's set of stored invoices.
144+
// If it is not found, this call will fail. Note that these invoices should
145+
// be settled using settleInvoice to have a preimage, settled state and settled
146+
// date set.
147+
func (h *mockLightningClient) LookupInvoice(_ context.Context,
148+
hash lntypes.Hash) (*lndclient.Invoice, error) {
149+
150+
h.lnd.lock.Lock()
151+
defer h.lnd.lock.Unlock()
152+
153+
inv, ok := h.lnd.Invoices[hash]
154+
if !ok {
155+
return nil, fmt.Errorf("invoice: %x not found", hash)
156+
}
157+
158+
return inv, nil
159+
}
160+
131161
// ListTransactions returns all known transactions of the backing lnd node.
132162
func (h *mockLightningClient) ListTransactions(
133163
ctx context.Context) ([]*wire.MsgTx, error) {

test/lnd_services_mock.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ func NewMockLnd() *LndMockServices {
6969
NodePubkey: testNodePubkey,
7070
Signature: testSignature,
7171
SignatureMsg: testSignatureMsg,
72+
Invoices: make(map[lntypes.Hash]*lndclient.Invoice),
7273
}
7374

7475
lightningClient.lnd = &lnd
@@ -158,6 +159,10 @@ type LndMockServices struct {
158159

159160
Transactions []*wire.MsgTx
160161

162+
// Invoices is a set of invoices that have been created by the mock,
163+
// keyed by hash string.
164+
Invoices map[lntypes.Hash]*lndclient.Invoice
165+
161166
WaitForFinished func()
162167

163168
lock sync.Mutex

0 commit comments

Comments
 (0)