Skip to content

Commit af08c42

Browse files
committed
Merge branch '0-18-4-branch-rc1-9062' into 0-18-4-branch-rc1
2 parents 906fa0b + b2b5ec0 commit af08c42

File tree

2 files changed

+358
-244
lines changed

2 files changed

+358
-244
lines changed

contractcourt/htlc_timeout_resolver.go

Lines changed: 87 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -549,7 +549,6 @@ func (h *htlcTimeoutResolver) sweepSecondLevelTx(immediate bool) error {
549549
return err
550550
}
551551

552-
// TODO(yy): checkpoint here?
553552
return err
554553
}
555554

@@ -573,6 +572,59 @@ func (h *htlcTimeoutResolver) sendSecondLevelTxLegacy() error {
573572
return h.Checkpoint(h)
574573
}
575574

575+
// sweepDirectHtlcOutput sends the direct spend of the HTLC output to the
576+
// sweeper. This is used when the remote party goes on chain, and we're able to
577+
// sweep an HTLC we offered after a timeout. Only the CLTV encumbered outputs
578+
// are resolved via this path.
579+
func (h *htlcTimeoutResolver) sweepDirectHtlcOutput(immediate bool) error {
580+
var htlcWitnessType input.StandardWitnessType
581+
if h.isTaproot() {
582+
htlcWitnessType = input.TaprootHtlcOfferedRemoteTimeout
583+
} else {
584+
htlcWitnessType = input.HtlcOfferedRemoteTimeout
585+
}
586+
587+
sweepInput := input.NewCsvInputWithCltv(
588+
&h.htlcResolution.ClaimOutpoint, htlcWitnessType,
589+
&h.htlcResolution.SweepSignDesc, h.broadcastHeight,
590+
h.htlcResolution.CsvDelay, h.htlcResolution.Expiry,
591+
)
592+
593+
// Calculate the budget.
594+
//
595+
// TODO(yy): the budget is twice the output's value, which is needed as
596+
// we don't force sweep the output now. To prevent cascading force
597+
// closes, we use all its output value plus a wallet input as the
598+
// budget. This is a temporary solution until we can optionally cancel
599+
// the incoming HTLC, more details in,
600+
// - https://github.com/lightningnetwork/lnd/issues/7969
601+
budget := calculateBudget(
602+
btcutil.Amount(sweepInput.SignDesc().Output.Value), 2, 0,
603+
)
604+
605+
log.Infof("%T(%x): offering offered remote timeout HTLC output to "+
606+
"sweeper with deadline %v and budget=%v at height=%v",
607+
h, h.htlc.RHash[:], h.incomingHTLCExpiryHeight, budget,
608+
h.broadcastHeight)
609+
610+
_, err := h.Sweeper.SweepInput(
611+
sweepInput,
612+
sweep.Params{
613+
Budget: budget,
614+
615+
// This is an outgoing HTLC, so we want to make sure
616+
// that we sweep it before the incoming HTLC expires.
617+
DeadlineHeight: h.incomingHTLCExpiryHeight,
618+
Immediate: immediate,
619+
},
620+
)
621+
if err != nil {
622+
return err
623+
}
624+
625+
return nil
626+
}
627+
576628
// spendHtlcOutput handles the initial spend of an HTLC output via the timeout
577629
// clause. If this is our local commitment, the second-level timeout TX will be
578630
// used to spend the output into the next stage. If this is the remote
@@ -593,8 +645,18 @@ func (h *htlcTimeoutResolver) spendHtlcOutput(
593645
return nil, err
594646
}
595647

596-
// If we have no SignDetails, and we haven't already sent the output to
597-
// the utxo nursery, then we'll do so now.
648+
// If this is a remote commitment there's no second level timeout txn,
649+
// and we can just send this directly to the sweeper.
650+
case h.htlcResolution.SignedTimeoutTx == nil && !h.outputIncubating:
651+
if err := h.sweepDirectHtlcOutput(immediate); err != nil {
652+
log.Errorf("Sending direct spend to sweeper: %v", err)
653+
654+
return nil, err
655+
}
656+
657+
// If we have a SignedTimeoutTx but no SignDetails, this is a local
658+
// commitment for a non-anchor channel, so we'll send it to the utxo
659+
// nursery.
598660
case h.htlcResolution.SignDetails == nil && !h.outputIncubating:
599661
if err := h.sendSecondLevelTxLegacy(); err != nil {
600662
log.Errorf("Sending timeout tx to nursery: %v", err)
@@ -701,6 +763,13 @@ func (h *htlcTimeoutResolver) handleCommitSpend(
701763
)
702764

703765
switch {
766+
767+
// If we swept an HTLC directly off the remote party's commitment
768+
// transaction, then we can exit here as there's no second level sweep
769+
// to do.
770+
case h.htlcResolution.SignedTimeoutTx == nil:
771+
break
772+
704773
// If the sweeper is handling the second level transaction, wait for
705774
// the CSV and possible CLTV lock to expire, before sweeping the output
706775
// on the second-level.
@@ -774,6 +843,7 @@ func (h *htlcTimeoutResolver) handleCommitSpend(
774843
h.htlcResolution.CsvDelay,
775844
uint32(commitSpend.SpendingHeight), h.htlc.RHash,
776845
)
846+
777847
// Calculate the budget for this sweep.
778848
budget := calculateBudget(
779849
btcutil.Amount(inp.SignDesc().Output.Value),
@@ -811,6 +881,7 @@ func (h *htlcTimeoutResolver) handleCommitSpend(
811881
case h.htlcResolution.SignedTimeoutTx != nil:
812882
log.Infof("%T(%v): waiting for nursery/sweeper to spend CSV "+
813883
"delayed output", h, claimOutpoint)
884+
814885
sweepTx, err := waitForSpend(
815886
&claimOutpoint,
816887
h.htlcResolution.SweepSignDesc.Output.PkScript,
@@ -877,9 +948,11 @@ func (h *htlcTimeoutResolver) IsResolved() bool {
877948

878949
// report returns a report on the resolution state of the contract.
879950
func (h *htlcTimeoutResolver) report() *ContractReport {
880-
// If the sign details are nil, the report will be created by handled
881-
// by the nursery.
882-
if h.htlcResolution.SignDetails == nil {
951+
// If we have a SignedTimeoutTx but no SignDetails, this is a local
952+
// commitment for a non-anchor channel, which was handled by the utxo
953+
// nursery.
954+
if h.htlcResolution.SignDetails == nil && h.
955+
htlcResolution.SignedTimeoutTx != nil {
883956
return nil
884957
}
885958

@@ -899,13 +972,20 @@ func (h *htlcTimeoutResolver) initReport() {
899972
)
900973
}
901974

975+
// If there's no timeout transaction, then we're already effectively in
976+
// level two.
977+
stage := uint32(1)
978+
if h.htlcResolution.SignedTimeoutTx == nil {
979+
stage = 2
980+
}
981+
902982
h.currentReport = ContractReport{
903983
Outpoint: h.htlcResolution.ClaimOutpoint,
904984
Type: ReportOutputOutgoingHtlc,
905985
Amount: finalAmt,
906986
MaturityHeight: h.htlcResolution.Expiry,
907987
LimboBalance: finalAmt,
908-
Stage: 1,
988+
Stage: stage,
909989
}
910990
}
911991

0 commit comments

Comments
 (0)