diff --git a/routing/route/route.go b/routing/route/route.go index 48217fc81..bb0208481 100644 --- a/routing/route/route.go +++ b/routing/route/route.go @@ -188,12 +188,21 @@ func (h *Hop) PackHopPayload(w io.Writer, nextChanID uint64) error { // required routing fields, as well as these optional values. var records []tlv.Record - // Every hop must have an amount to forward and CLTV expiry. + // Hops that are not part of a blinded path will have an amount and + // a CLTV expiry field. Zero values indicate that the hop is inside of + // a blinded route, so the TLV should not be included. amt := uint64(h.AmtToForward) - records = append(records, - record.NewAmtToFwdRecord(&amt), - record.NewLockTimeRecord(&h.OutgoingTimeLock), - ) + if amt != 0 { + records = append( + records, record.NewAmtToFwdRecord(&amt), + ) + } + + if h.OutgoingTimeLock != 0 { + records = append( + records, record.NewLockTimeRecord(&h.OutgoingTimeLock), + ) + } // BOLT 04 says the next_hop_id should be omitted for the final hop, // but present for all others. @@ -286,13 +295,18 @@ func (h *Hop) PayloadSize(nextChanID uint64) uint64 { } // Add amount size. - addRecord(record.AmtOnionType, tlv.SizeTUint64(uint64(h.AmtToForward))) - + if h.AmtToForward != 0 { + addRecord(record.AmtOnionType, tlv.SizeTUint64( + uint64(h.AmtToForward), + )) + } // Add lock time size. - addRecord( - record.LockTimeOnionType, - tlv.SizeTUint64(uint64(h.OutgoingTimeLock)), - ) + if h.OutgoingTimeLock != 0 { + addRecord( + record.LockTimeOnionType, + tlv.SizeTUint64(uint64(h.OutgoingTimeLock)), + ) + } // Add next hop if present. if nextChanID != 0 { diff --git a/routing/route/route_test.go b/routing/route/route_test.go index a8d33d941..ac79f1c66 100644 --- a/routing/route/route_test.go +++ b/routing/route/route_test.go @@ -8,6 +8,7 @@ import ( "github.com/btcsuite/btcd/btcec/v2" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/record" + "github.com/stretchr/testify/require" ) var ( @@ -159,6 +160,20 @@ func TestAMPHop(t *testing.T) { } } +// TestNoForwardingParams tests packing of a hop payload without an amount or +// expiry height. +func TestNoForwardingParams(t *testing.T) { + t.Parallel() + + hop := Hop{ + EncryptedData: []byte{1, 2, 3}, + } + + var b bytes.Buffer + err := hop.PackHopPayload(&b, 2) + require.NoError(t, err) +} + // TestPayloadSize tests the payload size calculation that is provided by Hop // structs. func TestPayloadSize(t *testing.T) {