Skip to content

Commit 729bc70

Browse files
jharveybRoasbeef
authored andcommitted
tapgarden: accept fee rate arg on batch finalize
In this commit, we add support for overriding the fee estimator and providing a target fee rate to the planter when finalizing a batch. Provided fee rates are only checked against a minimum value and not a maximum fee rate.
1 parent b5e647c commit 729bc70

File tree

3 files changed

+57
-16
lines changed

3 files changed

+57
-16
lines changed

tapgarden/caretaker.go

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"github.com/lightninglabs/taproot-assets/proof"
2525
"github.com/lightninglabs/taproot-assets/universe"
2626
"github.com/lightningnetwork/lnd/chainntnfs"
27+
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
2728
"golang.org/x/exp/maps"
2829
"golang.org/x/sync/errgroup"
2930
)
@@ -75,6 +76,10 @@ type BatchCaretakerConfig struct {
7576
// Batch is the minting batch that this caretaker is responsible for?
7677
Batch *MintingBatch
7778

79+
// BatchFeeRate is an optional manually-set feerate specified when
80+
// finalizing a batch.
81+
BatchFeeRate *chainfee.SatPerKWeight
82+
7883
GardenKit
7984

8085
// BroadcastCompleteChan is used to signal back to the caller that the
@@ -389,13 +394,26 @@ func (b *BatchCaretaker) fundGenesisPsbt(ctx context.Context) (*FundedPsbt, erro
389394
log.Infof("BatchCaretaker(%x): creating skeleton PSBT", b.batchKey[:])
390395
log.Tracef("PSBT: %v", spew.Sdump(genesisPkt))
391396

392-
feeRate, err := b.cfg.ChainBridge.EstimateFee(
393-
ctx, GenesisConfTarget,
394-
)
395-
if err != nil {
396-
return nil, fmt.Errorf("unable to estimate fee: %w", err)
397+
// If a fee rate was manually assigned for this batch, use that instead
398+
// of a fee rate estimate.
399+
var feeRate chainfee.SatPerKWeight
400+
switch {
401+
case b.cfg.BatchFeeRate != nil:
402+
feeRate = *b.cfg.BatchFeeRate
403+
log.Infof("BatchCaretaker(%x): using manual fee rate")
404+
405+
default:
406+
feeRate, err = b.cfg.ChainBridge.EstimateFee(
407+
ctx, GenesisConfTarget,
408+
)
409+
if err != nil {
410+
return nil, fmt.Errorf("unable to estimate fee: %w", err)
411+
}
397412
}
398413

414+
log.Infof("BatchCaretaker(%x): using fee rate: %v",
415+
feeRate.FeePerKVByte().String())
416+
399417
fundedGenesisPkt, err := b.cfg.Wallet.FundPsbt(
400418
ctx, genesisPkt, 1, feeRate,
401419
)
@@ -726,6 +744,8 @@ func (b *BatchCaretaker) stateStep(currentState BatchState) (BatchState, error)
726744
}
727745
b.cfg.Batch.GenesisPacket.ChainFees = chainFees
728746

747+
log.Infof("BatchCaretaker(%x): GenesisPacket absolute fee: "+
748+
"%d sats", chainFees)
729749
log.Infof("BatchCaretaker(%x): GenesisPacket finalized",
730750
b.batchKey[:])
731751
log.Tracef("GenesisPacket: %v", spew.Sdump(signedPkt))

tapgarden/interface.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ type Planter interface {
4444

4545
// FinalizeBatch signals that the asset minter should finalize
4646
// the current batch, if one exists.
47-
FinalizeBatch() (*MintingBatch, error)
47+
FinalizeBatch(feeRate *chainfee.SatPerKWeight) (*MintingBatch, error)
4848

4949
// CancelBatch signals that the asset minter should cancel the
5050
// current batch, if one exists.

tapgarden/planter.go

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/lightninglabs/taproot-assets/proof"
1515
"github.com/lightninglabs/taproot-assets/tapscript"
1616
"github.com/lightninglabs/taproot-assets/universe"
17+
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
1718
"github.com/lightningnetwork/lnd/ticker"
1819
"golang.org/x/exp/maps"
1920
)
@@ -227,9 +228,11 @@ func NewChainPlanter(cfg PlanterConfig) *ChainPlanter {
227228

228229
// newCaretakerForBatch creates a new BatchCaretaker for a given batch and
229230
// inserts it into the caretaker map.
230-
func (c *ChainPlanter) newCaretakerForBatch(batch *MintingBatch) *BatchCaretaker {
231+
func (c *ChainPlanter) newCaretakerForBatch(batch *MintingBatch,
232+
feeRate *chainfee.SatPerKWeight) *BatchCaretaker {
233+
231234
batchKey := asset.ToSerialized(batch.BatchKey.PubKey)
232-
caretaker := NewBatchCaretaker(&BatchCaretakerConfig{
235+
batchConfig := &BatchCaretakerConfig{
233236
Batch: batch,
234237
GardenKit: c.cfg.GardenKit,
235238
BroadcastCompleteChan: make(chan struct{}, 1),
@@ -241,7 +244,12 @@ func (c *ChainPlanter) newCaretakerForBatch(batch *MintingBatch) *BatchCaretaker
241244
CancelRespChan: make(chan CancelResp, 1),
242245
UpdateMintingProofs: c.updateMintingProofs,
243246
ErrChan: c.cfg.ErrChan,
244-
})
247+
}
248+
if feeRate != nil {
249+
batchConfig.BatchFeeRate = feeRate
250+
}
251+
252+
caretaker := NewBatchCaretaker(batchConfig)
245253
c.caretakers[batchKey] = caretaker
246254

247255
return caretaker
@@ -296,7 +304,8 @@ func (c *ChainPlanter) Start() error {
296304
batch.AssetMetas = make(AssetMetas)
297305
}
298306

299-
caretaker := c.newCaretakerForBatch(batch)
307+
// TODO(jhb): Log manual fee rates?
308+
caretaker := c.newCaretakerForBatch(batch, nil)
300309
if err := caretaker.Start(); err != nil {
301310
startErr = err
302311
return
@@ -485,7 +494,7 @@ func (c *ChainPlanter) gardener() {
485494
continue
486495
}
487496

488-
_, err := c.finalizeBatch()
497+
_, err := c.finalizeBatch(nil)
489498
if err != nil {
490499
c.cfg.ErrChan <- fmt.Errorf("unable to freeze "+
491500
"minting batch: %w", err)
@@ -590,7 +599,15 @@ func (c *ChainPlanter) gardener() {
590599
log.Infof("Finalizing batch %x",
591600
batchKey.SerializeCompressed())
592601

593-
caretaker, err := c.finalizeBatch()
602+
feeRate, err :=
603+
typedParam[*chainfee.SatPerKWeight](req)
604+
if err != nil {
605+
req.Error(fmt.Errorf("bad fee rate: "+
606+
"%w", err))
607+
break
608+
}
609+
610+
caretaker, err := c.finalizeBatch(*feeRate)
594611
if err != nil {
595612
c.cfg.ErrChan <- fmt.Errorf("unable "+
596613
"to freeze minting batch: %w",
@@ -643,10 +660,12 @@ func (c *ChainPlanter) gardener() {
643660
}
644661

645662
// finalizeBatch creates a new caretaker for the batch and starts it.
646-
func (c *ChainPlanter) finalizeBatch() (*BatchCaretaker, error) {
663+
func (c *ChainPlanter) finalizeBatch(
664+
feeRate *chainfee.SatPerKWeight) (*BatchCaretaker, error) {
665+
647666
// Prep the new care taker that'll be launched assuming the call below
648667
// to freeze the batch succeeds.
649-
caretaker := c.newCaretakerForBatch(c.pendingBatch)
668+
caretaker := c.newCaretakerForBatch(c.pendingBatch, feeRate)
650669

651670
// At this point, we have a non-empty batch, so we'll first finalize it
652671
// on disk. This means no further seedlings can be added to this batch.
@@ -707,8 +726,10 @@ func (c *ChainPlanter) ListBatches(batchKey *btcec.PublicKey) ([]*MintingBatch,
707726
}
708727

709728
// FinalizeBatch sends a signal to the planter to finalize the current batch.
710-
func (c *ChainPlanter) FinalizeBatch() (*MintingBatch, error) {
711-
req := newStateReq[*MintingBatch](reqTypeFinalizeBatch)
729+
func (c *ChainPlanter) FinalizeBatch(
730+
feeRate *chainfee.SatPerKWeight) (*MintingBatch, error) {
731+
732+
req := newStateParamReq[*MintingBatch](reqTypeFinalizeBatch, feeRate)
712733

713734
if !fn.SendOrQuit[stateRequest](c.stateReqs, req, c.Quit) {
714735
return nil, fmt.Errorf("chain planter shutting down")

0 commit comments

Comments
 (0)