• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lightningnetwork / lnd / 21485572389

29 Jan 2026 04:09PM UTC coverage: 65.247% (+0.2%) from 65.074%
21485572389

Pull #10089

github

web-flow
Merge 22d34d15e into 19b2ad797
Pull Request #10089: Onion message forwarding

1152 of 1448 new or added lines in 23 files covered. (79.56%)

4109 existing lines in 29 files now uncovered.

139515 of 213825 relevant lines covered (65.25%)

20529.09 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.0
/lnwire/update_add_htlc.go
1
package lnwire
2

3
import (
4
        "bytes"
5
        "io"
6

7
        "github.com/btcsuite/btcd/btcec/v2"
8
        "github.com/lightningnetwork/lnd/tlv"
9
)
10

11
const (
12
        // OnionPacketSize is the size of the serialized Sphinx onion packet
13
        // included in each UpdateAddHTLC message. The breakdown of the onion
14
        // packet is as follows: 1-byte version, 33-byte ephemeral public key
15
        // (for ECDH), 1300-bytes of per-hop data, and a 32-byte HMAC over the
16
        // entire packet.
17
        OnionPacketSize = 1366
18

19
        // ExperimentalAccountableType is the TLV type used for a custom
20
        // record that sets an experimental accountable value.
21
        ExperimentalAccountableType tlv.Type = 106823
22

23
        // ExperimentalUnaccountable is the value that the experimental
24
        // accountable field contains when a htlc is not accountable.
25
        ExperimentalUnaccountable = 0
26

27
        // ExperimentalAccountable is the value that the experimental
28
        // accountable field contains when a htlc is accountable. We're using a
29
        // single byte to represent our accountable value, but limit the value
30
        // to using the first three bits (max value = 00000111). Interpreted as
31
        // a uint8 (an alias for byte in go), we can just define this constant
32
        // as 7.
33
        ExperimentalAccountable = 7
34
)
35

36
type (
37
        // BlindingPointTlvType is the type for ephemeral pubkeys used in
38
        // route blinding.
39
        BlindingPointTlvType = tlv.TlvType0
40

41
        // BlindingPointRecord holds an optional blinding point on update add
42
        // htlc.
43
        //nolint:ll
44
        BlindingPointRecord = tlv.OptionalRecordT[BlindingPointTlvType, *btcec.PublicKey]
45
)
46

47
// UpdateAddHTLC is the message sent by Alice to Bob when she wishes to add an
48
// HTLC to his remote commitment transaction. In addition to information
49
// detailing the value, the ID, expiry, and the onion blob is also included
50
// which allows Bob to derive the next hop in the route. The HTLC added by this
51
// message is to be added to the remote node's "pending" HTLCs.  A subsequent
52
// CommitSig message will move the pending HTLC to the newly created commitment
53
// transaction, marking them as "staged".
54
type UpdateAddHTLC struct {
55
        // ChanID is the particular active channel that this UpdateAddHTLC is
56
        // bound to.
57
        ChanID ChannelID
58

59
        // ID is the identification server for this HTLC. This value is
60
        // explicitly included as it allows nodes to survive single-sided
61
        // restarts. The ID value for this sides starts at zero, and increases
62
        // with each offered HTLC.
63
        ID uint64
64

65
        // Amount is the amount of millisatoshis this HTLC is worth.
66
        Amount MilliSatoshi
67

68
        // PaymentHash is the payment hash to be included in the HTLC this
69
        // request creates. The pre-image to this HTLC must be revealed by the
70
        // upstream peer in order to fully settle the HTLC.
71
        PaymentHash [32]byte
72

73
        // Expiry is the number of blocks after which this HTLC should expire.
74
        // It is the receiver's duty to ensure that the outgoing HTLC has a
75
        // sufficient expiry value to allow her to redeem the incoming HTLC.
76
        Expiry uint32
77

78
        // OnionBlob is the raw serialized mix header used to route an HTLC in
79
        // a privacy-preserving manner. The mix header is defined currently to
80
        // be parsed as a 4-tuple: (groupElement, routingInfo, headerMAC,
81
        // body).  First the receiving node should use the groupElement, and
82
        // its current onion key to derive a shared secret with the source.
83
        // Once the shared secret has been derived, the headerMAC should be
84
        // checked FIRST. Note that the MAC only covers the routingInfo field.
85
        // If the MAC matches, and the shared secret is fresh, then the node
86
        // should strip off a layer of encryption, exposing the next hop to be
87
        // used in the subsequent UpdateAddHTLC message.
88
        OnionBlob [OnionPacketSize]byte
89

90
        // BlindingPoint is the ephemeral pubkey used to optionally blind the
91
        // next hop for this htlc.
92
        BlindingPoint BlindingPointRecord
93

94
        // CustomRecords maps TLV types to byte slices, storing arbitrary data
95
        // intended for inclusion in the ExtraData field of the UpdateAddHTLC
96
        // message.
97
        CustomRecords CustomRecords
98

99
        // ExtraData is the set of data that was appended to this message to
100
        // fill out the full maximum transport message size. These fields can
101
        // be used to specify optional data such as custom TLV fields.
102
        ExtraData ExtraOpaqueData
103
}
104

105
// NewUpdateAddHTLC returns a new empty UpdateAddHTLC message.
106
func NewUpdateAddHTLC() *UpdateAddHTLC {
×
107
        return &UpdateAddHTLC{}
×
108
}
×
109

110
// A compile time check to ensure UpdateAddHTLC implements the lnwire.Message
111
// interface.
112
var _ Message = (*UpdateAddHTLC)(nil)
113

114
// Decode deserializes a serialized UpdateAddHTLC message stored in the passed
115
// io.Reader observing the specified protocol version.
116
//
117
// This is part of the lnwire.Message interface.
118
func (c *UpdateAddHTLC) Decode(r io.Reader, pver uint32) error {
2,420✔
119
        // msgExtraData is a temporary variable used to read the message extra
2,420✔
120
        // data field from the reader.
2,420✔
121
        var msgExtraData ExtraOpaqueData
2,420✔
122

2,420✔
123
        if err := ReadElements(r,
2,420✔
124
                &c.ChanID,
2,420✔
125
                &c.ID,
2,420✔
126
                &c.Amount,
2,420✔
127
                c.PaymentHash[:],
2,420✔
128
                &c.Expiry,
2,420✔
129
                c.OnionBlob[:],
2,420✔
130
                &msgExtraData,
2,420✔
131
        ); err != nil {
2,428✔
132
                return err
8✔
133
        }
8✔
134

135
        // Extract TLV records from the extra data field.
136
        blindingRecord := c.BlindingPoint.Zero()
2,412✔
137

2,412✔
138
        customRecords, parsed, extraData, err := ParseAndExtractCustomRecords(
2,412✔
139
                msgExtraData, &blindingRecord,
2,412✔
140
        )
2,412✔
141
        if err != nil {
2,443✔
142
                return err
31✔
143
        }
31✔
144

145
        // Assign the parsed records back to the message.
146
        if parsed.Contains(blindingRecord.TlvType()) {
2,452✔
147
                c.BlindingPoint = tlv.SomeRecordT(blindingRecord)
71✔
148
        }
71✔
149

150
        c.CustomRecords = customRecords
2,381✔
151
        c.ExtraData = extraData
2,381✔
152

2,381✔
153
        return nil
2,381✔
154
}
155

156
// Encode serializes the target UpdateAddHTLC into the passed io.Writer
157
// observing the protocol version specified.
158
//
159
// This is part of the lnwire.Message interface.
160
func (c *UpdateAddHTLC) Encode(w *bytes.Buffer, pver uint32) error {
3,506✔
161
        if err := WriteChannelID(w, c.ChanID); err != nil {
3,506✔
162
                return err
×
163
        }
×
164

165
        if err := WriteUint64(w, c.ID); err != nil {
3,506✔
166
                return err
×
167
        }
×
168

169
        if err := WriteMilliSatoshi(w, c.Amount); err != nil {
3,506✔
170
                return err
×
171
        }
×
172

173
        if err := WriteBytes(w, c.PaymentHash[:]); err != nil {
3,506✔
174
                return err
×
175
        }
×
176

177
        if err := WriteUint32(w, c.Expiry); err != nil {
3,506✔
178
                return err
×
179
        }
×
180

181
        if err := WriteBytes(w, c.OnionBlob[:]); err != nil {
3,506✔
182
                return err
×
183
        }
×
184

185
        // Only include blinding point in extra data if present.
186
        var records []tlv.RecordProducer
3,506✔
187
        c.BlindingPoint.WhenSome(
3,506✔
188
                func(b tlv.RecordT[BlindingPointTlvType, *btcec.PublicKey]) {
3,575✔
189
                        records = append(records, &b)
69✔
190
                },
69✔
191
        )
192

193
        extraData, err := MergeAndEncode(records, c.ExtraData, c.CustomRecords)
3,506✔
194
        if err != nil {
3,507✔
195
                return err
1✔
196
        }
1✔
197

198
        return WriteBytes(w, extraData)
3,505✔
199
}
200

201
// MsgType returns the integer uniquely identifying this message type on the
202
// wire.
203
//
204
// This is part of the lnwire.Message interface.
205
func (c *UpdateAddHTLC) MsgType() MessageType {
5,343✔
206
        return MsgUpdateAddHTLC
5,343✔
207
}
5,343✔
208

209
// TargetChanID returns the channel id of the link for which this message is
210
// intended.
211
//
212
// NOTE: Part of peer.LinkUpdater interface.
213
func (c *UpdateAddHTLC) TargetChanID() ChannelID {
2✔
214
        return c.ChanID
2✔
215
}
2✔
216

217
// SerializedSize returns the serialized size of the message in bytes.
218
//
219
// This is part of the lnwire.SizeableMessage interface.
UNCOV
220
func (c *UpdateAddHTLC) SerializedSize() (uint32, error) {
×
UNCOV
221
        return MessageSerializedSize(c)
×
UNCOV
222
}
×
223

224
// A compile time check to ensure UpdateAddHTLC implements the
225
// lnwire.SizeableMessage interface.
226
var _ SizeableMessage = (*UpdateAddHTLC)(nil)
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc