@@ -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,118 @@ 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 (
1133+ & failureMsgBuf , uint16 (lnwire .CodeTemporaryChannelFailure ),
1134+ )
1135+ require .NoError (t , err )
1136+
1137+ // Write the length of the channel update (including invalid TLV).
1138+ err = lnwire .WriteUint16 (& failureMsgBuf , uint16 (chanUpdateBuf .Len ()))
1139+ require .NoError (t , err )
1140+
1141+ // Write the channel update bytes with invalid TLV appended.
1142+ _ , err = failureMsgBuf .Write (chanUpdateBuf .Bytes ())
1143+ require .NoError (t , err )
1144+
1145+ _ , err = lnwire .DecodeFailureMessage (& failureMsgBuf , 0 )
1146+ require .ErrorIs (t , err , lnwire .ErrParsingExtraTLVBytes )
1147+ require .ErrorIs (t , err , io .ErrUnexpectedEOF )
1148+
1149+ // Create an HTLCFailInfo and serialize it with the corrupted failure
1150+ // message.
1151+ failInfo := & HTLCFailInfo {
1152+ FailTime : time .Now (),
1153+ Reason : HTLCFailMessage ,
1154+ FailureSourceIndex : 2 ,
1155+ }
1156+
1157+ var buf bytes.Buffer
1158+
1159+ // Manually serialize the HTLCFailInfo with the corrupted failure bytes.
1160+ err = serializeTime (& buf , failInfo .FailTime )
1161+ require .NoError (t , err )
1162+
1163+ // Write the failure message bytes.
1164+ err = wire .WriteVarBytes (& buf , 0 , failureMsgBuf .Bytes ())
1165+ require .NoError (t , err )
1166+
1167+ // Write reason and failure source index.
1168+ err = WriteElements (
1169+ & buf , byte (failInfo .Reason ), failInfo .FailureSourceIndex ,
1170+ )
1171+ require .NoError (t , err )
1172+
1173+ // Now deserialize the HTLCFailInfo - this should NOT fail despite the
1174+ // invalid TLV data.
1175+ deserializedFailInfo , err := deserializeHTLCFailInfo (& buf )
1176+ require .NoError (t , err , "deserializeHTLCFailInfo should not fail " +
1177+ "with invalid TLV data" )
1178+ require .NotNil (t , deserializedFailInfo )
1179+
1180+ // Verify the basic fields are correctly deserialized.
1181+ require .Equal (t , failInfo .Reason , deserializedFailInfo .Reason )
1182+ require .Equal (t , failInfo .FailureSourceIndex ,
1183+ deserializedFailInfo .FailureSourceIndex )
1184+
1185+ // Verify the failure message is nil because the decoding failed
1186+ // due to invalid TLV data. The important part is that the
1187+ // HTLCFailInfo deserialization still succeeded despite the invalid
1188+ // TLV data in the failure message.
1189+ require .Nil (t , deserializedFailInfo .Message ,
1190+ "Message should be nil when TLV parsing fails" )
1191+ }
0 commit comments