Skip to content

Commit 966f41f

Browse files
authored
Merge pull request #8660 from GeorgeTsagk/interceptor-wire-records
Enhance `update_add_htlc` with remote peer's custom records
2 parents b009db3 + 1b1969b commit 966f41f

18 files changed

+1228
-778
lines changed

channeldb/channel.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2550,6 +2550,12 @@ type HTLC struct {
25502550
// HTLC. It is stored in the ExtraData field, which is used to store
25512551
// a TLV stream of additional information associated with the HTLC.
25522552
BlindingPoint lnwire.BlindingPointRecord
2553+
2554+
// CustomRecords is a set of custom TLV records that are associated with
2555+
// this HTLC. These records are used to store additional information
2556+
// about the HTLC that is not part of the standard HTLC fields. This
2557+
// field is encoded within the ExtraData field.
2558+
CustomRecords lnwire.CustomRecords
25532559
}
25542560

25552561
// serializeExtraData encodes a TLV stream of extra data to be stored with a
@@ -2568,6 +2574,11 @@ func (h *HTLC) serializeExtraData() error {
25682574
records = append(records, &b)
25692575
})
25702576

2577+
records, err := h.CustomRecords.ExtendRecordProducers(records)
2578+
if err != nil {
2579+
return err
2580+
}
2581+
25712582
return h.ExtraData.PackRecords(records...)
25722583
}
25732584

@@ -2589,7 +2600,18 @@ func (h *HTLC) deserializeExtraData() error {
25892600

25902601
if val, ok := tlvMap[h.BlindingPoint.TlvType()]; ok && val == nil {
25912602
h.BlindingPoint = tlv.SomeRecordT(blindingPoint)
2603+
2604+
// Remove the entry from the TLV map. Anything left in the map
2605+
// will be included in the custom records field.
2606+
delete(tlvMap, h.BlindingPoint.TlvType())
2607+
}
2608+
2609+
// Set the custom records field to the remaining TLV records.
2610+
customRecords, err := lnwire.NewCustomRecordsFromTlvTypeMap(tlvMap)
2611+
if err != nil {
2612+
return err
25922613
}
2614+
h.CustomRecords = customRecords
25932615

25942616
return nil
25952617
}

htlcswitch/interceptable_switch.go

Lines changed: 47 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"sync"
77

8+
"github.com/davecgh/go-spew/spew"
89
"github.com/go-errors/errors"
910
"github.com/lightningnetwork/lnd/chainntnfs"
1011
"github.com/lightningnetwork/lnd/channeldb/models"
@@ -622,15 +623,16 @@ func (f *interceptedForward) Packet() InterceptedPacket {
622623
ChanID: f.packet.incomingChanID,
623624
HtlcID: f.packet.incomingHTLCID,
624625
},
625-
OutgoingChanID: f.packet.outgoingChanID,
626-
Hash: f.htlc.PaymentHash,
627-
OutgoingExpiry: f.htlc.Expiry,
628-
OutgoingAmount: f.htlc.Amount,
629-
IncomingAmount: f.packet.incomingAmount,
630-
IncomingExpiry: f.packet.incomingTimeout,
631-
CustomRecords: f.packet.customRecords,
632-
OnionBlob: f.htlc.OnionBlob,
633-
AutoFailHeight: f.autoFailHeight,
626+
OutgoingChanID: f.packet.outgoingChanID,
627+
Hash: f.htlc.PaymentHash,
628+
OutgoingExpiry: f.htlc.Expiry,
629+
OutgoingAmount: f.htlc.Amount,
630+
IncomingAmount: f.packet.incomingAmount,
631+
IncomingExpiry: f.packet.incomingTimeout,
632+
CustomRecords: f.packet.customRecords,
633+
OnionBlob: f.htlc.OnionBlob,
634+
AutoFailHeight: f.autoFailHeight,
635+
IncomingWireCustomRecords: f.packet.incomingCustomRecords,
634636
}
635637
}
636638

@@ -659,50 +661,58 @@ func (f *interceptedForward) ResumeModified(
659661
htlc.Amount = amount
660662
})
661663

662-
//nolint:lll
663-
err := fn.MapOptionZ(customRecords, func(records record.CustomSet) error {
664-
if len(records) == 0 {
665-
return nil
666-
}
664+
err := fn.MapOptionZ(
665+
customRecords, func(records record.CustomSet) error {
666+
if len(records) == 0 {
667+
return nil
668+
}
667669

668-
// Type cast and validate custom records.
669-
htlc.CustomRecords = lnwire.CustomRecords(records)
670-
err := htlc.CustomRecords.Validate()
671-
if err != nil {
672-
return fmt.Errorf("failed to validate custom "+
673-
"records: %w", err)
674-
}
670+
// Type cast and validate custom records.
671+
htlc.CustomRecords = lnwire.CustomRecords(
672+
records,
673+
)
674+
err := htlc.CustomRecords.Validate()
675+
if err != nil {
676+
return fmt.Errorf("failed to validate "+
677+
"custom records: %w", err)
678+
}
675679

676-
return nil
677-
})
680+
return nil
681+
},
682+
)
678683
if err != nil {
679684
return fmt.Errorf("failed to encode custom records: %w",
680685
err)
681686
}
682687

683688
case *lnwire.UpdateFulfillHTLC:
684-
//nolint:lll
685-
err := fn.MapOptionZ(customRecords, func(records record.CustomSet) error {
686-
if len(records) == 0 {
687-
return nil
688-
}
689+
err := fn.MapOptionZ(
690+
customRecords, func(records record.CustomSet) error {
691+
if len(records) == 0 {
692+
return nil
693+
}
689694

690-
// Type cast and validate custom records.
691-
htlc.CustomRecords = lnwire.CustomRecords(records)
692-
err := htlc.CustomRecords.Validate()
693-
if err != nil {
694-
return fmt.Errorf("failed to validate custom "+
695-
"records: %w", err)
696-
}
695+
// Type cast and validate custom records.
696+
htlc.CustomRecords = lnwire.CustomRecords(
697+
records,
698+
)
699+
err := htlc.CustomRecords.Validate()
700+
if err != nil {
701+
return fmt.Errorf("failed to validate "+
702+
"custom records: %w", err)
703+
}
697704

698-
return nil
699-
})
705+
return nil
706+
},
707+
)
700708
if err != nil {
701709
return fmt.Errorf("failed to encode custom records: %w",
702710
err)
703711
}
704712
}
705713

714+
log.Tracef("Forwarding packet %v", spew.Sdump(f.packet))
715+
706716
// Forward to the switch. A link quit channel isn't needed, because we
707717
// are on a different thread now.
708718
return f.htlcSwitch.ForwardPackets(nil, f.packet)

htlcswitch/interfaces.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,10 @@ type InterceptedPacket struct {
357357
// OnionBlob is the onion packet for the next hop
358358
OnionBlob [lnwire.OnionPacketSize]byte
359359

360+
// IncomingWireCustomRecords are user-defined records that were defined
361+
// by the peer that forwarded this htlc to us.
362+
IncomingWireCustomRecords record.CustomSet
363+
360364
// AutoFailHeight is the block height at which this intercept will be
361365
// failed back automatically.
362366
AutoFailHeight int32

htlcswitch/link.go

Lines changed: 52 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ import (
2929
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
3030
"github.com/lightningnetwork/lnd/lnwire"
3131
"github.com/lightningnetwork/lnd/queue"
32+
"github.com/lightningnetwork/lnd/record"
3233
"github.com/lightningnetwork/lnd/ticker"
34+
"github.com/lightningnetwork/lnd/tlv"
3335
)
3436

3537
func init() {
@@ -3354,6 +3356,27 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg,
33543356
continue
33553357
}
33563358

3359+
var customRecords record.CustomSet
3360+
err = fn.MapOptionZ(
3361+
pd.CustomRecords, func(b tlv.Blob) error {
3362+
r, err := lnwire.ParseCustomRecords(b)
3363+
if err != nil {
3364+
return err
3365+
}
3366+
3367+
customRecords = record.CustomSet(r)
3368+
3369+
return nil
3370+
},
3371+
)
3372+
if err != nil {
3373+
l.fail(LinkFailureError{
3374+
code: ErrInternalError,
3375+
}, err.Error())
3376+
3377+
return
3378+
}
3379+
33573380
switch fwdPkg.State {
33583381
case channeldb.FwdStateProcessed:
33593382
// This add was not forwarded on the previous
@@ -3367,7 +3390,7 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg,
33673390
}
33683391

33693392
// Otherwise, it was already processed, we can
3370-
// can collect it and continue.
3393+
// collect it and continue.
33713394
addMsg := &lnwire.UpdateAddHTLC{
33723395
Expiry: fwdInfo.OutgoingCTLV,
33733396
Amount: fwdInfo.AmountToForward,
@@ -3387,19 +3410,21 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg,
33873410

33883411
inboundFee := l.cfg.FwrdingPolicy.InboundFee
33893412

3413+
//nolint:lll
33903414
updatePacket := &htlcPacket{
3391-
incomingChanID: l.ShortChanID(),
3392-
incomingHTLCID: pd.HtlcIndex,
3393-
outgoingChanID: fwdInfo.NextHop,
3394-
sourceRef: pd.SourceRef,
3395-
incomingAmount: pd.Amount,
3396-
amount: addMsg.Amount,
3397-
htlc: addMsg,
3398-
obfuscator: obfuscator,
3399-
incomingTimeout: pd.Timeout,
3400-
outgoingTimeout: fwdInfo.OutgoingCTLV,
3401-
customRecords: pld.CustomRecords(),
3402-
inboundFee: inboundFee,
3415+
incomingChanID: l.ShortChanID(),
3416+
incomingHTLCID: pd.HtlcIndex,
3417+
outgoingChanID: fwdInfo.NextHop,
3418+
sourceRef: pd.SourceRef,
3419+
incomingAmount: pd.Amount,
3420+
amount: addMsg.Amount,
3421+
htlc: addMsg,
3422+
obfuscator: obfuscator,
3423+
incomingTimeout: pd.Timeout,
3424+
outgoingTimeout: fwdInfo.OutgoingCTLV,
3425+
customRecords: pld.CustomRecords(),
3426+
inboundFee: inboundFee,
3427+
incomingCustomRecords: customRecords,
34033428
}
34043429
switchPackets = append(
34053430
switchPackets, updatePacket,
@@ -3455,19 +3480,21 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg,
34553480
if fwdPkg.State == channeldb.FwdStateLockedIn {
34563481
inboundFee := l.cfg.FwrdingPolicy.InboundFee
34573482

3483+
//nolint:lll
34583484
updatePacket := &htlcPacket{
3459-
incomingChanID: l.ShortChanID(),
3460-
incomingHTLCID: pd.HtlcIndex,
3461-
outgoingChanID: fwdInfo.NextHop,
3462-
sourceRef: pd.SourceRef,
3463-
incomingAmount: pd.Amount,
3464-
amount: addMsg.Amount,
3465-
htlc: addMsg,
3466-
obfuscator: obfuscator,
3467-
incomingTimeout: pd.Timeout,
3468-
outgoingTimeout: fwdInfo.OutgoingCTLV,
3469-
customRecords: pld.CustomRecords(),
3470-
inboundFee: inboundFee,
3485+
incomingChanID: l.ShortChanID(),
3486+
incomingHTLCID: pd.HtlcIndex,
3487+
outgoingChanID: fwdInfo.NextHop,
3488+
sourceRef: pd.SourceRef,
3489+
incomingAmount: pd.Amount,
3490+
amount: addMsg.Amount,
3491+
htlc: addMsg,
3492+
obfuscator: obfuscator,
3493+
incomingTimeout: pd.Timeout,
3494+
outgoingTimeout: fwdInfo.OutgoingCTLV,
3495+
customRecords: pld.CustomRecords(),
3496+
inboundFee: inboundFee,
3497+
incomingCustomRecords: customRecords,
34713498
}
34723499

34733500
fwdPkg.FwdFilter.Set(idx)

htlcswitch/packet.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,10 @@ type htlcPacket struct {
9898
// were included in the payload.
9999
customRecords record.CustomSet
100100

101+
// incomingCustomRecords are custom type range TLVs that are included
102+
// in the incoming update_add_htlc.
103+
incomingCustomRecords record.CustomSet
104+
101105
// originalOutgoingChanID is used when sending back failure messages.
102106
// It is only used for forwarded Adds on option_scid_alias channels.
103107
// This is to avoid possible confusion if a payer uses the public SCID

itest/list_on_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,10 @@ var allTestCases = []*lntest.TestCase{
430430
Name: "forward interceptor modified htlc",
431431
TestFunc: testForwardInterceptorModifiedHtlc,
432432
},
433+
{
434+
Name: "forward interceptor wire records",
435+
TestFunc: testForwardInterceptorWireRecords,
436+
},
433437
{
434438
Name: "zero conf channel open",
435439
TestFunc: testZeroConfChannelOpen,

0 commit comments

Comments
 (0)