mirror of
https://github.com/lightninglabs/aperture.git
synced 2025-12-17 00:54:20 +01:00
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.
This commit is contained in:
@@ -337,7 +337,7 @@ func (a *Aperture) Start(errChan chan error) error {
|
|||||||
|
|
||||||
a.challenger, err = challenger.NewLNCChallenger(
|
a.challenger, err = challenger.NewLNCChallenger(
|
||||||
session, lncStore, a.cfg.InvoiceBatchSize,
|
session, lncStore, a.cfg.InvoiceBatchSize,
|
||||||
genInvoiceReq, errChan,
|
genInvoiceReq, errChan, a.cfg.StrictVerify,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to start lnc "+
|
return fmt.Errorf("unable to start lnc "+
|
||||||
@@ -361,7 +361,7 @@ func (a *Aperture) Start(errChan chan error) error {
|
|||||||
|
|
||||||
a.challenger, err = challenger.NewLndChallenger(
|
a.challenger, err = challenger.NewLndChallenger(
|
||||||
client, a.cfg.InvoiceBatchSize, genInvoiceReq,
|
client, a.cfg.InvoiceBatchSize, genInvoiceReq,
|
||||||
context.Background, errChan,
|
context.Background, errChan, a.cfg.StrictVerify,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ type LNCChallenger struct {
|
|||||||
// connect to an lnd backend to create payment challenges.
|
// connect to an lnd backend to create payment challenges.
|
||||||
func NewLNCChallenger(session *lnc.Session, lncStore lnc.Store,
|
func NewLNCChallenger(session *lnc.Session, lncStore lnc.Store,
|
||||||
invoiceBatchSize int, genInvoiceReq InvoiceRequestGenerator,
|
invoiceBatchSize int, genInvoiceReq InvoiceRequestGenerator,
|
||||||
errChan chan<- error) (*LNCChallenger, error) {
|
errChan chan<- error, strictVerify bool) (*LNCChallenger, error) {
|
||||||
|
|
||||||
nodeConn, err := lnc.NewNodeConn(session, lncStore)
|
nodeConn, err := lnc.NewNodeConn(session, lncStore)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -35,7 +35,7 @@ func NewLNCChallenger(session *lnc.Session, lncStore lnc.Store,
|
|||||||
|
|
||||||
lndChallenger, err := NewLndChallenger(
|
lndChallenger, err := NewLndChallenger(
|
||||||
client, invoiceBatchSize, genInvoiceReq, nodeConn.CtxFunc,
|
client, invoiceBatchSize, genInvoiceReq, nodeConn.CtxFunc,
|
||||||
errChan,
|
errChan, strictVerify,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -25,6 +25,10 @@ type LndChallenger struct {
|
|||||||
invoicesCancel func()
|
invoicesCancel func()
|
||||||
invoicesCond *sync.Cond
|
invoicesCond *sync.Cond
|
||||||
|
|
||||||
|
// strictVerify indicates whether we should verify the invoice states,
|
||||||
|
// or rely on the higher level preimage verification.
|
||||||
|
strictVerify bool
|
||||||
|
|
||||||
errChan chan<- error
|
errChan chan<- error
|
||||||
|
|
||||||
quit chan struct{}
|
quit chan struct{}
|
||||||
@@ -38,9 +42,8 @@ var _ Challenger = (*LndChallenger)(nil)
|
|||||||
// NewLndChallenger creates a new challenger that uses the given connection to
|
// NewLndChallenger creates a new challenger that uses the given connection to
|
||||||
// an lnd backend to create payment challenges.
|
// an lnd backend to create payment challenges.
|
||||||
func NewLndChallenger(client InvoiceClient, batchSize int,
|
func NewLndChallenger(client InvoiceClient, batchSize int,
|
||||||
genInvoiceReq InvoiceRequestGenerator,
|
genInvoiceReq InvoiceRequestGenerator, ctxFunc func() context.Context,
|
||||||
ctxFunc func() context.Context,
|
errChan chan<- error, strictVerification bool) (*LndChallenger, error) {
|
||||||
errChan chan<- error) (*LndChallenger, error) {
|
|
||||||
|
|
||||||
// Make sure we have a valid context function. This will be called to
|
// Make sure we have a valid context function. This will be called to
|
||||||
// create a new context for each call to the lnd client.
|
// create a new context for each call to the lnd client.
|
||||||
@@ -63,6 +66,7 @@ func NewLndChallenger(client InvoiceClient, batchSize int,
|
|||||||
invoicesCond: sync.NewCond(invoicesMtx),
|
invoicesCond: sync.NewCond(invoicesMtx),
|
||||||
quit: make(chan struct{}),
|
quit: make(chan struct{}),
|
||||||
errChan: errChan,
|
errChan: errChan,
|
||||||
|
strictVerify: strictVerification,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := challenger.Start()
|
err := challenger.Start()
|
||||||
@@ -78,6 +82,14 @@ func NewLndChallenger(client InvoiceClient, batchSize int,
|
|||||||
// invoices on startup and a subscription to all subsequent invoice updates
|
// invoices on startup and a subscription to all subsequent invoice updates
|
||||||
// is created.
|
// is created.
|
||||||
func (l *LndChallenger) Start() error {
|
func (l *LndChallenger) Start() error {
|
||||||
|
// If we aren't doing strict verification, then we can just exit here as
|
||||||
|
// we don't need the invoice state.
|
||||||
|
if !l.strictVerify {
|
||||||
|
log.Infof("Skipping invoice state tracking strict_verify=%v",
|
||||||
|
l.strictVerify)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// These are the default values for the subscription. In case there are
|
// These are the default values for the subscription. In case there are
|
||||||
// no invoices yet, this will instruct lnd to just send us all updates.
|
// no invoices yet, this will instruct lnd to just send us all updates.
|
||||||
// If there are existing invoices, these indices will be updated to
|
// If there are existing invoices, these indices will be updated to
|
||||||
@@ -303,6 +315,12 @@ func (l *LndChallenger) NewChallenge(price int64) (string, lntypes.Hash,
|
|||||||
func (l *LndChallenger) VerifyInvoiceStatus(hash lntypes.Hash,
|
func (l *LndChallenger) VerifyInvoiceStatus(hash lntypes.Hash,
|
||||||
state lnrpc.Invoice_InvoiceState, timeout time.Duration) error {
|
state lnrpc.Invoice_InvoiceState, timeout time.Duration) error {
|
||||||
|
|
||||||
|
// If we're not doing strict verification, we can skip this check.
|
||||||
|
if !l.strictVerify {
|
||||||
|
log.Tracef("Skipping invoice state check, pay_hash=%v", hash)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Prevent the challenger to be shut down while we're still waiting for
|
// Prevent the challenger to be shut down while we're still waiting for
|
||||||
// status updates.
|
// status updates.
|
||||||
l.wg.Add(1)
|
l.wg.Add(1)
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ func newChallenger() (*LndChallenger, *mockInvoiceClient, chan error) {
|
|||||||
invoicesMtx: invoicesMtx,
|
invoicesMtx: invoicesMtx,
|
||||||
invoicesCond: sync.NewCond(invoicesMtx),
|
invoicesCond: sync.NewCond(invoicesMtx),
|
||||||
errChan: mainErrChan,
|
errChan: mainErrChan,
|
||||||
|
strictVerify: true,
|
||||||
}, mockClient, mainErrChan
|
}, mockClient, mainErrChan
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,7 +143,7 @@ func TestLndChallenger(t *testing.T) {
|
|||||||
// First of all, test that the NewLndChallenger doesn't allow a nil
|
// First of all, test that the NewLndChallenger doesn't allow a nil
|
||||||
// invoice generator function.
|
// invoice generator function.
|
||||||
errChan := make(chan error)
|
errChan := make(chan error)
|
||||||
_, err := NewLndChallenger(nil, 1, nil, nil, errChan)
|
_, err := NewLndChallenger(nil, 1, nil, nil, errChan, true)
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
|
|
||||||
// Now mock the lnd backend and create a challenger instance that we can
|
// Now mock the lnd backend and create a challenger instance that we can
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ var (
|
|||||||
defaultLogLevel = "info"
|
defaultLogLevel = "info"
|
||||||
defaultLogFilename = "aperture.log"
|
defaultLogFilename = "aperture.log"
|
||||||
defaultInvoiceBatchSize = 100000
|
defaultInvoiceBatchSize = 100000
|
||||||
|
defaultStrictVerify = false
|
||||||
|
|
||||||
defaultSqliteDatabaseFileName = "aperture.db"
|
defaultSqliteDatabaseFileName = "aperture.db"
|
||||||
|
|
||||||
@@ -224,6 +225,11 @@ type Config struct {
|
|||||||
// request.
|
// request.
|
||||||
InvoiceBatchSize int `long:"invoicebatchsize" description:"The number of invoices to fetch in a single request."`
|
InvoiceBatchSize int `long:"invoicebatchsize" description:"The number of invoices to fetch in a single request."`
|
||||||
|
|
||||||
|
// StrictVerify is a flag that indicates whether we should verify the
|
||||||
|
// invoice status strictly or not. If set to true, then this requires
|
||||||
|
// all invoices to be read from disk at start up.
|
||||||
|
StrictVerify bool `long:"strictverify" description:"Whether to verify the invoice status strictly or not."`
|
||||||
|
|
||||||
// Logging controls various aspects of aperture logging.
|
// Logging controls various aspects of aperture logging.
|
||||||
Logging *build.LogConfig `group:"logging" namespace:"logging"`
|
Logging *build.LogConfig `group:"logging" namespace:"logging"`
|
||||||
|
|
||||||
@@ -274,5 +280,6 @@ func NewConfig() *Config {
|
|||||||
InvoiceBatchSize: defaultInvoiceBatchSize,
|
InvoiceBatchSize: defaultInvoiceBatchSize,
|
||||||
Logging: build.DefaultLogConfig(),
|
Logging: build.DefaultLogConfig(),
|
||||||
Blocklist: []string{},
|
Blocklist: []string{},
|
||||||
|
StrictVerify: defaultStrictVerify,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,10 @@ debuglevel: "debug"
|
|||||||
autocert: false
|
autocert: false
|
||||||
servername: aperture.example.com
|
servername: aperture.example.com
|
||||||
|
|
||||||
|
# Whether we should verify the invoice status strictly or not. If set to true,
|
||||||
|
# then this requires all invoices to be read from disk at start up.
|
||||||
|
strictverify: false
|
||||||
|
|
||||||
# The port on which the pprof profile will be served. If no port is provided,
|
# The port on which the pprof profile will be served. If no port is provided,
|
||||||
# the profile will not be served.
|
# the profile will not be served.
|
||||||
profile: 9999
|
profile: 9999
|
||||||
|
|||||||
Reference in New Issue
Block a user