Skip to content

Commit 95b248a

Browse files
authored
Merge pull request #9194 from lightningnetwork/aux-channel-htlc
multi: generate and pass along HTLC resolution blobs for aux channels
2 parents e6efa2e + 9a1adbe commit 95b248a

27 files changed

+728
-141
lines changed

contractcourt/breach_arbitrator.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -752,7 +752,7 @@ justiceTxBroadcast:
752752
}
753753

754754
return aux.NotifyBroadcast(
755-
&bumpReq, finalTx.justiceTx, finalTx.fee,
755+
&bumpReq, finalTx.justiceTx, finalTx.fee, nil,
756756
)
757757
})
758758
if err != nil {
@@ -1160,6 +1160,11 @@ func (bo *breachedOutput) SignDesc() *input.SignDescriptor {
11601160
return &bo.signDesc
11611161
}
11621162

1163+
// Preimage returns the preimage that was used to create the breached output.
1164+
func (bo *breachedOutput) Preimage() fn.Option[lntypes.Preimage] {
1165+
return fn.None[lntypes.Preimage]()
1166+
}
1167+
11631168
// CraftInputScript computes a valid witness that allows us to spend from the
11641169
// breached output. It does so by first generating and memoizing the witness
11651170
// generation function, which parameterized primarily by the witness type and

contractcourt/briefcase.go

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1571,6 +1571,7 @@ func encodeTaprootAuxData(w io.Writer, c *ContractResolutions) error {
15711571
})
15721572
}
15731573

1574+
htlcBlobs := newAuxHtlcBlobs()
15741575
for _, htlc := range c.HtlcResolutions.IncomingHTLCs {
15751576
htlc := htlc
15761577

@@ -1581,8 +1582,9 @@ func encodeTaprootAuxData(w io.Writer, c *ContractResolutions) error {
15811582
continue
15821583
}
15831584

1585+
var resID resolverID
15841586
if htlc.SignedSuccessTx != nil {
1585-
resID := newResolverID(
1587+
resID = newResolverID(
15861588
htlc.SignedSuccessTx.TxIn[0].PreviousOutPoint,
15871589
)
15881590
//nolint:lll
@@ -1598,10 +1600,14 @@ func encodeTaprootAuxData(w io.Writer, c *ContractResolutions) error {
15981600
tapCase.CtrlBlocks.Val.IncomingHtlcCtrlBlocks[resID] = bridgeCtrlBlock
15991601
}
16001602
} else {
1601-
resID := newResolverID(htlc.ClaimOutpoint)
1603+
resID = newResolverID(htlc.ClaimOutpoint)
16021604
//nolint:lll
16031605
tapCase.CtrlBlocks.Val.IncomingHtlcCtrlBlocks[resID] = ctrlBlock
16041606
}
1607+
1608+
htlc.ResolutionBlob.WhenSome(func(b []byte) {
1609+
htlcBlobs[resID] = b
1610+
})
16051611
}
16061612
for _, htlc := range c.HtlcResolutions.OutgoingHTLCs {
16071613
htlc := htlc
@@ -1613,8 +1619,9 @@ func encodeTaprootAuxData(w io.Writer, c *ContractResolutions) error {
16131619
continue
16141620
}
16151621

1622+
var resID resolverID
16161623
if htlc.SignedTimeoutTx != nil {
1617-
resID := newResolverID(
1624+
resID = newResolverID(
16181625
htlc.SignedTimeoutTx.TxIn[0].PreviousOutPoint,
16191626
)
16201627
//nolint:lll
@@ -1632,17 +1639,27 @@ func encodeTaprootAuxData(w io.Writer, c *ContractResolutions) error {
16321639
tapCase.CtrlBlocks.Val.OutgoingHtlcCtrlBlocks[resID] = bridgeCtrlBlock
16331640
}
16341641
} else {
1635-
resID := newResolverID(htlc.ClaimOutpoint)
1642+
resID = newResolverID(htlc.ClaimOutpoint)
16361643
//nolint:lll
16371644
tapCase.CtrlBlocks.Val.OutgoingHtlcCtrlBlocks[resID] = ctrlBlock
16381645
}
1646+
1647+
htlc.ResolutionBlob.WhenSome(func(b []byte) {
1648+
htlcBlobs[resID] = b
1649+
})
16391650
}
16401651

16411652
if c.AnchorResolution != nil {
16421653
anchorSignDesc := c.AnchorResolution.AnchorSignDescriptor
16431654
tapCase.TapTweaks.Val.AnchorTweak = anchorSignDesc.TapTweak
16441655
}
16451656

1657+
if len(htlcBlobs) != 0 {
1658+
tapCase.HtlcBlobs = tlv.SomeRecordT(
1659+
tlv.NewRecordT[tlv.TlvType4](htlcBlobs),
1660+
)
1661+
}
1662+
16461663
return tapCase.Encode(w)
16471664
}
16481665

@@ -1661,6 +1678,8 @@ func decodeTapRootAuxData(r io.Reader, c *ContractResolutions) error {
16611678
})
16621679
}
16631680

1681+
htlcBlobs := tapCase.HtlcBlobs.ValOpt().UnwrapOr(newAuxHtlcBlobs())
1682+
16641683
for i := range c.HtlcResolutions.IncomingHTLCs {
16651684
htlc := c.HtlcResolutions.IncomingHTLCs[i]
16661685

@@ -1687,7 +1706,12 @@ func decodeTapRootAuxData(r io.Reader, c *ContractResolutions) error {
16871706
htlc.SweepSignDesc.ControlBlock = ctrlBlock
16881707
}
16891708

1709+
if htlcBlob, ok := htlcBlobs[resID]; ok {
1710+
htlc.ResolutionBlob = fn.Some(htlcBlob)
1711+
}
1712+
16901713
c.HtlcResolutions.IncomingHTLCs[i] = htlc
1714+
16911715
}
16921716
for i := range c.HtlcResolutions.OutgoingHTLCs {
16931717
htlc := c.HtlcResolutions.OutgoingHTLCs[i]
@@ -1715,6 +1739,10 @@ func decodeTapRootAuxData(r io.Reader, c *ContractResolutions) error {
17151739
htlc.SweepSignDesc.ControlBlock = ctrlBlock
17161740
}
17171741

1742+
if htlcBlob, ok := htlcBlobs[resID]; ok {
1743+
htlc.ResolutionBlob = fn.Some(htlcBlob)
1744+
}
1745+
17181746
c.HtlcResolutions.OutgoingHTLCs[i] = htlc
17191747
}
17201748

contractcourt/chain_watcher.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,7 @@ func (c *chainWatcher) handleUnknownLocalState(
436436
return s.FetchLeavesFromCommit(
437437
lnwallet.NewAuxChanState(c.cfg.chanState),
438438
c.cfg.chanState.LocalCommitment, *commitKeyRing,
439+
lntypes.Local,
439440
)
440441
},
441442
).Unpack()

contractcourt/htlc_incoming_contest_resolver.go

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -99,17 +99,6 @@ func (h *htlcIncomingContestResolver) Resolve(
9999
return nil, nil
100100
}
101101

102-
// If the HTLC has custom records, then for now we'll pause resolution.
103-
//
104-
// TODO(roasbeef): Implement resolving HTLCs with custom records
105-
// (follow-up PR).
106-
if len(h.htlc.CustomRecords) != 0 {
107-
select { //nolint:gosimple
108-
case <-h.quit:
109-
return nil, errResolverShuttingDown
110-
}
111-
}
112-
113102
// First try to parse the payload. If that fails, we can stop resolution
114103
// now.
115104
payload, nextHopOnionBlob, err := h.decodePayload()

contractcourt/htlc_lease_resolver.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ import (
66
"github.com/btcsuite/btcd/wire"
77
"github.com/lightningnetwork/lnd/chainntnfs"
88
"github.com/lightningnetwork/lnd/channeldb"
9+
"github.com/lightningnetwork/lnd/fn"
910
"github.com/lightningnetwork/lnd/input"
11+
"github.com/lightningnetwork/lnd/tlv"
1012
)
1113

1214
// htlcLeaseResolver is a struct that houses the lease specific HTLC resolution
@@ -52,8 +54,8 @@ func (h *htlcLeaseResolver) deriveWaitHeight(csvDelay uint32,
5254
// send to the sweeper so the output can ultimately be swept.
5355
func (h *htlcLeaseResolver) makeSweepInput(op *wire.OutPoint,
5456
wType, cltvWtype input.StandardWitnessType,
55-
signDesc *input.SignDescriptor,
56-
csvDelay, broadcastHeight uint32, payHash [32]byte) *input.BaseInput {
57+
signDesc *input.SignDescriptor, csvDelay, broadcastHeight uint32,
58+
payHash [32]byte, resBlob fn.Option[tlv.Blob]) *input.BaseInput {
5759

5860
if h.hasCLTV() {
5961
log.Infof("%T(%x): CSV and CLTV locks expired, offering "+
@@ -63,13 +65,17 @@ func (h *htlcLeaseResolver) makeSweepInput(op *wire.OutPoint,
6365
op, cltvWtype, signDesc,
6466
broadcastHeight, csvDelay,
6567
h.leaseExpiry,
68+
input.WithResolutionBlob(resBlob),
6669
)
6770
}
6871

6972
log.Infof("%T(%x): CSV lock expired, offering second-layer output to "+
7073
"sweeper: %v", h, payHash, op)
7174

72-
return input.NewCsvInput(op, wType, signDesc, broadcastHeight, csvDelay)
75+
return input.NewCsvInput(
76+
op, wType, signDesc, broadcastHeight, csvDelay,
77+
input.WithResolutionBlob(resBlob),
78+
)
7379
}
7480

7581
// SupplementState allows the user of a ContractResolver to supplement it with

contractcourt/htlc_outgoing_contest_resolver.go

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -58,17 +58,6 @@ func (h *htlcOutgoingContestResolver) Resolve(
5858
return nil, nil
5959
}
6060

61-
// If the HTLC has custom records, then for now we'll pause resolution.
62-
//
63-
// TODO(roasbeef): Implement resolving HTLCs with custom records
64-
// (follow-up PR).
65-
if len(h.htlc.CustomRecords) != 0 {
66-
select { //nolint:gosimple
67-
case <-h.quit:
68-
return nil, errResolverShuttingDown
69-
}
70-
}
71-
7261
// Otherwise, we'll watch for two external signals to decide if we'll
7362
// morph into another resolver, or fully resolve the contract.
7463
//

contractcourt/htlc_success_resolver.go

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -123,17 +123,6 @@ func (h *htlcSuccessResolver) Resolve(
123123
return nil, nil
124124
}
125125

126-
// If the HTLC has custom records, then for now we'll pause resolution.
127-
//
128-
// TODO(roasbeef): Implement resolving HTLCs with custom records
129-
// (follow-up PR).
130-
if len(h.htlc.CustomRecords) != 0 {
131-
select { //nolint:gosimple
132-
case <-h.quit:
133-
return nil, errResolverShuttingDown
134-
}
135-
}
136-
137126
// If we don't have a success transaction, then this means that this is
138127
// an output on the remote party's commitment transaction.
139128
if h.htlcResolution.SignedSuccessTx == nil {
@@ -258,6 +247,9 @@ func (h *htlcSuccessResolver) broadcastReSignedSuccessTx(immediate bool) (
258247
h.htlcResolution.SignedSuccessTx,
259248
h.htlcResolution.SignDetails, h.htlcResolution.Preimage,
260249
h.broadcastHeight,
250+
input.WithResolutionBlob(
251+
h.htlcResolution.ResolutionBlob,
252+
),
261253
)
262254
} else {
263255
//nolint:lll
@@ -414,7 +406,7 @@ func (h *htlcSuccessResolver) broadcastReSignedSuccessTx(immediate bool) (
414406
input.LeaseHtlcAcceptedSuccessSecondLevel,
415407
&h.htlcResolution.SweepSignDesc,
416408
h.htlcResolution.CsvDelay, uint32(commitSpend.SpendingHeight),
417-
h.htlc.RHash,
409+
h.htlc.RHash, h.htlcResolution.ResolutionBlob,
418410
)
419411

420412
// Calculate the budget for this sweep.
@@ -470,6 +462,9 @@ func (h *htlcSuccessResolver) resolveRemoteCommitOutput(immediate bool) (
470462
h.htlcResolution.Preimage[:],
471463
h.broadcastHeight,
472464
h.htlcResolution.CsvDelay,
465+
input.WithResolutionBlob(
466+
h.htlcResolution.ResolutionBlob,
467+
),
473468
))
474469
} else {
475470
inp = lnutils.Ptr(input.MakeHtlcSucceedInput(

contractcourt/htlc_timeout_resolver.go

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -426,17 +426,6 @@ func (h *htlcTimeoutResolver) Resolve(
426426
return nil, nil
427427
}
428428

429-
// If the HTLC has custom records, then for now we'll pause resolution.
430-
//
431-
// TODO(roasbeef): Implement resolving HTLCs with custom records
432-
// (follow-up PR).
433-
if len(h.htlc.CustomRecords) != 0 {
434-
select { //nolint:gosimple
435-
case <-h.quit:
436-
return nil, errResolverShuttingDown
437-
}
438-
}
439-
440429
// Start by spending the HTLC output, either by broadcasting the
441430
// second-level timeout transaction, or directly if this is the remote
442431
// commitment.
@@ -499,6 +488,9 @@ func (h *htlcTimeoutResolver) sweepSecondLevelTx(immediate bool) error {
499488
h.htlcResolution.SignedTimeoutTx,
500489
h.htlcResolution.SignDetails,
501490
h.broadcastHeight,
491+
input.WithResolutionBlob(
492+
h.htlcResolution.ResolutionBlob,
493+
),
502494
))
503495
} else {
504496
inp = lnutils.Ptr(input.MakeHtlcSecondLevelTimeoutAnchorInput(
@@ -592,6 +584,7 @@ func (h *htlcTimeoutResolver) sweepDirectHtlcOutput(immediate bool) error {
592584
&h.htlcResolution.ClaimOutpoint, htlcWitnessType,
593585
&h.htlcResolution.SweepSignDesc, h.broadcastHeight,
594586
h.htlcResolution.CsvDelay, h.htlcResolution.Expiry,
587+
input.WithResolutionBlob(h.htlcResolution.ResolutionBlob),
595588
)
596589

597590
// Calculate the budget.
@@ -846,6 +839,7 @@ func (h *htlcTimeoutResolver) handleCommitSpend(
846839
&h.htlcResolution.SweepSignDesc,
847840
h.htlcResolution.CsvDelay,
848841
uint32(commitSpend.SpendingHeight), h.htlc.RHash,
842+
h.htlcResolution.ResolutionBlob,
849843
)
850844

851845
// Calculate the budget for this sweep.

0 commit comments

Comments
 (0)