diff --git a/htlcswitch/iterator.go b/htlcswitch/iterator.go index 6e3ae07d..f201129e 100644 --- a/htlcswitch/iterator.go +++ b/htlcswitch/iterator.go @@ -9,6 +9,7 @@ import ( "github.com/btcsuite/btcd/btcec" "github.com/lightningnetwork/lightning-onion" "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightningnetwork/lnd/record" "github.com/lightningnetwork/lnd/tlv" ) @@ -175,15 +176,9 @@ func (r *sphinxHopIterator) ForwardingInstructions() (ForwardingInfo, error) { var cid uint64 tlvStream, err := tlv.NewStream( - tlv.MakeDynamicRecord( - tlv.AmtOnionType, &amt, nil, - tlv.ETUint64, tlv.DTUint64, - ), - tlv.MakeDynamicRecord( - tlv.LockTimeOnionType, &cltv, nil, - tlv.ETUint32, tlv.DTUint32, - ), - tlv.MakePrimitiveRecord(tlv.NextHopOnionType, &cid), + record.NewAmtToFwdRecord(&amt), + record.NewLockTimeRecord(&cltv), + record.NewNextHopIDRecord(&cid), ) if err != nil { return ForwardingInfo{}, err diff --git a/htlcswitch/iterator_test.go b/htlcswitch/iterator_test.go index 01c28ed9..ae6940e5 100644 --- a/htlcswitch/iterator_test.go +++ b/htlcswitch/iterator_test.go @@ -8,6 +8,7 @@ import ( "github.com/davecgh/go-spew/spew" sphinx "github.com/lightningnetwork/lightning-onion" "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightningnetwork/lnd/record" "github.com/lightningnetwork/lnd/tlv" ) @@ -38,19 +39,9 @@ func TestSphinxHopIteratorForwardingInstructions(t *testing.T) { // as we would normally in the routing network. var b bytes.Buffer tlvRecords := []tlv.Record{ - tlv.MakeDynamicRecord( - tlv.AmtOnionType, &hopData.ForwardAmount, func() uint64 { - return tlv.SizeTUint64(hopData.ForwardAmount) - }, - tlv.ETUint64, tlv.DTUint64, - ), - tlv.MakeDynamicRecord( - tlv.LockTimeOnionType, &hopData.OutgoingCltv, func() uint64 { - return tlv.SizeTUint32(hopData.OutgoingCltv) - }, - tlv.ETUint32, tlv.DTUint32, - ), - tlv.MakePrimitiveRecord(tlv.NextHopOnionType, &nextAddrInt), + record.NewAmtToFwdRecord(&hopData.ForwardAmount), + record.NewLockTimeRecord(&hopData.OutgoingCltv), + record.NewNextHopIDRecord(&nextAddrInt), } tlvStream, err := tlv.NewStream(tlvRecords...) if err != nil { diff --git a/record/hop.go b/record/hop.go new file mode 100644 index 00000000..3f515e6b --- /dev/null +++ b/record/hop.go @@ -0,0 +1,47 @@ +package record + +import ( + "github.com/lightningnetwork/lnd/tlv" +) + +const ( + // AmtOnionType is the type used in the onion to refrence the amount to + // send to the next hop. + AmtOnionType tlv.Type = 2 + + // LockTimeTLV is the type used in the onion to refenernce the CLTV + // value that should be used for the next hop's HTLC. + LockTimeOnionType tlv.Type = 4 + + // NextHopOnionType is the type used in the onion to reference the ID + // of the next hop. + NextHopOnionType tlv.Type = 6 +) + +// NewAmtToFwdRecord creates a tlv.Record that encodes the amount_to_forward +// (type 2) for an onion payload. +func NewAmtToFwdRecord(amt *uint64) tlv.Record { + return tlv.MakeDynamicRecord( + AmtOnionType, amt, func() uint64 { + return tlv.SizeTUint64(*amt) + }, + tlv.ETUint64, tlv.DTUint64, + ) +} + +// NewLockTimeRecord creates a tlv.Record that encodes the outgoing_cltv_value +// (type 4) for an onion payload. +func NewLockTimeRecord(lockTime *uint32) tlv.Record { + return tlv.MakeDynamicRecord( + LockTimeOnionType, lockTime, func() uint64 { + return tlv.SizeTUint32(*lockTime) + }, + tlv.ETUint32, tlv.DTUint32, + ) +} + +// NewNextHopIDRecord creates a tlv.Record that encodes the short_channel_id +// (type 6) for an onion payload. +func NewNextHopIDRecord(cid *uint64) tlv.Record { + return tlv.MakePrimitiveRecord(NextHopOnionType, cid) +} diff --git a/routing/route/route.go b/routing/route/route.go index 70712d04..ef902468 100644 --- a/routing/route/route.go +++ b/routing/route/route.go @@ -11,6 +11,7 @@ import ( "github.com/btcsuite/btcd/btcec" sphinx "github.com/lightningnetwork/lightning-onion" "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightningnetwork/lnd/record" "github.com/lightningnetwork/lnd/tlv" ) @@ -103,28 +104,33 @@ func (h *Hop) PackHopPayload(w io.Writer, nextChanID uint64) error { // Otherwise, we'll need to make a new stream that includes our // required routing fields, as well as these optional values. + var records []tlv.Record + + // Every hop must have an amount to forward and CLTV expiry. amt := uint64(h.AmtToForward) - combinedRecords := append(h.TLVRecords, - tlv.MakeDynamicRecord( - tlv.AmtOnionType, &amt, func() uint64 { - return tlv.SizeTUint64(amt) - }, - tlv.ETUint64, tlv.DTUint64, - ), - tlv.MakeDynamicRecord( - tlv.LockTimeOnionType, &h.OutgoingTimeLock, func() uint64 { - return tlv.SizeTUint32(h.OutgoingTimeLock) - }, - tlv.ETUint32, tlv.DTUint32, - ), - tlv.MakePrimitiveRecord(tlv.NextHopOnionType, &nextChanID), + records = append(records, + record.NewAmtToFwdRecord(&amt), + record.NewLockTimeRecord(&h.OutgoingTimeLock), ) + // BOLT 04 says the next_hop_id should be omitted for the final hop, + // but present for all others. + // + // TODO(conner): test using hop.Exit once available + if nextChanID != 0 { + records = append(records, + record.NewNextHopIDRecord(&nextChanID), + ) + } + + // Append any custom types destined for this hop. + records = append(records, h.TLVRecords...) + // To ensure we produce a canonical stream, we'll sort the records // before encoding them as a stream in the hop payload. - tlv.SortRecords(combinedRecords) + tlv.SortRecords(records) - tlvStream, err := tlv.NewStream(combinedRecords...) + tlvStream, err := tlv.NewStream(records...) if err != nil { return err } diff --git a/tlv/onion_types.go b/tlv/onion_types.go deleted file mode 100644 index 65d5b42c..00000000 --- a/tlv/onion_types.go +++ /dev/null @@ -1,15 +0,0 @@ -package tlv - -const ( - // AmtOnionType is the type used in the onion to refrence the amount to - // send to the next hop. - AmtOnionType Type = 2 - - // LockTimeTLV is the type used in the onion to refenernce the CLTV - // value that should be used for the next hop's HTLC. - LockTimeOnionType Type = 4 - - // NextHopOnionType is the type used in the onion to reference the ID - // of the next hop. - NextHopOnionType Type = 6 -)