contractcourt: specify deadline and budget for commit sweep

This commit is contained in:
yyforyongyu 2024-03-02 17:46:14 +08:00
parent aa44197f88
commit 01fd4e5642
No known key found for this signature in database
GPG Key ID: 9BCD95C4FF296868
4 changed files with 101 additions and 19 deletions

View File

@ -13,17 +13,12 @@ import (
"github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcd/wire"
"github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/fn"
"github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/sweep" "github.com/lightningnetwork/lnd/sweep"
) )
const (
// commitOutputConfTarget is the default confirmation target we'll use
// for sweeps of commit outputs that belong to us.
commitOutputConfTarget = 6
)
// commitSweepResolver is a resolver that will attempt to sweep the commitment // commitSweepResolver is a resolver that will attempt to sweep the commitment
// output paying to us, in the case that the remote party broadcasts their // output paying to us, in the case that the remote party broadcasts their
// version of the commitment transaction. We can sweep this output immediately, // version of the commitment transaction. We can sweep this output immediately,
@ -347,12 +342,23 @@ func (c *commitSweepResolver) Resolve() (ContractResolver, error) {
// TODO(roasbeef): instead of ading ctrl block to the sign desc, make // TODO(roasbeef): instead of ading ctrl block to the sign desc, make
// new input type, have sweeper set it? // new input type, have sweeper set it?
// With our input constructed, we'll now offer it to the // Calculate the budget for the sweeping this input.
// sweeper. budget := calculateBudget(
c.log.Infof("sweeping commit output") btcutil.Amount(inp.SignDesc().Output.Value),
c.Budget.ToLocalRatio, c.Budget.ToLocal,
)
c.log.Infof("Sweeping commit output using budget=%v", budget)
feePref := sweep.FeeEstimateInfo{ConfTarget: commitOutputConfTarget} // With our input constructed, we'll now offer it to the sweeper.
resultChan, err := c.Sweeper.SweepInput(inp, sweep.Params{Fee: feePref}) resultChan, err := c.Sweeper.SweepInput(
inp, sweep.Params{
Budget: budget,
// Specify a nil deadline here as there's no time
// pressure.
DeadlineHeight: fn.None[int32](),
},
)
if err != nil { if err != nil {
c.log.Errorf("unable to sweep input: %v", err) c.log.Errorf("unable to sweep input: %v", err)

View File

@ -129,15 +129,18 @@ func (s *mockSweeper) SweepInput(input input.Input, params sweep.Params) (
s.sweptInputs <- input s.sweptInputs <- input
// TODO(yy): use `mock.Mock` to avoid the conversion. // TODO(yy): replace mockSweeper with `mock.Mock`.
fee, ok := params.Fee.(sweep.FeeEstimateInfo) if params.Fee != nil {
if !ok { fee, ok := params.Fee.(sweep.FeeEstimateInfo)
return nil, fmt.Errorf("unexpected fee type: %T", params.Fee) if !ok {
} return nil, fmt.Errorf("unexpected fee type: %T",
params.Fee)
}
// Update the deadlines used if it's set. // Update the deadlines used if it's set.
if fee.ConfTarget != 0 { if fee.ConfTarget != 0 {
s.deadlines = append(s.deadlines, int(fee.ConfTarget)) s.deadlines = append(s.deadlines, int(fee.ConfTarget))
}
} }
result := make(chan sweep.Result, 1) result := make(chan sweep.Result, 1)

View File

@ -111,3 +111,27 @@ func DefaultBudgetConfig() *BudgetConfig {
NoDeadlineHTLCRatio: DefaultBudgetRatio, NoDeadlineHTLCRatio: DefaultBudgetRatio,
} }
} }
// calculateBudget takes an output value, a configured ratio and budget value,
// and returns the budget to use for sweeping the output. If the budget value
// is set, it will be used as cap.
func calculateBudget(value btcutil.Amount, ratio float64,
max btcutil.Amount) btcutil.Amount {
// If ratio is not set, using the default value.
if ratio == 0 {
ratio = DefaultBudgetRatio
}
budget := value.MulF64(ratio)
log.Tracef("Calculated budget=%v using value=%v, ratio=%v, cap=%v",
budget, value, ratio, max)
if max != 0 && budget > max {
log.Debugf("Calculated budget=%v is capped at %v", budget, max)
return max
}
return budget
}

View File

@ -3,6 +3,7 @@ package contractcourt
import ( import (
"testing" "testing"
"github.com/btcsuite/btcd/btcutil"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -81,3 +82,51 @@ func TestBudgetConfigValidate(t *testing.T) {
}) })
} }
} }
// TestCalculateBudget checks that the budget calculation works as expected.
func TestCalculateBudget(t *testing.T) {
t.Parallel()
testCases := []struct {
name string
value btcutil.Amount
ratio float64
max btcutil.Amount
expected btcutil.Amount
}{
{
// When the ratio is not specified, the default 0.5
// should be used.
name: "use default ratio",
value: btcutil.Amount(1000),
ratio: 0,
max: 0,
expected: btcutil.Amount(500),
},
{
// When the ratio is specified, the default is not
// used.
name: "use specified ratio",
value: btcutil.Amount(1000),
ratio: 0.1,
max: 0,
expected: btcutil.Amount(100),
},
{
// When the max is specified, the budget should be
// capped at that value.
name: "budget capped at max",
value: btcutil.Amount(1000),
ratio: 0.1,
max: btcutil.Amount(1),
expected: btcutil.Amount(1),
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
budget := calculateBudget(tc.value, tc.ratio, tc.max)
require.Equal(t, tc.expected, budget)
})
}
}