Skip to content

Commit

Permalink
use stateless invoices
Browse files Browse the repository at this point in the history
  • Loading branch information
joostjager committed Jul 1, 2022
1 parent 23daad2 commit 6e42206
Show file tree
Hide file tree
Showing 16 changed files with 412 additions and 764 deletions.
229 changes: 73 additions & 156 deletions cmd/lnmuxd/lnmux_proto/lnmux.pb.go

Large diffs are not rendered by default.

2 changes: 0 additions & 2 deletions cmd/lnmuxd/lnmux_proto/lnmux.pb.validate.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 3 additions & 14 deletions cmd/lnmuxd/lnmux_proto/lnmux.proto
Original file line number Diff line number Diff line change
Expand Up @@ -33,23 +33,12 @@ message SubscribeSingleInvoiceRequest {

message SubscribeSingleInvoiceResponse {
enum InvoiceState {
STATE_OPEN = 0;
STATE_ACCEPTED = 1;
STATE_SETTLE_REQUESTED = 2;
STATE_SETTLED = 3;
STATE_CANCELLED = 4;
}

enum CancelledReason {
REASON_NONE = 0;
REASON_EXPIRED = 1;
REASON_ACCEPT_TIMEOUT = 2;
REASON_EXTERNAL = 3;
STATE_ACCEPTED = 0;
STATE_SETTLE_REQUESTED = 1;
STATE_SETTLED = 2;
}

InvoiceState state = 1;

CancelledReason cancelled_reason = 2;
}

message SettleInvoiceRequest {
Expand Down
1 change: 1 addition & 0 deletions cmd/lnmuxd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ func runAction(c *cli.Context) error {
HtlcHoldDuration: 30 * time.Second,
AcceptTimeout: 60 * time.Second,
Logger: log,
PrivKey: identityKey,
AutoSettle: cfg.AutoSettle,
},
)
Expand Down
43 changes: 1 addition & 42 deletions cmd/lnmuxd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"errors"
"fmt"
"math/rand"
"time"

"github.com/bottlepay/lnmux"
Expand Down Expand Up @@ -39,8 +38,6 @@ func newServer(creator *lnmux.InvoiceCreator, registry *lnmux.InvoiceRegistry) (

func marshallInvoiceState(state persistence.InvoiceState) lnmux_proto.SubscribeSingleInvoiceResponse_InvoiceState {
switch state {
case persistence.InvoiceStateOpen:
return lnmux_proto.SubscribeSingleInvoiceResponse_STATE_OPEN

case persistence.InvoiceStateAccepted:
return lnmux_proto.SubscribeSingleInvoiceResponse_STATE_ACCEPTED
Expand All @@ -51,33 +48,11 @@ func marshallInvoiceState(state persistence.InvoiceState) lnmux_proto.SubscribeS
case persistence.InvoiceStateSettled:
return lnmux_proto.SubscribeSingleInvoiceResponse_STATE_SETTLED

case persistence.InvoiceStateCancelled:
return lnmux_proto.SubscribeSingleInvoiceResponse_STATE_CANCELLED

default:
panic("unknown invoice state")
}
}

func marshallCancelledReason(reason persistence.CancelledReason) lnmux_proto.SubscribeSingleInvoiceResponse_CancelledReason {
switch reason {
case persistence.CancelledReasonNone:
return lnmux_proto.SubscribeSingleInvoiceResponse_REASON_NONE

case persistence.CancelledReasonExpired:
return lnmux_proto.SubscribeSingleInvoiceResponse_REASON_EXPIRED

case persistence.CancelledReasonAcceptTimeout:
return lnmux_proto.SubscribeSingleInvoiceResponse_REASON_ACCEPT_TIMEOUT

case persistence.CancelledReasonExternal:
return lnmux_proto.SubscribeSingleInvoiceResponse_REASON_EXTERNAL

default:
panic("unknown cancelled reason")
}
}

func (s *server) SubscribeSingleInvoice(req *lnmux_proto.SubscribeSingleInvoiceRequest,
subscription lnmux_proto.Service_SubscribeSingleInvoiceServer) error {

Expand Down Expand Up @@ -136,8 +111,7 @@ func (s *server) SubscribeSingleInvoice(req *lnmux_proto.SubscribeSingleInvoiceR
}

err := subscription.Send(&lnmux_proto.SubscribeSingleInvoiceResponse{
State: marshallInvoiceState(update.State),
CancelledReason: marshallCancelledReason(update.CancelledReason),
State: marshallInvoiceState(update.State),
})
if err != nil {
return err
Expand Down Expand Up @@ -170,7 +144,6 @@ func (s *server) AddInvoice(ctx context.Context,

// Create the invoice.
expiry := time.Duration(req.ExpirySecs) * time.Second
expiryTime := time.Now().Add(expiry)
invoice, preimage, err := s.creator.Create(
req.AmtMsat, expiry, req.Description, descHash, finalCltvExpiry,
)
Expand All @@ -180,20 +153,6 @@ func (s *server) AddInvoice(ctx context.Context,

hash := preimage.Hash()

// Store invoice.
creationData := &persistence.InvoiceCreationData{
InvoiceCreationData: invoice.InvoiceCreationData,
CreatedAt: invoice.CreationDate,
ID: int64(rand.Int31()),
PaymentRequest: invoice.PaymentRequest,
ExpiresAt: expiryTime,
}

err = s.registry.NewInvoice(creationData)
if err != nil {
return nil, err
}

return &lnmux_proto.AddInvoiceResponse{
PaymentRequest: invoice.PaymentRequest,
Hash: hash[:],
Expand Down
47 changes: 30 additions & 17 deletions invoice_creator.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package lnmux

import (
"crypto/rand"
"encoding/binary"
"time"

"github.com/btcsuite/btcd/btcec/v2"
Expand All @@ -17,6 +17,8 @@ import (
"github.com/bottlepay/lnmux/types"
)

var byteOrder = binary.BigEndian

const virtualChannel = 12345

type InvoiceCreatorConfig struct {
Expand Down Expand Up @@ -65,6 +67,8 @@ func (c *InvoiceCreator) Create(amtMSat int64, expiry time.Duration,
memo string, descHash *lntypes.Hash, cltvDelta uint64) (
*Invoice, lntypes.Preimage, error) {

creationDate := time.Now()

// Get features.
featureMgr, err := feature.NewManager(feature.Config{})
if err != nil {
Expand All @@ -77,11 +81,27 @@ func (c *InvoiceCreator) Create(amtMSat int64, expiry time.Duration,

nodeSigner := netann.NewNodeSigner(nodeKeySigner)

paymentPreimage := &lntypes.Preimage{}
if _, err := rand.Read(paymentPreimage[:]); err != nil {
privKey, err := c.keyRing.DerivePrivKey(c.idKeyDesc)
if err != nil {
return nil, lntypes.Preimage{}, err
}
paymentHash := paymentPreimage.Hash()

expiryTime := creationDate.Add(expiry)
statelessData, err := encodeStatelessData(
privKey.Serialize(), amtMSat, expiryTime,
)
if err != nil {
return nil, lntypes.Preimage{}, err
}

paymentHash := statelessData.preimage.Hash()

// TODO: Optionally we could encrypt the payment metadata here, just like
// rust-lightning does:
// https://github.com/lightningdevkit/rust-lightning/blob/a600eee87c96ee8865402e86bb1865011bf2d2de/lightning/src/ln/inbound_payment.rs#L166
//
// Background:
// https://github.com/lightningdevkit/rust-lightning/issues/1171#issuecomment-1162817360

// We also create an encoded payment request which allows the
// caller to compactly send the invoice to the payer. We'll create a
Expand Down Expand Up @@ -128,17 +148,11 @@ func (c *InvoiceCreator) Create(amtMSat int64, expiry time.Duration,
invoiceFeatures := featureMgr.Get(feature.SetInvoice)
options = append(options, zpay32.Features(invoiceFeatures))

// Generate and set a random payment address for this invoice. If the
// sender understands payment addresses, this can be used to avoid
// intermediaries probing the receiver.
var paymentAddr [32]byte
if _, err := rand.Read(paymentAddr[:]); err != nil {
return nil, lntypes.Preimage{}, err
}
options = append(options, zpay32.PaymentAddr(paymentAddr))
// Set the payment address.
options = append(options, zpay32.PaymentAddr(statelessData.paymentAddr))

// Create and encode the payment request as a bech32 (zpay32) string.
creationDate := time.Now()

payReq, err := zpay32.NewInvoice(
c.activeNetParams, paymentHash, creationDate, options...,
)
Expand All @@ -159,12 +173,11 @@ func (c *InvoiceCreator) Create(amtMSat int64, expiry time.Duration,
CreationDate: creationDate,
PaymentRequest: payReqString,
InvoiceCreationData: types.InvoiceCreationData{
FinalCltvDelta: int32(payReq.MinFinalCLTVExpiry()),
Value: lnwire.MilliSatoshi(amtMSat),
PaymentPreimage: *paymentPreimage,
PaymentAddr: paymentAddr,
PaymentPreimage: statelessData.preimage,
PaymentAddr: statelessData.paymentAddr,
},
}

return newInvoice, *paymentPreimage, nil
return newInvoice, statelessData.preimage, nil
}
Loading

0 comments on commit 6e42206

Please sign in to comment.