mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-02-22 22:25:24 +01:00
contractcourt: specify deadline and budget for nursery
This commit is contained in:
parent
33abbe1942
commit
9c1e6941c3
9 changed files with 68 additions and 23 deletions
|
@ -122,7 +122,8 @@ type ChainArbitratorConfig struct {
|
||||||
// absolute/relative item block.
|
// absolute/relative item block.
|
||||||
IncubateOutputs func(wire.OutPoint,
|
IncubateOutputs func(wire.OutPoint,
|
||||||
fn.Option[lnwallet.OutgoingHtlcResolution],
|
fn.Option[lnwallet.OutgoingHtlcResolution],
|
||||||
fn.Option[lnwallet.IncomingHtlcResolution], uint32) error
|
fn.Option[lnwallet.IncomingHtlcResolution],
|
||||||
|
uint32, fn.Option[int32]) error
|
||||||
|
|
||||||
// PreimageDB is a global store of all known pre-images. We'll use this
|
// PreimageDB is a global store of all known pre-images. We'll use this
|
||||||
// to decide if we should broadcast a commitment transaction to claim
|
// to decide if we should broadcast a commitment transaction to claim
|
||||||
|
|
|
@ -364,7 +364,7 @@ func createTestChannelArbitrator(t *testing.T, log ArbitratorLog,
|
||||||
IncubateOutputs: func(wire.OutPoint,
|
IncubateOutputs: func(wire.OutPoint,
|
||||||
fn.Option[lnwallet.OutgoingHtlcResolution],
|
fn.Option[lnwallet.OutgoingHtlcResolution],
|
||||||
fn.Option[lnwallet.IncomingHtlcResolution],
|
fn.Option[lnwallet.IncomingHtlcResolution],
|
||||||
uint32) error {
|
uint32, fn.Option[int32]) error {
|
||||||
|
|
||||||
incubateChan <- struct{}{}
|
incubateChan <- struct{}{}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -208,7 +208,7 @@ func (h *htlcSuccessResolver) broadcastSuccessTx() (*wire.OutPoint, error) {
|
||||||
err := h.IncubateOutputs(
|
err := h.IncubateOutputs(
|
||||||
h.ChanPoint, fn.None[lnwallet.OutgoingHtlcResolution](),
|
h.ChanPoint, fn.None[lnwallet.OutgoingHtlcResolution](),
|
||||||
fn.Some(h.htlcResolution),
|
fn.Some(h.htlcResolution),
|
||||||
h.broadcastHeight,
|
h.broadcastHeight, fn.Some(int32(h.htlc.RefundTimeout)),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -69,7 +69,7 @@ func newHtlcResolverTestContext(t *testing.T,
|
||||||
IncubateOutputs: func(wire.OutPoint,
|
IncubateOutputs: func(wire.OutPoint,
|
||||||
fn.Option[lnwallet.OutgoingHtlcResolution],
|
fn.Option[lnwallet.OutgoingHtlcResolution],
|
||||||
fn.Option[lnwallet.IncomingHtlcResolution],
|
fn.Option[lnwallet.IncomingHtlcResolution],
|
||||||
uint32) error {
|
uint32, fn.Option[int32]) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
|
|
@ -547,7 +547,7 @@ func (h *htlcTimeoutResolver) sendSecondLevelTxLegacy() error {
|
||||||
err := h.IncubateOutputs(
|
err := h.IncubateOutputs(
|
||||||
h.ChanPoint, fn.Some(h.htlcResolution),
|
h.ChanPoint, fn.Some(h.htlcResolution),
|
||||||
fn.None[lnwallet.IncomingHtlcResolution](),
|
fn.None[lnwallet.IncomingHtlcResolution](),
|
||||||
h.broadcastHeight,
|
h.broadcastHeight, h.incomingHTLCExpiryHeight,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -288,7 +288,7 @@ func TestHtlcTimeoutResolver(t *testing.T) {
|
||||||
IncubateOutputs: func(wire.OutPoint,
|
IncubateOutputs: func(wire.OutPoint,
|
||||||
fn.Option[lnwallet.OutgoingHtlcResolution],
|
fn.Option[lnwallet.OutgoingHtlcResolution],
|
||||||
fn.Option[lnwallet.IncomingHtlcResolution],
|
fn.Option[lnwallet.IncomingHtlcResolution],
|
||||||
uint32) error {
|
uint32, fn.Option[int32]) error {
|
||||||
|
|
||||||
incubateChan <- struct{}{}
|
incubateChan <- struct{}{}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -205,6 +205,9 @@ type NurseryConfig struct {
|
||||||
|
|
||||||
// Sweep sweeps an input back to the wallet.
|
// Sweep sweeps an input back to the wallet.
|
||||||
SweepInput func(input.Input, sweep.Params) (chan sweep.Result, error)
|
SweepInput func(input.Input, sweep.Params) (chan sweep.Result, error)
|
||||||
|
|
||||||
|
// Budget is the configured budget for the nursery.
|
||||||
|
Budget *BudgetConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
// UtxoNursery is a system dedicated to incubating time-locked outputs created
|
// UtxoNursery is a system dedicated to incubating time-locked outputs created
|
||||||
|
@ -336,7 +339,7 @@ func (u *UtxoNursery) Stop() error {
|
||||||
func (u *UtxoNursery) IncubateOutputs(chanPoint wire.OutPoint,
|
func (u *UtxoNursery) IncubateOutputs(chanPoint wire.OutPoint,
|
||||||
outgoingHtlc fn.Option[lnwallet.OutgoingHtlcResolution],
|
outgoingHtlc fn.Option[lnwallet.OutgoingHtlcResolution],
|
||||||
incomingHtlc fn.Option[lnwallet.IncomingHtlcResolution],
|
incomingHtlc fn.Option[lnwallet.IncomingHtlcResolution],
|
||||||
broadcastHeight uint32) error {
|
broadcastHeight uint32, deadlineHeight fn.Option[int32]) error {
|
||||||
|
|
||||||
// Add to wait group because nursery might shut down during execution of
|
// Add to wait group because nursery might shut down during execution of
|
||||||
// this function. Otherwise it could happen that nursery thinks it is
|
// this function. Otherwise it could happen that nursery thinks it is
|
||||||
|
@ -386,7 +389,7 @@ func (u *UtxoNursery) IncubateOutputs(chanPoint wire.OutPoint,
|
||||||
|
|
||||||
htlcOutput := makeKidOutput(
|
htlcOutput := makeKidOutput(
|
||||||
&htlcRes.ClaimOutpoint, &chanPoint, htlcRes.CsvDelay,
|
&htlcRes.ClaimOutpoint, &chanPoint, htlcRes.CsvDelay,
|
||||||
witType, &htlcRes.SweepSignDesc, 0,
|
witType, &htlcRes.SweepSignDesc, 0, deadlineHeight,
|
||||||
)
|
)
|
||||||
|
|
||||||
if htlcOutput.Amount() > 0 {
|
if htlcOutput.Amount() > 0 {
|
||||||
|
@ -403,7 +406,9 @@ func (u *UtxoNursery) IncubateOutputs(chanPoint wire.OutPoint,
|
||||||
// a baby output as we need to go to the second level to sweep
|
// a baby output as we need to go to the second level to sweep
|
||||||
// it.
|
// it.
|
||||||
if htlcRes.SignedTimeoutTx != nil {
|
if htlcRes.SignedTimeoutTx != nil {
|
||||||
htlcOutput := makeBabyOutput(&chanPoint, &htlcRes)
|
htlcOutput := makeBabyOutput(
|
||||||
|
&chanPoint, &htlcRes, deadlineHeight,
|
||||||
|
)
|
||||||
|
|
||||||
if htlcOutput.Amount() > 0 {
|
if htlcOutput.Amount() > 0 {
|
||||||
babyOutputs = append(babyOutputs, htlcOutput)
|
babyOutputs = append(babyOutputs, htlcOutput)
|
||||||
|
@ -434,6 +439,7 @@ func (u *UtxoNursery) IncubateOutputs(chanPoint wire.OutPoint,
|
||||||
htlcOutput := makeKidOutput(
|
htlcOutput := makeKidOutput(
|
||||||
&htlcRes.ClaimOutpoint, &chanPoint, htlcRes.CsvDelay,
|
&htlcRes.ClaimOutpoint, &chanPoint, htlcRes.CsvDelay,
|
||||||
witType, &htlcRes.SweepSignDesc, htlcRes.Expiry,
|
witType, &htlcRes.SweepSignDesc, htlcRes.Expiry,
|
||||||
|
deadlineHeight,
|
||||||
)
|
)
|
||||||
kidOutputs = append(kidOutputs, htlcOutput)
|
kidOutputs = append(kidOutputs, htlcOutput)
|
||||||
})
|
})
|
||||||
|
@ -815,6 +821,32 @@ func (u *UtxoNursery) graduateClass(classHeight uint32) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// decideDeadlineAndBudget returns the deadline and budget for a given output.
|
||||||
|
func (u *UtxoNursery) decideDeadlineAndBudget(k kidOutput) (fn.Option[int32],
|
||||||
|
btcutil.Amount) {
|
||||||
|
|
||||||
|
// Assume this is a to_local output and use a None deadline.
|
||||||
|
deadline := fn.None[int32]()
|
||||||
|
|
||||||
|
// Exit early if this is not HTLC.
|
||||||
|
if !k.isHtlc {
|
||||||
|
budget := calculateBudget(
|
||||||
|
k.amt, u.cfg.Budget.ToLocalRatio, u.cfg.Budget.ToLocal,
|
||||||
|
)
|
||||||
|
|
||||||
|
return deadline, budget
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise it's the first-level HTLC output, we'll use the
|
||||||
|
// time-sensitive settings for it.
|
||||||
|
budget := calculateBudget(
|
||||||
|
k.amt, u.cfg.Budget.DeadlineHTLCRatio,
|
||||||
|
u.cfg.Budget.DeadlineHTLC,
|
||||||
|
)
|
||||||
|
|
||||||
|
return k.deadlineHeight, budget
|
||||||
|
}
|
||||||
|
|
||||||
// sweepMatureOutputs generates and broadcasts the transaction that transfers
|
// sweepMatureOutputs generates and broadcasts the transaction that transfers
|
||||||
// control of funds from a prior channel commitment transaction to the user's
|
// control of funds from a prior channel commitment transaction to the user's
|
||||||
// wallet. The outputs swept were previously time locked (either absolute or
|
// wallet. The outputs swept were previously time locked (either absolute or
|
||||||
|
@ -825,15 +857,17 @@ func (u *UtxoNursery) sweepMatureOutputs(classHeight uint32,
|
||||||
utxnLog.Infof("Sweeping %v CSV-delayed outputs with sweep tx for "+
|
utxnLog.Infof("Sweeping %v CSV-delayed outputs with sweep tx for "+
|
||||||
"height %v", len(kgtnOutputs), classHeight)
|
"height %v", len(kgtnOutputs), classHeight)
|
||||||
|
|
||||||
feePref := sweep.FeeEstimateInfo{ConfTarget: kgtnOutputConfTarget}
|
|
||||||
for _, output := range kgtnOutputs {
|
for _, output := range kgtnOutputs {
|
||||||
// Create local copy to prevent pointer to loop variable to be
|
// Create local copy to prevent pointer to loop variable to be
|
||||||
// passed in with disastrous consequences.
|
// passed in with disastrous consequences.
|
||||||
local := output
|
local := output
|
||||||
|
|
||||||
|
// Calculate the deadline height and budget for this output.
|
||||||
|
deadline, budget := u.decideDeadlineAndBudget(local)
|
||||||
|
|
||||||
resultChan, err := u.cfg.SweepInput(&local, sweep.Params{
|
resultChan, err := u.cfg.SweepInput(&local, sweep.Params{
|
||||||
Fee: feePref,
|
DeadlineHeight: deadline,
|
||||||
Force: true,
|
Budget: budget,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -1270,7 +1304,8 @@ type babyOutput struct {
|
||||||
// provided sign descriptors and witness types will be used once the output
|
// provided sign descriptors and witness types will be used once the output
|
||||||
// reaches the delay and claim stage.
|
// reaches the delay and claim stage.
|
||||||
func makeBabyOutput(chanPoint *wire.OutPoint,
|
func makeBabyOutput(chanPoint *wire.OutPoint,
|
||||||
htlcResolution *lnwallet.OutgoingHtlcResolution) babyOutput {
|
htlcResolution *lnwallet.OutgoingHtlcResolution,
|
||||||
|
deadlineHeight fn.Option[int32]) babyOutput {
|
||||||
|
|
||||||
htlcOutpoint := htlcResolution.ClaimOutpoint
|
htlcOutpoint := htlcResolution.ClaimOutpoint
|
||||||
blocksToMaturity := htlcResolution.CsvDelay
|
blocksToMaturity := htlcResolution.CsvDelay
|
||||||
|
@ -1288,7 +1323,7 @@ func makeBabyOutput(chanPoint *wire.OutPoint,
|
||||||
|
|
||||||
kid := makeKidOutput(
|
kid := makeKidOutput(
|
||||||
&htlcOutpoint, chanPoint, blocksToMaturity, witnessType,
|
&htlcOutpoint, chanPoint, blocksToMaturity, witnessType,
|
||||||
&htlcResolution.SweepSignDesc, 0,
|
&htlcResolution.SweepSignDesc, 0, deadlineHeight,
|
||||||
)
|
)
|
||||||
|
|
||||||
return babyOutput{
|
return babyOutput{
|
||||||
|
@ -1361,12 +1396,18 @@ type kidOutput struct {
|
||||||
// NOTE: This will only be set for: outgoing HTLC's on the commitment
|
// NOTE: This will only be set for: outgoing HTLC's on the commitment
|
||||||
// transaction of the remote party.
|
// transaction of the remote party.
|
||||||
absoluteMaturity uint32
|
absoluteMaturity uint32
|
||||||
|
|
||||||
|
// deadlineHeight is the absolute height that this output should be
|
||||||
|
// confirmed at. For an incoming HTLC, this is the CLTV expiry height.
|
||||||
|
// For outgoing HTLC, this is its corresponding incoming HTLC's CLTV
|
||||||
|
// expiry height.
|
||||||
|
deadlineHeight fn.Option[int32]
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeKidOutput(outpoint, originChanPoint *wire.OutPoint,
|
func makeKidOutput(outpoint, originChanPoint *wire.OutPoint,
|
||||||
blocksToMaturity uint32, witnessType input.StandardWitnessType,
|
blocksToMaturity uint32, witnessType input.StandardWitnessType,
|
||||||
signDescriptor *input.SignDescriptor,
|
signDescriptor *input.SignDescriptor, absoluteMaturity uint32,
|
||||||
absoluteMaturity uint32) kidOutput {
|
deadlineHeight fn.Option[int32]) kidOutput {
|
||||||
|
|
||||||
// This is an HTLC either if it's an incoming HTLC on our commitment
|
// This is an HTLC either if it's an incoming HTLC on our commitment
|
||||||
// transaction, or is an outgoing HTLC on the commitment transaction of
|
// transaction, or is an outgoing HTLC on the commitment transaction of
|
||||||
|
@ -1389,6 +1430,7 @@ func makeKidOutput(outpoint, originChanPoint *wire.OutPoint,
|
||||||
originChanPoint: *originChanPoint,
|
originChanPoint: *originChanPoint,
|
||||||
blocksToMaturity: blocksToMaturity,
|
blocksToMaturity: blocksToMaturity,
|
||||||
absoluteMaturity: absoluteMaturity,
|
absoluteMaturity: absoluteMaturity,
|
||||||
|
deadlineHeight: deadlineHeight,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -464,6 +464,7 @@ func createNurseryTestContext(t *testing.T,
|
||||||
PublishTransaction: func(tx *wire.MsgTx, _ string) error {
|
PublishTransaction: func(tx *wire.MsgTx, _ string) error {
|
||||||
return publishFunc(tx, "nursery")
|
return publishFunc(tx, "nursery")
|
||||||
},
|
},
|
||||||
|
Budget: DefaultBudgetConfig(),
|
||||||
}
|
}
|
||||||
|
|
||||||
nursery := NewUtxoNursery(&nurseryCfg)
|
nursery := NewUtxoNursery(&nurseryCfg)
|
||||||
|
@ -628,9 +629,8 @@ func incubateTestOutput(t *testing.T, nursery *UtxoNursery,
|
||||||
|
|
||||||
// Hand off to nursery.
|
// Hand off to nursery.
|
||||||
err := nursery.IncubateOutputs(
|
err := nursery.IncubateOutputs(
|
||||||
testChanPoint,
|
testChanPoint, fn.Some(*outgoingRes),
|
||||||
fn.Some(*outgoingRes),
|
fn.None[lnwallet.IncomingHtlcResolution](), 0, fn.None[int32](),
|
||||||
fn.None[lnwallet.IncomingHtlcResolution](), 0,
|
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
@ -710,9 +710,9 @@ func TestRejectedCribTransaction(t *testing.T) {
|
||||||
|
|
||||||
// Hand off to nursery.
|
// Hand off to nursery.
|
||||||
err := ctx.nursery.IncubateOutputs(
|
err := ctx.nursery.IncubateOutputs(
|
||||||
testChanPoint,
|
testChanPoint, fn.Some(*outgoingRes),
|
||||||
fn.Some(*outgoingRes),
|
|
||||||
fn.None[lnwallet.IncomingHtlcResolution](), 0,
|
fn.None[lnwallet.IncomingHtlcResolution](), 0,
|
||||||
|
fn.None[int32](),
|
||||||
)
|
)
|
||||||
if test.expectErr {
|
if test.expectErr {
|
||||||
require.ErrorIs(t, err, test.broadcastErr)
|
require.ErrorIs(t, err, test.broadcastErr)
|
||||||
|
|
|
@ -1099,6 +1099,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
|
||||||
PublishTransaction: cc.Wallet.PublishTransaction,
|
PublishTransaction: cc.Wallet.PublishTransaction,
|
||||||
Store: utxnStore,
|
Store: utxnStore,
|
||||||
SweepInput: s.sweeper.SweepInput,
|
SweepInput: s.sweeper.SweepInput,
|
||||||
|
Budget: s.cfg.Sweeper.Budget,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Construct a closure that wraps the htlcswitch's CloseLink method.
|
// Construct a closure that wraps the htlcswitch's CloseLink method.
|
||||||
|
@ -1151,11 +1152,12 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
|
||||||
IncubateOutputs: func(chanPoint wire.OutPoint,
|
IncubateOutputs: func(chanPoint wire.OutPoint,
|
||||||
outHtlcRes fn.Option[lnwallet.OutgoingHtlcResolution],
|
outHtlcRes fn.Option[lnwallet.OutgoingHtlcResolution],
|
||||||
inHtlcRes fn.Option[lnwallet.IncomingHtlcResolution],
|
inHtlcRes fn.Option[lnwallet.IncomingHtlcResolution],
|
||||||
broadcastHeight uint32) error {
|
broadcastHeight uint32,
|
||||||
|
deadlineHeight fn.Option[int32]) error {
|
||||||
|
|
||||||
return s.utxoNursery.IncubateOutputs(
|
return s.utxoNursery.IncubateOutputs(
|
||||||
chanPoint, outHtlcRes, inHtlcRes,
|
chanPoint, outHtlcRes, inHtlcRes,
|
||||||
broadcastHeight,
|
broadcastHeight, deadlineHeight,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
PreimageDB: s.witnessBeacon,
|
PreimageDB: s.witnessBeacon,
|
||||||
|
|
Loading…
Add table
Reference in a new issue