Skip to content

Commit 7c93dff

Browse files
committed
sweepbatcher: add option WithPublishErrorHandler
WithPublishErrorHandler sets the callback used to handle publish errors. It can be used to filter out noisy messages.
1 parent 6b852c1 commit 7c93dff

File tree

3 files changed

+281
-97
lines changed

3 files changed

+281
-97
lines changed

sweepbatcher/sweep_batch.go

Lines changed: 84 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,11 @@ type batch struct {
282282
// verifySchnorrSig is a function that verifies a schnorr signature.
283283
verifySchnorrSig VerifySchnorrSig
284284

285+
// publishErrorHandler is a function that handles transaction publishing
286+
// error. By default, it logs all errors as warnings, but "insufficient
287+
// fee" as Info.
288+
publishErrorHandler PublishErrorHandler
289+
285290
// purger is a function that can take a sweep which is being purged and
286291
// hand it over to the batcher for further processing.
287292
purger Purger
@@ -308,23 +313,24 @@ type Purger func(sweepReq *SweepRequest) error
308313
// struct is only used as a wrapper for the arguments that are required to
309314
// create a new batch.
310315
type batchKit struct {
311-
id int32
312-
batchTxid *chainhash.Hash
313-
batchPkScript []byte
314-
state batchState
315-
primaryID lntypes.Hash
316-
sweeps map[lntypes.Hash]sweep
317-
rbfCache rbfCache
318-
returnChan chan SweepRequest
319-
wallet lndclient.WalletKitClient
320-
chainNotifier lndclient.ChainNotifierClient
321-
signerClient lndclient.SignerClient
322-
musig2SignSweep MuSig2SignSweep
323-
verifySchnorrSig VerifySchnorrSig
324-
purger Purger
325-
store BatcherStore
326-
log btclog.Logger
327-
quit chan struct{}
316+
id int32
317+
batchTxid *chainhash.Hash
318+
batchPkScript []byte
319+
state batchState
320+
primaryID lntypes.Hash
321+
sweeps map[lntypes.Hash]sweep
322+
rbfCache rbfCache
323+
returnChan chan SweepRequest
324+
wallet lndclient.WalletKitClient
325+
chainNotifier lndclient.ChainNotifierClient
326+
signerClient lndclient.SignerClient
327+
musig2SignSweep MuSig2SignSweep
328+
verifySchnorrSig VerifySchnorrSig
329+
publishErrorHandler PublishErrorHandler
330+
purger Purger
331+
store BatcherStore
332+
log btclog.Logger
333+
quit chan struct{}
328334
}
329335

330336
// scheduleNextCall schedules the next call to the batch handler's main event
@@ -353,28 +359,29 @@ func NewBatch(cfg batchConfig, bk batchKit) *batch {
353359
return &batch{
354360
// We set the ID to a negative value to flag that this batch has
355361
// never been persisted, so it needs to be assigned a new ID.
356-
id: -1,
357-
state: Open,
358-
sweeps: make(map[lntypes.Hash]sweep),
359-
blockEpochChan: make(chan int32),
360-
spendChan: make(chan *chainntnfs.SpendDetail),
361-
confChan: make(chan *chainntnfs.TxConfirmation, 1),
362-
reorgChan: make(chan struct{}, 1),
363-
errChan: make(chan error, 1),
364-
callEnter: make(chan struct{}),
365-
callLeave: make(chan struct{}),
366-
stopping: make(chan struct{}),
367-
finished: make(chan struct{}),
368-
quit: bk.quit,
369-
batchTxid: bk.batchTxid,
370-
wallet: bk.wallet,
371-
chainNotifier: bk.chainNotifier,
372-
signerClient: bk.signerClient,
373-
muSig2SignSweep: bk.musig2SignSweep,
374-
verifySchnorrSig: bk.verifySchnorrSig,
375-
purger: bk.purger,
376-
store: bk.store,
377-
cfg: &cfg,
362+
id: -1,
363+
state: Open,
364+
sweeps: make(map[lntypes.Hash]sweep),
365+
blockEpochChan: make(chan int32),
366+
spendChan: make(chan *chainntnfs.SpendDetail),
367+
confChan: make(chan *chainntnfs.TxConfirmation, 1),
368+
reorgChan: make(chan struct{}, 1),
369+
errChan: make(chan error, 1),
370+
callEnter: make(chan struct{}),
371+
callLeave: make(chan struct{}),
372+
stopping: make(chan struct{}),
373+
finished: make(chan struct{}),
374+
quit: bk.quit,
375+
batchTxid: bk.batchTxid,
376+
wallet: bk.wallet,
377+
chainNotifier: bk.chainNotifier,
378+
signerClient: bk.signerClient,
379+
muSig2SignSweep: bk.musig2SignSweep,
380+
verifySchnorrSig: bk.verifySchnorrSig,
381+
publishErrorHandler: bk.publishErrorHandler,
382+
purger: bk.purger,
383+
store: bk.store,
384+
cfg: &cfg,
378385
}
379386
}
380387

@@ -396,32 +403,33 @@ func NewBatchFromDB(cfg batchConfig, bk batchKit) (*batch, error) {
396403
}
397404

398405
return &batch{
399-
id: bk.id,
400-
state: bk.state,
401-
primarySweepID: bk.primaryID,
402-
sweeps: bk.sweeps,
403-
blockEpochChan: make(chan int32),
404-
spendChan: make(chan *chainntnfs.SpendDetail),
405-
confChan: make(chan *chainntnfs.TxConfirmation, 1),
406-
reorgChan: make(chan struct{}, 1),
407-
errChan: make(chan error, 1),
408-
callEnter: make(chan struct{}),
409-
callLeave: make(chan struct{}),
410-
stopping: make(chan struct{}),
411-
finished: make(chan struct{}),
412-
quit: bk.quit,
413-
batchTxid: bk.batchTxid,
414-
batchPkScript: bk.batchPkScript,
415-
rbfCache: bk.rbfCache,
416-
wallet: bk.wallet,
417-
chainNotifier: bk.chainNotifier,
418-
signerClient: bk.signerClient,
419-
muSig2SignSweep: bk.musig2SignSweep,
420-
verifySchnorrSig: bk.verifySchnorrSig,
421-
purger: bk.purger,
422-
store: bk.store,
423-
log: bk.log,
424-
cfg: &cfg,
406+
id: bk.id,
407+
state: bk.state,
408+
primarySweepID: bk.primaryID,
409+
sweeps: bk.sweeps,
410+
blockEpochChan: make(chan int32),
411+
spendChan: make(chan *chainntnfs.SpendDetail),
412+
confChan: make(chan *chainntnfs.TxConfirmation, 1),
413+
reorgChan: make(chan struct{}, 1),
414+
errChan: make(chan error, 1),
415+
callEnter: make(chan struct{}),
416+
callLeave: make(chan struct{}),
417+
stopping: make(chan struct{}),
418+
finished: make(chan struct{}),
419+
quit: bk.quit,
420+
batchTxid: bk.batchTxid,
421+
batchPkScript: bk.batchPkScript,
422+
rbfCache: bk.rbfCache,
423+
wallet: bk.wallet,
424+
chainNotifier: bk.chainNotifier,
425+
signerClient: bk.signerClient,
426+
muSig2SignSweep: bk.musig2SignSweep,
427+
verifySchnorrSig: bk.verifySchnorrSig,
428+
publishErrorHandler: bk.publishErrorHandler,
429+
purger: bk.purger,
430+
store: bk.store,
431+
log: bk.log,
432+
cfg: &cfg,
425433
}, nil
426434
}
427435

@@ -795,23 +803,31 @@ func (b *batch) publish(ctx context.Context) error {
795803
return err
796804
}
797805

806+
// logPublishError is a function which logs publish errors.
807+
logPublishError := func(errMsg string, err error) {
808+
b.publishErrorHandler(err, errMsg, b.log)
809+
}
810+
798811
if b.cfg.mixedBatch {
799812
fee, err, signSuccess = b.publishMixedBatch(ctx)
800813
if err != nil {
801-
b.log.Warnf("Mixed batch publish error: %v", err)
814+
logPublishError("mixed batch publish error", err)
802815
}
803816
} else {
804817
fee, err, signSuccess = b.publishBatchCoop(ctx)
805818
if err != nil {
806-
b.log.Warnf("co-op publish error: %v", err)
819+
logPublishError("co-op publish error", err)
807820
}
808821
}
809822

810823
if !signSuccess {
811824
fee, err = b.publishBatch(ctx)
825+
if err != nil {
826+
logPublishError("non-coop publish error", err)
827+
}
812828
}
829+
813830
if err != nil {
814-
b.log.Warnf("publish error: %v", err)
815831
return nil
816832
}
817833

sweepbatcher/sweep_batcher.go

Lines changed: 76 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"errors"
66
"fmt"
7+
"strings"
78
"sync"
89
"time"
910

@@ -12,6 +13,8 @@ import (
1213
"github.com/btcsuite/btcd/chaincfg"
1314
"github.com/btcsuite/btcd/chaincfg/chainhash"
1415
"github.com/btcsuite/btcd/wire"
16+
"github.com/btcsuite/btclog"
17+
"github.com/btcsuite/btcwallet/chain"
1518
"github.com/lightninglabs/lndclient"
1619
"github.com/lightninglabs/loop/labels"
1720
"github.com/lightninglabs/loop/loopdb"
@@ -159,6 +162,25 @@ type VerifySchnorrSig func(pubKey *btcec.PublicKey, hash, sig []byte) error
159162
type FeeRateProvider func(ctx context.Context,
160163
swapHash lntypes.Hash) (chainfee.SatPerKWeight, error)
161164

165+
// PublishErrorHandler is a function that handles transaction publishing error.
166+
type PublishErrorHandler func(err error, errMsg string, log btclog.Logger)
167+
168+
// defaultPublishErrorLogger is an instance of PublishErrorHandler which logs
169+
// all errors as warnings, but "insufficient fee" as info (since they are
170+
// expected, if RBF fails).
171+
func defaultPublishErrorLogger(err error, errMsg string, log btclog.Logger) {
172+
// Check if the error is "insufficient fee" error.
173+
if strings.Contains(err.Error(), chain.ErrInsufficientFee.Error()) {
174+
// Log "insufficient fee" with level Info.
175+
log.Infof("%s: %v", errMsg, err)
176+
177+
return
178+
}
179+
180+
// Log any other error as a warning.
181+
log.Warnf("%s: %v", errMsg, err)
182+
}
183+
162184
// SweepRequest is a request to sweep a specific outpoint.
163185
type SweepRequest struct {
164186
// SwapHash is the hash of the swap that is being swept.
@@ -296,6 +318,11 @@ type Batcher struct {
296318
// expensive) way. If the whole procedure fails for whatever reason, the
297319
// batch is signed non-cooperatively (the fallback).
298320
mixedBatch bool
321+
322+
// publishErrorHandler is a function that handles transaction publishing
323+
// error. By default, it logs all errors as warnings, but "insufficient
324+
// fee" as Info.
325+
publishErrorHandler PublishErrorHandler
299326
}
300327

301328
// BatcherConfig holds batcher configuration.
@@ -341,6 +368,11 @@ type BatcherConfig struct {
341368
// expensive) way. If the whole procedure fails for whatever reason, the
342369
// batch is signed non-cooperatively (the fallback).
343370
mixedBatch bool
371+
372+
// publishErrorHandler is a function that handles transaction publishing
373+
// error. By default, it logs all errors as warnings, but "insufficient
374+
// fee" as Info.
375+
publishErrorHandler PublishErrorHandler
344376
}
345377

346378
// BatcherOption configures batcher behaviour.
@@ -420,6 +452,14 @@ func WithMixedBatch() BatcherOption {
420452
}
421453
}
422454

455+
// WithPublishErrorHandler sets the callback used to handle publish errors.
456+
// It can be used to filter out noisy messages.
457+
func WithPublishErrorHandler(handler PublishErrorHandler) BatcherOption {
458+
return func(cfg *BatcherConfig) {
459+
cfg.publishErrorHandler = handler
460+
}
461+
}
462+
423463
// NewBatcher creates a new Batcher instance.
424464
func NewBatcher(wallet lndclient.WalletKitClient,
425465
chainNotifier lndclient.ChainNotifierClient,
@@ -432,6 +472,11 @@ func NewBatcher(wallet lndclient.WalletKitClient,
432472
// By default, loop/labels.LoopOutBatchSweepSuccess is used
433473
// to label sweep transactions.
434474
txLabeler: labels.LoopOutBatchSweepSuccess,
475+
476+
// publishErrorHandler is a function that handles transaction
477+
// publishing error. By default, it logs all errors as warnings,
478+
// but "insufficient fee" as Info.
479+
publishErrorHandler: defaultPublishErrorLogger,
435480
}
436481
for _, opt := range opts {
437482
opt(&cfg)
@@ -448,26 +493,27 @@ func NewBatcher(wallet lndclient.WalletKitClient,
448493
}
449494

450495
return &Batcher{
451-
batches: make(map[int32]*batch),
452-
sweepReqs: make(chan SweepRequest),
453-
errChan: make(chan error, 1),
454-
quit: make(chan struct{}),
455-
initDone: make(chan struct{}),
456-
wallet: wallet,
457-
chainNotifier: chainNotifier,
458-
signerClient: signerClient,
459-
musig2ServerSign: musig2ServerSigner,
460-
VerifySchnorrSig: verifySchnorrSig,
461-
chainParams: chainparams,
462-
store: store,
463-
sweepStore: sweepStore,
464-
clock: cfg.clock,
465-
initialDelay: cfg.initialDelay,
466-
publishDelay: cfg.publishDelay,
467-
customFeeRate: cfg.customFeeRate,
468-
txLabeler: cfg.txLabeler,
469-
customMuSig2Signer: cfg.customMuSig2Signer,
470-
mixedBatch: cfg.mixedBatch,
496+
batches: make(map[int32]*batch),
497+
sweepReqs: make(chan SweepRequest),
498+
errChan: make(chan error, 1),
499+
quit: make(chan struct{}),
500+
initDone: make(chan struct{}),
501+
wallet: wallet,
502+
chainNotifier: chainNotifier,
503+
signerClient: signerClient,
504+
musig2ServerSign: musig2ServerSigner,
505+
VerifySchnorrSig: verifySchnorrSig,
506+
chainParams: chainparams,
507+
store: store,
508+
sweepStore: sweepStore,
509+
clock: cfg.clock,
510+
initialDelay: cfg.initialDelay,
511+
publishDelay: cfg.publishDelay,
512+
customFeeRate: cfg.customFeeRate,
513+
txLabeler: cfg.txLabeler,
514+
customMuSig2Signer: cfg.customMuSig2Signer,
515+
mixedBatch: cfg.mixedBatch,
516+
publishErrorHandler: cfg.publishErrorHandler,
471517
}
472518
}
473519

@@ -1092,14 +1138,15 @@ func (b *Batcher) newBatchConfig(maxTimeoutDistance int32) batchConfig {
10921138
// newBatchKit creates new batch kit.
10931139
func (b *Batcher) newBatchKit() batchKit {
10941140
return batchKit{
1095-
returnChan: b.sweepReqs,
1096-
wallet: b.wallet,
1097-
chainNotifier: b.chainNotifier,
1098-
signerClient: b.signerClient,
1099-
musig2SignSweep: b.musig2ServerSign,
1100-
verifySchnorrSig: b.VerifySchnorrSig,
1101-
purger: b.AddSweep,
1102-
store: b.store,
1103-
quit: b.quit,
1141+
returnChan: b.sweepReqs,
1142+
wallet: b.wallet,
1143+
chainNotifier: b.chainNotifier,
1144+
signerClient: b.signerClient,
1145+
musig2SignSweep: b.musig2ServerSign,
1146+
verifySchnorrSig: b.VerifySchnorrSig,
1147+
publishErrorHandler: b.publishErrorHandler,
1148+
purger: b.AddSweep,
1149+
store: b.store,
1150+
quit: b.quit,
11041151
}
11051152
}

0 commit comments

Comments
 (0)