diff --git a/lnrpc/invoicesrpc/utils.go b/lnrpc/invoicesrpc/utils.go new file mode 100644 index 00000000..47ed217d --- /dev/null +++ b/lnrpc/invoicesrpc/utils.go @@ -0,0 +1,119 @@ +package invoicesrpc + +import ( + "encoding/hex" + "fmt" + + "github.com/btcsuite/btcd/chaincfg" + "github.com/lightningnetwork/lnd/channeldb" + "github.com/lightningnetwork/lnd/lnrpc" + "github.com/lightningnetwork/lnd/routing" + "github.com/lightningnetwork/lnd/zpay32" +) + +// CreateRPCInvoice creates an *lnrpc.Invoice from the *channeldb.Invoice. +func CreateRPCInvoice(invoice *channeldb.Invoice, + activeNetParams *chaincfg.Params) (*lnrpc.Invoice, error) { + + paymentRequest := string(invoice.PaymentRequest) + decoded, err := zpay32.Decode(paymentRequest, activeNetParams) + if err != nil { + return nil, fmt.Errorf("unable to decode payment request: %v", + err) + } + + var descHash []byte + if decoded.DescriptionHash != nil { + descHash = decoded.DescriptionHash[:] + } + + fallbackAddr := "" + if decoded.FallbackAddr != nil { + fallbackAddr = decoded.FallbackAddr.String() + } + + settleDate := int64(0) + if !invoice.SettleDate.IsZero() { + settleDate = invoice.SettleDate.Unix() + } + + // Expiry time will default to 3600 seconds if not specified + // explicitly. + expiry := int64(decoded.Expiry().Seconds()) + + // The expiry will default to 9 blocks if not specified explicitly. + cltvExpiry := decoded.MinFinalCLTVExpiry() + + // Convert between the `lnrpc` and `routing` types. + routeHints := CreateRPCRouteHints(decoded.RouteHints) + + preimage := invoice.Terms.PaymentPreimage + satAmt := invoice.Terms.Value.ToSatoshis() + satAmtPaid := invoice.AmtPaid.ToSatoshis() + + isSettled := invoice.Terms.State == channeldb.ContractSettled + + var state lnrpc.Invoice_InvoiceState + switch invoice.Terms.State { + case channeldb.ContractOpen: + state = lnrpc.Invoice_OPEN + case channeldb.ContractSettled: + state = lnrpc.Invoice_SETTLED + default: + return nil, fmt.Errorf("unknown invoice state") + } + + return &lnrpc.Invoice{ + Memo: string(invoice.Memo[:]), + Receipt: invoice.Receipt[:], + RHash: decoded.PaymentHash[:], + RPreimage: preimage[:], + Value: int64(satAmt), + CreationDate: invoice.CreationDate.Unix(), + SettleDate: settleDate, + Settled: isSettled, + PaymentRequest: paymentRequest, + DescriptionHash: descHash, + Expiry: expiry, + CltvExpiry: cltvExpiry, + FallbackAddr: fallbackAddr, + RouteHints: routeHints, + AddIndex: invoice.AddIndex, + Private: len(routeHints) > 0, + SettleIndex: invoice.SettleIndex, + AmtPaidSat: int64(satAmtPaid), + AmtPaidMsat: int64(invoice.AmtPaid), + AmtPaid: int64(invoice.AmtPaid), + State: state, + }, nil +} + +// CreateRPCRouteHints takes in the decoded form of an invoice's route hints +// and converts them into the lnrpc type. +func CreateRPCRouteHints(routeHints [][]routing.HopHint) []*lnrpc.RouteHint { + var res []*lnrpc.RouteHint + + for _, route := range routeHints { + hopHints := make([]*lnrpc.HopHint, 0, len(route)) + for _, hop := range route { + pubKey := hex.EncodeToString( + hop.NodeID.SerializeCompressed(), + ) + + hint := &lnrpc.HopHint{ + NodeId: pubKey, + ChanId: hop.ChannelID, + FeeBaseMsat: hop.FeeBaseMSat, + FeeProportionalMillionths: hop.FeeProportionalMillionths, + CltvExpiryDelta: uint32(hop.CLTVExpiryDelta), + } + + hopHints = append(hopHints, hint) + } + + routeHint := &lnrpc.RouteHint{HopHints: hopHints} + res = append(res, routeHint) + } + + return res +} diff --git a/rpcserver.go b/rpcserver.go index 934c54e4..e8151677 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -35,6 +35,7 @@ import ( "github.com/lightningnetwork/lnd/invoices" "github.com/lightningnetwork/lnd/lncfg" "github.com/lightningnetwork/lnd/lnrpc" + "github.com/lightningnetwork/lnd/lnrpc/invoicesrpc" "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/macaroons" @@ -3332,111 +3333,6 @@ func (r *rpcServer) AddInvoice(ctx context.Context, }, nil } -// createRPCInvoice creates an *lnrpc.Invoice from the *channeldb.Invoice. -func createRPCInvoice(invoice *channeldb.Invoice) (*lnrpc.Invoice, error) { - paymentRequest := string(invoice.PaymentRequest) - decoded, err := zpay32.Decode(paymentRequest, activeNetParams.Params) - if err != nil { - return nil, fmt.Errorf("unable to decode payment request: %v", - err) - } - - descHash := []byte("") - if decoded.DescriptionHash != nil { - descHash = decoded.DescriptionHash[:] - } - - fallbackAddr := "" - if decoded.FallbackAddr != nil { - fallbackAddr = decoded.FallbackAddr.String() - } - - settleDate := int64(0) - if !invoice.SettleDate.IsZero() { - settleDate = invoice.SettleDate.Unix() - } - - // Expiry time will default to 3600 seconds if not specified - // explicitly. - expiry := int64(decoded.Expiry().Seconds()) - - // The expiry will default to 9 blocks if not specified explicitly. - cltvExpiry := decoded.MinFinalCLTVExpiry() - - // Convert between the `lnrpc` and `routing` types. - routeHints := createRPCRouteHints(decoded.RouteHints) - - preimage := invoice.Terms.PaymentPreimage - satAmt := invoice.Terms.Value.ToSatoshis() - satAmtPaid := invoice.AmtPaid.ToSatoshis() - - isSettled := invoice.Terms.State == channeldb.ContractSettled - - var state lnrpc.Invoice_InvoiceState - switch invoice.Terms.State { - case channeldb.ContractOpen: - state = lnrpc.Invoice_OPEN - case channeldb.ContractSettled: - state = lnrpc.Invoice_SETTLED - default: - return nil, fmt.Errorf("unknown invoice state") - } - - return &lnrpc.Invoice{ - Memo: string(invoice.Memo[:]), - Receipt: invoice.Receipt[:], - RHash: decoded.PaymentHash[:], - RPreimage: preimage[:], - Value: int64(satAmt), - CreationDate: invoice.CreationDate.Unix(), - SettleDate: settleDate, - Settled: isSettled, - PaymentRequest: paymentRequest, - DescriptionHash: descHash, - Expiry: expiry, - CltvExpiry: cltvExpiry, - FallbackAddr: fallbackAddr, - RouteHints: routeHints, - AddIndex: invoice.AddIndex, - Private: len(routeHints) > 0, - SettleIndex: invoice.SettleIndex, - AmtPaidSat: int64(satAmtPaid), - AmtPaidMsat: int64(invoice.AmtPaid), - AmtPaid: int64(invoice.AmtPaid), - State: state, - }, nil -} - -// createRPCRouteHints takes in the decoded form of an invoice's route hints -// and converts them into the lnrpc type. -func createRPCRouteHints(routeHints [][]routing.HopHint) []*lnrpc.RouteHint { - var res []*lnrpc.RouteHint - - for _, route := range routeHints { - hopHints := make([]*lnrpc.HopHint, 0, len(route)) - for _, hop := range route { - pubKey := hex.EncodeToString( - hop.NodeID.SerializeCompressed(), - ) - - hint := &lnrpc.HopHint{ - NodeId: pubKey, - ChanId: hop.ChannelID, - FeeBaseMsat: hop.FeeBaseMSat, - FeeProportionalMillionths: hop.FeeProportionalMillionths, - CltvExpiryDelta: uint32(hop.CLTVExpiryDelta), - } - - hopHints = append(hopHints, hint) - } - - routeHint := &lnrpc.RouteHint{HopHints: hopHints} - res = append(res, routeHint) - } - - return res -} - // LookupInvoice attempts to look up an invoice according to its payment hash. // The passed payment hash *must* be exactly 32 bytes, if not an error is // returned. @@ -3479,7 +3375,9 @@ func (r *rpcServer) LookupInvoice(ctx context.Context, return spew.Sdump(invoice) })) - rpcInvoice, err := createRPCInvoice(&invoice) + rpcInvoice, err := invoicesrpc.CreateRPCInvoice( + &invoice, activeNetParams.Params, + ) if err != nil { return nil, err } @@ -3519,7 +3417,9 @@ func (r *rpcServer) ListInvoices(ctx context.Context, LastIndexOffset: invoiceSlice.LastIndexOffset, } for i, invoice := range invoiceSlice.Invoices { - resp.Invoices[i], err = createRPCInvoice(&invoice) + resp.Invoices[i], err = invoicesrpc.CreateRPCInvoice( + &invoice, activeNetParams.Params, + ) if err != nil { return nil, err } @@ -3541,7 +3441,9 @@ func (r *rpcServer) SubscribeInvoices(req *lnrpc.InvoiceSubscription, for { select { case newInvoice := <-invoiceClient.NewInvoices: - rpcInvoice, err := createRPCInvoice(newInvoice) + rpcInvoice, err := invoicesrpc.CreateRPCInvoice( + newInvoice, activeNetParams.Params, + ) if err != nil { return err } @@ -3551,7 +3453,9 @@ func (r *rpcServer) SubscribeInvoices(req *lnrpc.InvoiceSubscription, } case settledInvoice := <-invoiceClient.SettledInvoices: - rpcInvoice, err := createRPCInvoice(settledInvoice) + rpcInvoice, err := invoicesrpc.CreateRPCInvoice( + settledInvoice, activeNetParams.Params, + ) if err != nil { return err } @@ -4455,7 +4359,7 @@ func (r *rpcServer) DecodePayReq(ctx context.Context, expiry := int64(payReq.Expiry().Seconds()) // Convert between the `lnrpc` and `routing` types. - routeHints := createRPCRouteHints(payReq.RouteHints) + routeHints := invoicesrpc.CreateRPCRouteHints(payReq.RouteHints) amt := int64(0) if payReq.MilliSat != nil {