From 940b491051d2f61225424551e52d8f2118e3d2cf Mon Sep 17 00:00:00 2001 From: Carla Kirk-Cohen Date: Tue, 20 Dec 2022 14:02:42 -0500 Subject: [PATCH] routing: only pack amount and cltv if populated With the addition of blinded routes, we now need to account for the possibility that intermediate nodes payloads will not have an amount and expiry set because that information is provided by the recipient encrypted data blob. This commit updates our payload packing to only optionally include those fields. --- routing/route/route.go | 36 +++++++++++++++++++++++++----------- routing/route/route_test.go | 15 +++++++++++++++ 2 files changed, 40 insertions(+), 11 deletions(-) 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) {