Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[bug]: contractcourt: max budget used immediately for anchor sweeps #8738

Closed
morehouse opened this issue May 7, 2024 · 3 comments · Fixed by #8751
Closed

[bug]: contractcourt: max budget used immediately for anchor sweeps #8738

morehouse opened this issue May 7, 2024 · 3 comments · Fixed by #8751
Assignees
Labels
bug Unintended code behaviour contracts fees Related to the fees paid for transactions (both LN and funding/commitment transactions) utxo sweeping
Milestone

Comments

@morehouse
Copy link
Collaborator

For outgoing HTLCs the commitment deadline is calculated incorrectly, causing the entire anchor budget to be spent immediately.

Problem

The commitment deadline is derived from the timelocks of the outgoing HTLCs, instead of the timelocks for the matching upstream (incoming) HTLCs.

func (c *ChannelArbitrator) findCommitmentDeadlineAndValue(heightHint uint32,
htlcs htlcSet) (fn.Option[int32], btcutil.Amount, error) {
deadlineMinHeight := uint32(math.MaxUint32)
totalValue := btcutil.Amount(0)
// First, iterate through the outgoingHTLCs to find the lowest CLTV
// value.
for _, htlc := range htlcs.outgoingHTLCs {
// Skip if the HTLC is dust.
if htlc.OutputIndex < 0 {
log.Debugf("ChannelArbitrator(%v): skipped deadline "+
"for dust htlc=%x",
c.cfg.ChanPoint, htlc.RHash[:])
continue
}
value := htlc.Amt.ToSatoshis()
totalValue += value
if htlc.RefundTimeout < deadlineMinHeight {
deadlineMinHeight = htlc.RefundTimeout
log.Tracef("ChannelArbitrator(%v): outgoing HTLC has "+
"deadline=%v, value=%v", c.cfg.ChanPoint,
deadlineMinHeight, value)
}
}

Since ChannelArbitrator only broadcast commitments for outgoing HTLCs once the timelock has already expired, the resulting deadline for anchor sweeping is always 0 (which is bumped to 1). This causes the sweeper to spend the entire budget immediately.

Solution

The upstream HTLC timelocks need to be used for the deadline instead.

@morehouse morehouse added bug Unintended code behaviour fees Related to the fees paid for transactions (both LN and funding/commitment transactions) contracts utxo sweeping labels May 7, 2024
@morehouse morehouse added this to the v0.18.0 milestone May 7, 2024
@Roasbeef
Copy link
Member

Roasbeef commented May 7, 2024

Nice catch! We added FindOutgoingHTLCDeadline to pass into the HTLC timeout resolver so it could use compute the CLTV delta. We can use the same routine here to compute the deltas to determine what the overall commitment deadline should be.

@yyforyongyu
Copy link
Collaborator

Thank you for catching this! I forgot to mention I wanna more opinions here re how we decide the deadline in this case. I don't think we can use the CLTV delta directly, as it may cause no blocks left when sweeping the outgoing HTLCs. Essentially, when sweeping the CPFP anchor and outgoing HTLC, the CLTV is the shared deadline. The expected result is, the HTLC is swept within CLTV delta blocks, which means the anchor CPFP must be confirmed at some block within the CLTV delta too.

More aggressive on the CPFP part.
|-CPFP-|-----HTLC-----|

Share the deadlines evenly.
|---CPFP---|---HTLC---|

More aggressive on the HTLC part.
|-----CPFP-----|-HTLC-|

I think as a starting point, we can ask the CPFP anchor and the HTLC to share the deadline evenly, wdyt?

In the long run, I think the deadline used for CPFP anchor sweeping is a function over all the HTLCs' deadlines and values, future stuff tho.

@morehouse
Copy link
Collaborator Author

Thank you for catching this! I forgot to mention I wanna more opinions here re how we decide the deadline in this case. I don't think we can use the CLTV delta directly, as it may cause no blocks left when sweeping the outgoing HTLCs.

This is also something we need to consider for incoming HTLCs, which have a much shorter default window (10 blocks) to confirm the commitment and HTLC-preimage transactions.

Splitting the window in half seems best to me, especially for this shorter 10 block window. Splitting unevenly (e.g., 80-20) would result in too short of deadlines for either the commitment or HTLC-preimage.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Unintended code behaviour contracts fees Related to the fees paid for transactions (both LN and funding/commitment transactions) utxo sweeping
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants