@@ -22,6 +22,7 @@ import (
2222 "github.com/btcsuite/btcwallet/walletdb"
2323 "github.com/lightningnetwork/lnd/aliasmgr"
2424 "github.com/lightningnetwork/lnd/batch"
25+ "github.com/lightningnetwork/lnd/fn/v2"
2526 "github.com/lightningnetwork/lnd/graph/db/models"
2627 "github.com/lightningnetwork/lnd/input"
2728 "github.com/lightningnetwork/lnd/kvdb"
@@ -284,6 +285,13 @@ func (c *KVStore) getChannelMap(edges kvdb.RBucket) (
284285 case errors .Is (err , ErrEdgePolicyOptionalFieldNotFound ):
285286 return nil
286287
288+ // We don't want a single policy with bad TLV data to stop us
289+ // from loading the rest of the data, so we just skip this
290+ // policy. This is for backwards compatibility since we did not
291+ // use to validate TLV data in the past before persisting it.
292+ case errors .Is (err , ErrParsingExtraTLVBytes ):
293+ return nil
294+
287295 case err != nil :
288296 return err
289297 }
@@ -474,24 +482,19 @@ func (c *KVStore) forEachNodeDirectedChannel(tx kvdb.RTx,
474482 cachedInPolicy .ToNodeFeatures = toNodeFeatures
475483 }
476484
477- var inboundFee lnwire.Fee
478- if p1 != nil {
479- // Extract inbound fee. If there is a decoding error,
480- // skip this edge.
481- _ , err := p1 .ExtraOpaqueData .ExtractRecords (& inboundFee )
482- if err != nil {
483- return nil
484- }
485- }
486-
487485 directedChannel := & DirectedChannel {
488486 ChannelID : e .ChannelID ,
489487 IsNode1 : node == e .NodeKey1Bytes ,
490488 OtherNode : e .NodeKey2Bytes ,
491489 Capacity : e .Capacity ,
492490 OutPolicySet : p1 != nil ,
493491 InPolicy : cachedInPolicy ,
494- InboundFee : inboundFee ,
492+ }
493+
494+ if p1 != nil {
495+ p1 .InboundFee .WhenSome (func (fee lnwire.Fee ) {
496+ directedChannel .InboundFee = fee
497+ })
495498 }
496499
497500 if node == e .NodeKey2Bytes {
@@ -2342,7 +2345,7 @@ func (c *KVStore) FilterChannelRange(startHeight,
23422345 edge , err := deserializeChanEdgePolicyRaw (r )
23432346 if err != nil && ! errors .Is (
23442347 err , ErrEdgePolicyOptionalFieldNotFound ,
2345- ) {
2348+ ) && ! errors . Is ( err , ErrParsingExtraTLVBytes ) {
23462349
23472350 return err
23482351 }
@@ -2357,7 +2360,7 @@ func (c *KVStore) FilterChannelRange(startHeight,
23572360 edge , err := deserializeChanEdgePolicyRaw (r )
23582361 if err != nil && ! errors .Is (
23592362 err , ErrEdgePolicyOptionalFieldNotFound ,
2360- ) {
2363+ ) && ! errors . Is ( err , ErrParsingExtraTLVBytes ) {
23612364
23622365 return err
23632366 }
@@ -4334,15 +4337,20 @@ func putChanEdgePolicy(edges kvdb.RwBucket, edge *models.ChannelEdgePolicy,
43344337 // need to deserialize the existing policy within the database
43354338 // (now outdated by the new one), and delete its corresponding
43364339 // entry within the update index. We'll ignore any
4337- // ErrEdgePolicyOptionalFieldNotFound error, as we only need
4338- // the channel ID and update time to delete the entry.
4340+ // ErrEdgePolicyOptionalFieldNotFound or ErrParsingExtraTLVBytes
4341+ // errors, as we only need the channel ID and update time to
4342+ // delete the entry.
4343+ //
43394344 // TODO(halseth): get rid of these invalid policies in a
43404345 // migration.
4346+ // TODO(elle): complete the above TODO in migration from kvdb
4347+ // to SQL.
43414348 oldEdgePolicy , err := deserializeChanEdgePolicy (
43424349 bytes .NewReader (edgeBytes ),
43434350 )
43444351 if err != nil &&
4345- ! errors .Is (err , ErrEdgePolicyOptionalFieldNotFound ) {
4352+ ! errors .Is (err , ErrEdgePolicyOptionalFieldNotFound ) &&
4353+ ! errors .Is (err , ErrParsingExtraTLVBytes ) {
43464354
43474355 return err
43484356 }
@@ -4449,6 +4457,11 @@ func fetchChanEdgePolicy(edges kvdb.RBucket, chanID []byte,
44494457 case errors .Is (err , ErrEdgePolicyOptionalFieldNotFound ):
44504458 return nil , nil
44514459
4460+ // If the policy contains invalid TLV bytes, we return nil as if
4461+ // the policy was unknown.
4462+ case errors .Is (err , ErrParsingExtraTLVBytes ):
4463+ return nil , nil
4464+
44524465 case err != nil :
44534466 return nil , err
44544467 }
@@ -4546,6 +4559,12 @@ func serializeChanEdgePolicy(w io.Writer, edge *models.ChannelEdgePolicy,
45464559 }
45474560 }
45484561
4562+ // Validate that the ExtraOpaqueData is in fact a valid TLV stream.
4563+ err = edge .ExtraOpaqueData .ValidateTLV ()
4564+ if err != nil {
4565+ return fmt .Errorf ("%w: %w" , ErrParsingExtraTLVBytes , err )
4566+ }
4567+
45494568 if len (edge .ExtraOpaqueData ) > MaxAllowedExtraOpaqueBytes {
45504569 return ErrTooManyExtraOpaqueBytes (len (edge .ExtraOpaqueData ))
45514570 }
@@ -4562,15 +4581,18 @@ func serializeChanEdgePolicy(w io.Writer, edge *models.ChannelEdgePolicy,
45624581
45634582func deserializeChanEdgePolicy (r io.Reader ) (* models.ChannelEdgePolicy , error ) {
45644583 // Deserialize the policy. Note that in case an optional field is not
4565- // found, both an error and a populated policy object are returned.
4566- edge , deserializeErr := deserializeChanEdgePolicyRaw (r )
4567- if deserializeErr != nil &&
4568- ! errors .Is (deserializeErr , ErrEdgePolicyOptionalFieldNotFound ) {
4584+ // found or if the edge has invalid TLV data, then both an error and a
4585+ // populated policy object are returned so that the caller can decide
4586+ // if it still wants to use the edge or not.
4587+ edge , err := deserializeChanEdgePolicyRaw (r )
4588+ if err != nil &&
4589+ ! errors .Is (err , ErrEdgePolicyOptionalFieldNotFound ) &&
4590+ ! errors .Is (err , ErrParsingExtraTLVBytes ) {
45694591
4570- return nil , deserializeErr
4592+ return nil , err
45714593 }
45724594
4573- return edge , deserializeErr
4595+ return edge , err
45744596}
45754597
45764598func deserializeChanEdgePolicyRaw (r io.Reader ) (* models.ChannelEdgePolicy ,
@@ -4657,6 +4679,22 @@ func deserializeChanEdgePolicyRaw(r io.Reader) (*models.ChannelEdgePolicy,
46574679 edge .ExtraOpaqueData = opq [8 :]
46584680 }
46594681
4682+ // Attempt to extract the inbound fee from the opaque data. If we fail
4683+ // to parse the TLV here, we return an error we also return the edge
4684+ // so that the caller can still use it. This is for backwards
4685+ // compatibility in case we have already persisted some policies that
4686+ // have invalid TLV data.
4687+ var inboundFee lnwire.Fee
4688+ typeMap , err := edge .ExtraOpaqueData .ExtractRecords (& inboundFee )
4689+ if err != nil {
4690+ return edge , fmt .Errorf ("%w: %w" , ErrParsingExtraTLVBytes , err )
4691+ }
4692+
4693+ val , ok := typeMap [lnwire .FeeRecordType ]
4694+ if ok && val == nil {
4695+ edge .InboundFee = fn .Some (inboundFee )
4696+ }
4697+
46604698 return edge , nil
46614699}
46624700
0 commit comments