@@ -2,7 +2,10 @@ package lnwire
22
33import (
44 "bytes"
5+ "fmt"
56 "io"
7+
8+ "github.com/lightningnetwork/lnd/tlv"
69)
710
811// UpdateFulfillHTLC is sent by Alice to Bob when she wishes to settle a
@@ -23,6 +26,10 @@ type UpdateFulfillHTLC struct {
2326 // HTLC.
2427 PaymentPreimage [32 ]byte
2528
29+ // CustomRecords maps TLV types to byte slices, storing arbitrary data
30+ // intended for inclusion in the ExtraData field.
31+ CustomRecords CustomRecords
32+
2633 // ExtraData is the set of data that was appended to this message to
2734 // fill out the full maximum transport message size. These fields can
2835 // be used to specify optional data such as custom TLV fields.
@@ -49,12 +56,75 @@ var _ Message = (*UpdateFulfillHTLC)(nil)
4956//
5057// This is part of the lnwire.Message interface.
5158func (c * UpdateFulfillHTLC ) Decode (r io.Reader , pver uint32 ) error {
52- return ReadElements (r ,
59+ // msgExtraData is a temporary variable used to read the message extra
60+ // data field from the reader.
61+ var msgExtraData ExtraOpaqueData
62+
63+ if err := ReadElements (r ,
5364 & c .ChanID ,
5465 & c .ID ,
5566 c .PaymentPreimage [:],
56- & c .ExtraData ,
67+ & msgExtraData ,
68+ ); err != nil {
69+ return err
70+ }
71+
72+ // Extract TLV records from the message extra data field.
73+ extraDataTlvMap , err := msgExtraData .ExtractRecords ()
74+ if err != nil {
75+ return err
76+ }
77+
78+ // Any records from the extra data TLV map which are in the custom
79+ // records TLV type range will be included in the custom records field
80+ // and removed from the extra data field.
81+ customRecordsTlvMap := make (tlv.TypeMap , len (extraDataTlvMap ))
82+ for k , v := range extraDataTlvMap {
83+ // Skip records that are not in the custom records TLV type
84+ // range.
85+ if k < MinCustomRecordsTlvType {
86+ continue
87+ }
88+
89+ // Include the record in the custom records map.
90+ customRecordsTlvMap [k ] = v
91+
92+ // Now that the record is included in the custom records map,
93+ // we can remove it from the extra data TLV map.
94+ delete (extraDataTlvMap , k )
95+ }
96+
97+ // Set the custom records field to the TLV record map.
98+ customRecords , err := NewCustomRecordsFromTlvTypeMap (
99+ customRecordsTlvMap ,
57100 )
101+ if err != nil {
102+ return err
103+ }
104+ c .CustomRecords = customRecords
105+
106+ // Set custom records to nil if we didn't parse anything out of it so
107+ // that we can use assert.Equal in tests.
108+ if len (customRecordsTlvMap ) == 0 {
109+ c .CustomRecords = nil
110+ }
111+
112+ // Set extra data to nil if we didn't parse anything out of it so that
113+ // we can use assert.Equal in tests.
114+ if len (extraDataTlvMap ) == 0 {
115+ c .ExtraData = nil
116+ return nil
117+ }
118+
119+ // Encode the remaining records back into the extra data field. These
120+ // records are not in the custom records TLV type range and do not
121+ // have associated fields in the UpdateFulfillHTLC struct.
122+ c .ExtraData , err = NewExtraOpaqueDataFromTlvTypeMap (extraDataTlvMap )
123+ if err != nil {
124+ return err
125+ }
126+
127+ return nil
58128}
59129
60130// Encode serializes the target UpdateFulfillHTLC into the passed io.Writer
@@ -74,7 +144,34 @@ func (c *UpdateFulfillHTLC) Encode(w *bytes.Buffer, pver uint32) error {
74144 return err
75145 }
76146
77- return WriteBytes (w , c .ExtraData )
147+ // Construct a slice of all the records that we should include in the
148+ // message extra data field. We will start by including any records from
149+ // the extra data field.
150+ msgExtraDataRecords , err := c .ExtraData .RecordProducers ()
151+ if err != nil {
152+ return err
153+ }
154+
155+ // Include custom records in the extra data wire field if they are
156+ // present. Ensure that the custom records are validated before encoding
157+ // them.
158+ if err := c .CustomRecords .Validate (); err != nil {
159+ return fmt .Errorf ("custom records validation error: %w" , err )
160+ }
161+
162+ // Extend the message extra data records slice with TLV records from the
163+ // custom records field.
164+ customTlvRecords := c .CustomRecords .RecordProducers ()
165+ msgExtraDataRecords = append (msgExtraDataRecords , customTlvRecords ... )
166+
167+ // We will now construct the message extra data field that will be
168+ // encoded into the byte writer.
169+ var msgExtraData ExtraOpaqueData
170+ if err := msgExtraData .PackRecords (msgExtraDataRecords ... ); err != nil {
171+ return err
172+ }
173+
174+ return WriteBytes (w , msgExtraData )
78175}
79176
80177// MsgType returns the integer uniquely identifying this message type on the
0 commit comments