@@ -2,11 +2,15 @@ package paymentsdb
22
33import (
44 "bytes"
5+ "encoding/binary"
6+ "io"
57 "math"
68 "reflect"
79 "testing"
810 "time"
911
12+ "github.com/btcsuite/btcd/btcec/v2/ecdsa"
13+ "github.com/btcsuite/btcd/wire"
1014 "github.com/btcsuite/btcwallet/walletdb"
1115 "github.com/lightningnetwork/lnd/kvdb"
1216 "github.com/lightningnetwork/lnd/lntypes"
@@ -1070,3 +1074,116 @@ func TestLazySessionKeyDeserialize(t *testing.T) {
10701074 sessionKey := attempt .SessionKey ()
10711075 require .Equal (t , priv , sessionKey )
10721076}
1077+
1078+ // TestDeserializeHTLCFailInfoInvalidTLV tests that deserializeHTLCFailInfo
1079+ // handles invalid extra tlv data gracefully by not failing.
1080+ func TestDeserializeHTLCFailInfoInvalidTLV (t * testing.T ) {
1081+ // Create a channel update with valid data first, then encode it.
1082+ testSig := & ecdsa.Signature {}
1083+ sig , _ := lnwire .NewSigFromSignature (testSig )
1084+ chanUpdate := & lnwire.ChannelUpdate1 {
1085+ Signature : sig ,
1086+ ShortChannelID : lnwire .NewShortChanIDFromInt (1 ),
1087+ Timestamp : 1 ,
1088+ MessageFlags : 0 ,
1089+ ChannelFlags : 1 ,
1090+ ExtraOpaqueData : make ([]byte , 0 ),
1091+ }
1092+
1093+ var chanUpdateBuf bytes.Buffer
1094+ err := chanUpdate .Encode (& chanUpdateBuf , 0 )
1095+ require .NoError (t , err )
1096+
1097+ // Append invalid inbound fee TLV record to the encoded channel update.
1098+ // The inbound fee TLV has type 55555 and should have 8 bytes of data
1099+ // (2 uint32 values: BaseFee and FeeRate). We create an invalid one by
1100+ // using the correct type but with incomplete data (only 6 bytes
1101+ // instead of 8).
1102+ var invalidInboundFeeTLV bytes.Buffer
1103+
1104+ // Write type 55555 as varint: 0xfd + 2 bytes (canonical encoding)
1105+ err = invalidInboundFeeTLV .WriteByte (0xfd )
1106+ require .NoError (t , err )
1107+
1108+ var typeBytes [2 ]byte
1109+ binary .BigEndian .PutUint16 (typeBytes [:], 55555 )
1110+ _ , err = invalidInboundFeeTLV .Write (typeBytes [:])
1111+ require .NoError (t , err )
1112+
1113+ // Write length as 8 (single byte since 8 < 0xfd, no varint needed)
1114+ err = invalidInboundFeeTLV .WriteByte (8 )
1115+ require .NoError (t , err )
1116+
1117+ // Write only 6 bytes of value data (incomplete, should be 8 bytes)
1118+ var valueBytes [6 ]byte
1119+ binary .BigEndian .PutUint32 (valueBytes [0 :4 ], 1 )
1120+ binary .BigEndian .PutUint16 (valueBytes [4 :6 ], 2 )
1121+ _ , err = invalidInboundFeeTLV .Write (valueBytes [:])
1122+ require .NoError (t , err )
1123+
1124+ _ , err = chanUpdateBuf .Write (invalidInboundFeeTLV .Bytes ())
1125+ require .NoError (t , err )
1126+
1127+ // Manually create a TemporaryChannelFailure failure message with the
1128+ // corrupted channel update bytes.
1129+ var failureMsgBuf bytes.Buffer
1130+
1131+ // Write the failure code.
1132+ err = lnwire .WriteUint16 (& failureMsgBuf ,
1133+ uint16 (lnwire .CodeTemporaryChannelFailure ))
1134+ require .NoError (t , err )
1135+
1136+ // Write the length of the channel update (including invalid TLV).
1137+ err = lnwire .WriteUint16 (& failureMsgBuf , uint16 (chanUpdateBuf .Len ()))
1138+ require .NoError (t , err )
1139+
1140+ // Write the channel update bytes with invalid TLV appended.
1141+ _ , err = failureMsgBuf .Write (chanUpdateBuf .Bytes ())
1142+ require .NoError (t , err )
1143+
1144+ _ , err = lnwire .DecodeFailureMessage (& failureMsgBuf , 0 )
1145+ require .ErrorIs (t , err , lnwire .ErrParsingExtraTLVBytes )
1146+ require .ErrorIs (t , err , io .ErrUnexpectedEOF )
1147+
1148+ // Create an HTLCFailInfo and serialize it with the corrupted failure
1149+ // message.
1150+ failInfo := & HTLCFailInfo {
1151+ FailTime : time .Now (),
1152+ Reason : HTLCFailMessage ,
1153+ FailureSourceIndex : 2 ,
1154+ }
1155+
1156+ var buf bytes.Buffer
1157+
1158+ // Manually serialize the HTLCFailInfo with the corrupted failure bytes.
1159+ err = serializeTime (& buf , failInfo .FailTime )
1160+ require .NoError (t , err )
1161+
1162+ // Write the failure message bytes.
1163+ err = wire .WriteVarBytes (& buf , 0 , failureMsgBuf .Bytes ())
1164+ require .NoError (t , err )
1165+
1166+ // Write reason and failure source index.
1167+ err = WriteElements (& buf , byte (failInfo .Reason ),
1168+ failInfo .FailureSourceIndex )
1169+ require .NoError (t , err )
1170+
1171+ // Now deserialize the HTLCFailInfo - this should NOT fail despite the
1172+ // invalid TLV data.
1173+ deserializedFailInfo , err := deserializeHTLCFailInfo (& buf )
1174+ require .NoError (t , err , "deserializeHTLCFailInfo should not fail " +
1175+ "with invalid TLV data" )
1176+ require .NotNil (t , deserializedFailInfo )
1177+
1178+ // Verify the basic fields are correctly deserialized.
1179+ require .Equal (t , failInfo .Reason , deserializedFailInfo .Reason )
1180+ require .Equal (t , failInfo .FailureSourceIndex ,
1181+ deserializedFailInfo .FailureSourceIndex )
1182+
1183+ // Verify the failure message is nil because the decoding failed
1184+ // due to invalid TLV data. The important part is that the
1185+ // HTLCFailInfo deserialization still succeeded despite the invalid
1186+ // TLV data in the failure message.
1187+ require .Nil (t , deserializedFailInfo .Message ,
1188+ "Message should be nil when TLV parsing fails" )
1189+ }
0 commit comments