Skip to content

Commit 459a572

Browse files
committed
multi: add new strict-verify CLI option to control invoice usage
In this commit, we add a new CLI argument that allows a user to control if we use strict verification or not. Strict verification relies on checking the actual invoice state against lnd, and requires more state for the Aperture server. When strict verification isn't on, we rely only on the preimage payment hash relationship. Namely that the only way a user can obtain the preimage is to pay the invoice, and as we check the HMAC on the macaroon, we know that we created it with an invoice obtained from lnd.
1 parent ab83de2 commit 459a572

File tree

6 files changed

+38
-8
lines changed

6 files changed

+38
-8
lines changed

aperture.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ func (a *Aperture) Start(errChan chan error) error {
337337

338338
a.challenger, err = challenger.NewLNCChallenger(
339339
session, lncStore, a.cfg.InvoiceBatchSize,
340-
genInvoiceReq, errChan,
340+
genInvoiceReq, errChan, a.cfg.StrictVerify,
341341
)
342342
if err != nil {
343343
return fmt.Errorf("unable to start lnc "+
@@ -361,7 +361,7 @@ func (a *Aperture) Start(errChan chan error) error {
361361

362362
a.challenger, err = challenger.NewLndChallenger(
363363
client, a.cfg.InvoiceBatchSize, genInvoiceReq,
364-
context.Background, errChan,
364+
context.Background, errChan, a.cfg.StrictVerify,
365365
)
366366
if err != nil {
367367
return err

challenger/lnc.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ type LNCChallenger struct {
2020
// connect to an lnd backend to create payment challenges.
2121
func NewLNCChallenger(session *lnc.Session, lncStore lnc.Store,
2222
invoiceBatchSize int, genInvoiceReq InvoiceRequestGenerator,
23-
errChan chan<- error) (*LNCChallenger, error) {
23+
errChan chan<- error, strictVerify bool) (*LNCChallenger, error) {
2424

2525
nodeConn, err := lnc.NewNodeConn(session, lncStore)
2626
if err != nil {
@@ -35,7 +35,7 @@ func NewLNCChallenger(session *lnc.Session, lncStore lnc.Store,
3535

3636
lndChallenger, err := NewLndChallenger(
3737
client, invoiceBatchSize, genInvoiceReq, nodeConn.CtxFunc,
38-
errChan,
38+
errChan, strictVerify,
3939
)
4040
if err != nil {
4141
return nil, err

challenger/lnd.go

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ type LndChallenger struct {
2525
invoicesCancel func()
2626
invoicesCond *sync.Cond
2727

28+
// strictVerify indicates whether we should verify the invoice states,
29+
// or rely on the higher level preimage verification.
30+
strictVerify bool
31+
2832
errChan chan<- error
2933

3034
quit chan struct{}
@@ -38,9 +42,8 @@ var _ Challenger = (*LndChallenger)(nil)
3842
// NewLndChallenger creates a new challenger that uses the given connection to
3943
// an lnd backend to create payment challenges.
4044
func NewLndChallenger(client InvoiceClient, batchSize int,
41-
genInvoiceReq InvoiceRequestGenerator,
42-
ctxFunc func() context.Context,
43-
errChan chan<- error) (*LndChallenger, error) {
45+
genInvoiceReq InvoiceRequestGenerator, ctxFunc func() context.Context,
46+
errChan chan<- error, strictVerification bool) (*LndChallenger, error) {
4447

4548
// Make sure we have a valid context function. This will be called to
4649
// create a new context for each call to the lnd client.
@@ -63,6 +66,7 @@ func NewLndChallenger(client InvoiceClient, batchSize int,
6366
invoicesCond: sync.NewCond(invoicesMtx),
6467
quit: make(chan struct{}),
6568
errChan: errChan,
69+
strictVerify: strictVerification,
6670
}
6771

6872
err := challenger.Start()
@@ -78,6 +82,14 @@ func NewLndChallenger(client InvoiceClient, batchSize int,
7882
// invoices on startup and a subscription to all subsequent invoice updates
7983
// is created.
8084
func (l *LndChallenger) Start() error {
85+
// If we aren't doing strict verification, then we can just exit here as
86+
// we don't need the invoice state.
87+
if !l.strictVerify {
88+
log.Infof("Skipping invoice state tracking strict_verify=%v",
89+
l.strictVerify)
90+
return nil
91+
}
92+
8193
// These are the default values for the subscription. In case there are
8294
// no invoices yet, this will instruct lnd to just send us all updates.
8395
// If there are existing invoices, these indices will be updated to
@@ -303,6 +315,12 @@ func (l *LndChallenger) NewChallenge(price int64) (string, lntypes.Hash,
303315
func (l *LndChallenger) VerifyInvoiceStatus(hash lntypes.Hash,
304316
state lnrpc.Invoice_InvoiceState, timeout time.Duration) error {
305317

318+
// If we're not doing strict verification, we can skip this check.
319+
if !l.strictVerify {
320+
log.Tracef("Skipping invoice state check, pay_hash=%v", hash)
321+
return nil
322+
}
323+
306324
// Prevent the challenger to be shut down while we're still waiting for
307325
// status updates.
308326
l.wg.Add(1)

challenger/lnd_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ func newChallenger() (*LndChallenger, *mockInvoiceClient, chan error) {
120120
invoicesMtx: invoicesMtx,
121121
invoicesCond: sync.NewCond(invoicesMtx),
122122
errChan: mainErrChan,
123+
strictVerify: true,
123124
}, mockClient, mainErrChan
124125
}
125126

@@ -142,7 +143,7 @@ func TestLndChallenger(t *testing.T) {
142143
// First of all, test that the NewLndChallenger doesn't allow a nil
143144
// invoice generator function.
144145
errChan := make(chan error)
145-
_, err := NewLndChallenger(nil, 1, nil, nil, errChan)
146+
_, err := NewLndChallenger(nil, 1, nil, nil, errChan, true)
146147
require.Error(t, err)
147148

148149
// Now mock the lnd backend and create a challenger instance that we can

config.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ var (
2020
defaultLogLevel = "info"
2121
defaultLogFilename = "aperture.log"
2222
defaultInvoiceBatchSize = 100000
23+
defaultStrictVerify = false
2324

2425
defaultSqliteDatabaseFileName = "aperture.db"
2526

@@ -224,6 +225,11 @@ type Config struct {
224225
// request.
225226
InvoiceBatchSize int `long:"invoicebatchsize" description:"The number of invoices to fetch in a single request."`
226227

228+
// StrictVerify is a flag that indicates whether we should verify the
229+
// invoice status strictly or not. If set to true, then this requires
230+
// all invoices to be read from disk at start up.
231+
StrictVerify bool `long:"strictverify" description:"Whether to verify the invoice status strictly or not."`
232+
227233
// Logging controls various aspects of aperture logging.
228234
Logging *build.LogConfig `group:"logging" namespace:"logging"`
229235

@@ -274,5 +280,6 @@ func NewConfig() *Config {
274280
InvoiceBatchSize: defaultInvoiceBatchSize,
275281
Logging: build.DefaultLogConfig(),
276282
Blocklist: []string{},
283+
StrictVerify: defaultStrictVerify,
277284
}
278285
}

sample-conf.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ debuglevel: "debug"
1919
autocert: false
2020
servername: aperture.example.com
2121

22+
# Whether we should verify the invoice status strictly or not. If set to true,
23+
# then this requires all invoices to be read from disk at start up.
24+
strictverify: false
25+
2226
# The port on which the pprof profile will be served. If no port is provided,
2327
# the profile will not be served.
2428
profile: 9999

0 commit comments

Comments
 (0)