diff --git a/.gitignore b/.gitignore index 5ddd602d3..1e498b0cf 100644 --- a/.gitignore +++ b/.gitignore @@ -80,3 +80,5 @@ coverage.txt # Release build directory (to avoid build.vcs.modified Golang build tag to be # set to true by having untracked files in the working directory). /lnd-*/ + +.aider* diff --git a/lnwire/accept_channel.go b/lnwire/accept_channel.go index aace5d536..afb2f1412 100644 --- a/lnwire/accept_channel.go +++ b/lnwire/accept_channel.go @@ -128,8 +128,8 @@ type AcceptChannel struct { // interface. var _ Message = (*AcceptChannel)(nil) -// A compile time check to ensure AcceptChannel implements the lnwire.SizeableMessage -// interface. +// A compile time check to ensure AcceptChannel implements the +// lnwire.SizeableMessage interface. var _ SizeableMessage = (*AcceptChannel)(nil) // Encode serializes the target AcceptChannel into the passed io.Writer diff --git a/lnwire/channel_update.go b/lnwire/channel_update.go index 1c7f0eed2..88f981671 100644 --- a/lnwire/channel_update.go +++ b/lnwire/channel_update.go @@ -124,7 +124,8 @@ type ChannelUpdate1 struct { // interface. var _ Message = (*ChannelUpdate1)(nil) -// A compile time check to ensure ChannelUpdate1 implements the lnwire.SizeableMessage interface. +// A compile time check to ensure ChannelUpdate1 implements the +// lnwire.SizeableMessage interface. var _ SizeableMessage = (*ChannelUpdate1)(nil) // Decode deserializes a serialized ChannelUpdate stored in the passed diff --git a/lnwire/closing_complete.go b/lnwire/closing_complete.go index 14784a3c1..7980ef1ee 100644 --- a/lnwire/closing_complete.go +++ b/lnwire/closing_complete.go @@ -180,5 +180,6 @@ func (c *ClosingComplete) SerializedSize() (uint32, error) { // interface. var _ Message = (*ClosingComplete)(nil) -// A compile time check to ensure ClosingComplete implements the lnwire.SizeableMessage interface. +// A compile time check to ensure ClosingComplete implements the +// lnwire.SizeableMessage interface. var _ SizeableMessage = (*ClosingComplete)(nil) diff --git a/lnwire/closing_sig.go b/lnwire/closing_sig.go index 1eeec2580..94a356066 100644 --- a/lnwire/closing_sig.go +++ b/lnwire/closing_sig.go @@ -118,6 +118,6 @@ func (c *ClosingSig) SerializedSize() (uint32, error) { // interface. var _ Message = (*ClosingSig)(nil) -// A compile time check to ensure ClosingSig implements the lnwire.SizeableMessage -// interface. +// A compile time check to ensure ClosingSig implements the +// lnwire.SizeableMessage interface. var _ SizeableMessage = (*ClosingSig)(nil) diff --git a/lnwire/closing_signed.go b/lnwire/closing_signed.go index a82dbf402..c247cfe0a 100644 --- a/lnwire/closing_signed.go +++ b/lnwire/closing_signed.go @@ -59,7 +59,8 @@ func NewClosingSigned(cid ChannelID, fs btcutil.Amount, // interface. var _ Message = (*ClosingSigned)(nil) -// A compile time check to ensure ClosingSigned implements the lnwire.SizeableMessage interface. +// A compile time check to ensure ClosingSigned implements the +// lnwire.SizeableMessage interface. var _ SizeableMessage = (*ClosingSigned)(nil) // Decode deserializes a serialized ClosingSigned message stored in the passed diff --git a/lnwire/commit_sig.go b/lnwire/commit_sig.go index 7c5a41ccc..600ff81e7 100644 --- a/lnwire/commit_sig.go +++ b/lnwire/commit_sig.go @@ -64,7 +64,8 @@ func NewCommitSig() *CommitSig { // interface. var _ Message = (*CommitSig)(nil) -// A compile time check to ensure CommitSig implements the lnwire.SizeableMessage interface. +// A compile time check to ensure CommitSig implements the +// lnwire.SizeableMessage interface. var _ SizeableMessage = (*CommitSig)(nil) // Decode deserializes a serialized CommitSig message stored in the diff --git a/lnwire/custom.go b/lnwire/custom.go index e8c299297..740c23a14 100644 --- a/lnwire/custom.go +++ b/lnwire/custom.go @@ -69,7 +69,7 @@ type Custom struct { Data []byte } -// A compile time check to ensure FundingCreated implements the lnwire.Message +// A compile time check to ensure Custom implements the lnwire.Message // interface. var _ Message = (*Custom)(nil) diff --git a/lnwire/funding_signed.go b/lnwire/funding_signed.go index a7f23310a..182e4bbde 100644 --- a/lnwire/funding_signed.go +++ b/lnwire/funding_signed.go @@ -36,8 +36,8 @@ type FundingSigned struct { // interface. var _ Message = (*FundingSigned)(nil) -// A compile time check to ensure FundingSigned implements the lnwire.SizeableMessage -// interface. +// A compile time check to ensure FundingSigned implements the +// lnwire.SizeableMessage interface. var _ SizeableMessage = (*FundingSigned)(nil) // Encode serializes the target FundingSigned into the passed io.Writer diff --git a/lnwire/gossip_timestamp_range.go b/lnwire/gossip_timestamp_range.go index 25c2a033b..45ff1f939 100644 --- a/lnwire/gossip_timestamp_range.go +++ b/lnwire/gossip_timestamp_range.go @@ -58,7 +58,8 @@ func NewGossipTimestampRange() *GossipTimestampRange { // lnwire.Message interface. var _ Message = (*GossipTimestampRange)(nil) -// A compile time check to ensure GossipTimestampRange implements the lnwire.SizeableMessage interface. +// A compile time check to ensure GossipTimestampRange implements the +// lnwire.SizeableMessage interface. var _ SizeableMessage = (*GossipTimestampRange)(nil) // Decode deserializes a serialized GossipTimestampRange message stored in the diff --git a/lnwire/kickoff_sig.go b/lnwire/kickoff_sig.go index 3e46db453..b9c4c206a 100644 --- a/lnwire/kickoff_sig.go +++ b/lnwire/kickoff_sig.go @@ -27,6 +27,10 @@ type KickoffSig struct { // interface. var _ Message = (*KickoffSig)(nil) +// A compile time check to ensure KickoffSig implements the +// lnwire.SizeableMessage interface. +var _ SizeableMessage = (*KickoffSig)(nil) + // Encode serializes the target KickoffSig into the passed bytes.Buffer // observing the specified protocol version. // @@ -54,3 +58,10 @@ func (ks *KickoffSig) Decode(r io.Reader, _ uint32) error { // // This is part of the lnwire.Message interface. func (ks *KickoffSig) MsgType() MessageType { return MsgKickoffSig } + +// SerializedSize returns the serialized size of the message in bytes. +// +// This is part of the lnwire.SizeableMessage interface. +func (ks *KickoffSig) SerializedSize() (uint32, error) { + return MessageSerializedSize(ks) +} diff --git a/lnwire/message.go b/lnwire/message.go index 8c310bd78..ea480075a 100644 --- a/lnwire/message.go +++ b/lnwire/message.go @@ -65,6 +65,11 @@ const ( MsgChannelAnnouncement2 = 267 MsgChannelUpdate2 = 271 MsgKickoffSig = 777 + + // MsgEnd defines the end of the official message range of the protocol. + // If a new message is added beyond this message, then this should be + // modified. + MsgEnd = 778 ) // IsChannelUpdate is a filter function that discerns channel update messages diff --git a/lnwire/node_announcement.go b/lnwire/node_announcement.go index ae883e886..5ba2d7a1d 100644 --- a/lnwire/node_announcement.go +++ b/lnwire/node_announcement.go @@ -104,7 +104,8 @@ type NodeAnnouncement struct { // lnwire.Message interface. var _ Message = (*NodeAnnouncement)(nil) -// A compile time check to ensure NodeAnnouncement implements the lnwire.SizeableMessage interface. +// A compile time check to ensure NodeAnnouncement implements the +// lnwire.SizeableMessage interface. var _ SizeableMessage = (*NodeAnnouncement)(nil) // Decode deserializes a serialized NodeAnnouncement stored in the passed diff --git a/lnwire/open_channel.go b/lnwire/open_channel.go index 217ddbea0..1751f748b 100644 --- a/lnwire/open_channel.go +++ b/lnwire/open_channel.go @@ -164,8 +164,8 @@ type OpenChannel struct { // interface. var _ Message = (*OpenChannel)(nil) -// A compile time check to ensure OpenChannel implements the lnwire.SizeableMessage -// interface. +// A compile time check to ensure OpenChannel implements the +// lnwire.SizeableMessage interface. var _ SizeableMessage = (*OpenChannel)(nil) // Encode serializes the target OpenChannel into the passed io.Writer diff --git a/lnwire/query_channel_range.go b/lnwire/query_channel_range.go index 90b144bda..c816a0050 100644 --- a/lnwire/query_channel_range.go +++ b/lnwire/query_channel_range.go @@ -49,8 +49,8 @@ func NewQueryChannelRange() *QueryChannelRange { // lnwire.Message interface. var _ Message = (*QueryChannelRange)(nil) -// A compile time check to ensure QueryChannelRange implements the lnwire.SizeableMessage -// interface. +// A compile time check to ensure QueryChannelRange implements the +// lnwire.SizeableMessage interface. var _ SizeableMessage = (*QueryChannelRange)(nil) // Decode deserializes a serialized QueryChannelRange message stored in the diff --git a/lnwire/query_short_chan_ids.go b/lnwire/query_short_chan_ids.go index f12d07abf..37a73ab7c 100644 --- a/lnwire/query_short_chan_ids.go +++ b/lnwire/query_short_chan_ids.go @@ -91,8 +91,8 @@ func NewQueryShortChanIDs(h chainhash.Hash, e QueryEncoding, // lnwire.Message interface. var _ Message = (*QueryShortChanIDs)(nil) -// A compile time check to ensure QueryShortChanIDs implements the lnwire.SizeableMessage -// interface. +// A compile time check to ensure QueryShortChanIDs implements the +// lnwire.SizeableMessage interface. var _ SizeableMessage = (*QueryShortChanIDs)(nil) // Decode deserializes a serialized QueryShortChanIDs message stored in the diff --git a/lnwire/reply_channel_range.go b/lnwire/reply_channel_range.go index a3b11c53e..c3a744ebd 100644 --- a/lnwire/reply_channel_range.go +++ b/lnwire/reply_channel_range.go @@ -70,7 +70,8 @@ func NewReplyChannelRange() *ReplyChannelRange { // lnwire.Message interface. var _ Message = (*ReplyChannelRange)(nil) -// A compile time check to ensure ReplyChannelRange implements the lnwire.SizeableMessage interface. +// A compile time check to ensure ReplyChannelRange implements the +// lnwire.SizeableMessage interface. var _ SizeableMessage = (*ReplyChannelRange)(nil) // Decode deserializes a serialized ReplyChannelRange message stored in the diff --git a/lnwire/reply_short_chan_ids_end.go b/lnwire/reply_short_chan_ids_end.go index 30660a9cf..2e50d840f 100644 --- a/lnwire/reply_short_chan_ids_end.go +++ b/lnwire/reply_short_chan_ids_end.go @@ -39,7 +39,8 @@ func NewReplyShortChanIDsEnd() *ReplyShortChanIDsEnd { // lnwire.Message interface. var _ Message = (*ReplyShortChanIDsEnd)(nil) -// A compile time check to ensure ReplyShortChanIDsEnd implements the lnwire.SizeableMessage interface. +// A compile time check to ensure ReplyShortChanIDsEnd implements the +// lnwire.SizeableMessage interface. var _ SizeableMessage = (*ReplyShortChanIDsEnd)(nil) // Decode deserializes a serialized ReplyShortChanIDsEnd message stored in the diff --git a/lnwire/revoke_and_ack.go b/lnwire/revoke_and_ack.go index aa70b0714..3c9775c99 100644 --- a/lnwire/revoke_and_ack.go +++ b/lnwire/revoke_and_ack.go @@ -55,7 +55,8 @@ func NewRevokeAndAck() *RevokeAndAck { // interface. var _ Message = (*RevokeAndAck)(nil) -// A compile time check to ensure RevokeAndAck implements the lnwire.SizeableMessage interface. +// A compile time check to ensure RevokeAndAck implements the +// lnwire.SizeableMessage interface. var _ SizeableMessage = (*RevokeAndAck)(nil) // Decode deserializes a serialized RevokeAndAck message stored in the diff --git a/lnwire/shutdown.go b/lnwire/shutdown.go index 9ac6eb131..28df9a4ca 100644 --- a/lnwire/shutdown.go +++ b/lnwire/shutdown.go @@ -61,7 +61,8 @@ func NewShutdown(cid ChannelID, addr DeliveryAddress) *Shutdown { // interface. var _ Message = (*Shutdown)(nil) -// A compile-time check to ensure Shutdown implements the lnwire.SizeableMessage interface. +// A compile-time check to ensure Shutdown implements the lnwire.SizeableMessage +// interface. var _ SizeableMessage = (*Shutdown)(nil) // Decode deserializes a serialized Shutdown from the passed io.Reader, diff --git a/lnwire/stfu.go b/lnwire/stfu.go index f923c94b8..8e57739d5 100644 --- a/lnwire/stfu.go +++ b/lnwire/stfu.go @@ -24,7 +24,8 @@ type Stfu struct { // A compile time check to ensure Stfu implements the lnwire.Message interface. var _ Message = (*Stfu)(nil) -// A compile time check to ensure Stfu implements the lnwire.SizeableMessage interface. +// A compile time check to ensure Stfu implements the lnwire.SizeableMessage +// interface. var _ SizeableMessage = (*Stfu)(nil) // Encode serializes the target Stfu into the passed io.Writer. diff --git a/lnwire/test_message.go b/lnwire/test_message.go new file mode 100644 index 000000000..8b3d98400 --- /dev/null +++ b/lnwire/test_message.go @@ -0,0 +1,1669 @@ +package lnwire + +import ( + "bytes" + "fmt" + "image/color" + "math" + + "github.com/btcsuite/btcd/btcec/v2" + "github.com/btcsuite/btcd/btcutil" + "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/lightningnetwork/lnd/fn/v2" + "github.com/lightningnetwork/lnd/lnwallet/chainfee" + "github.com/lightningnetwork/lnd/tlv" + "pgregory.net/rapid" +) + +// TestMessage is an interface that extends the base Message interface with a +// method to populate the message with random testing data. +type TestMessage interface { + Message + + // RandTestMessage populates the message with random data suitable for + // testing. It uses the rapid testing framework to generate random + // values. + RandTestMessage(t *rapid.T) Message +} + +// A compile time check to ensure AcceptChannel implements the TestMessage +// interface. +var _ TestMessage = (*AcceptChannel)(nil) + +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (a *AcceptChannel) RandTestMessage(t *rapid.T) Message { + var pendingChanID [32]byte + pendingChanIDBytes := rapid.SliceOfN(rapid.Byte(), 32, 32).Draw( + t, "pendingChanID", + ) + copy(pendingChanID[:], pendingChanIDBytes) + + var channelType *ChannelType + includeChannelType := rapid.Bool().Draw(t, "includeChannelType") + includeLeaseExpiry := rapid.Bool().Draw(t, "includeLeaseExpiry") + includeLocalNonce := rapid.Bool().Draw(t, "includeLocalNonce") + + if includeChannelType { + channelType = RandChannelType(t) + } + + var leaseExpiry *LeaseExpiry + if includeLeaseExpiry { + leaseExpiry = RandLeaseExpiry(t) + } + + var localNonce OptMusig2NonceTLV + if includeLocalNonce { + nonce := RandMusig2Nonce(t) + localNonce = tlv.SomeRecordT( + tlv.NewRecordT[NonceRecordTypeT, Musig2Nonce](nonce), + ) + } + + return &AcceptChannel{ + PendingChannelID: pendingChanID, + DustLimit: btcutil.Amount( + rapid.IntRange(100, 1000).Draw(t, "dustLimit"), + ), + MaxValueInFlight: MilliSatoshi( + rapid.IntRange(10000, 1000000).Draw( + t, "maxValueInFlight", + ), + ), + ChannelReserve: btcutil.Amount( + rapid.IntRange(1000, 10000).Draw(t, "channelReserve"), + ), + HtlcMinimum: MilliSatoshi( + rapid.IntRange(1, 1000).Draw(t, "htlcMinimum"), + ), + MinAcceptDepth: uint32( + rapid.IntRange(1, 10).Draw(t, "minAcceptDepth"), + ), + CsvDelay: uint16( + rapid.IntRange(144, 1000).Draw(t, "csvDelay"), + ), + MaxAcceptedHTLCs: uint16( + rapid.IntRange(10, 500).Draw(t, "maxAcceptedHTLCs"), + ), + FundingKey: RandPubKey(t), + RevocationPoint: RandPubKey(t), + PaymentPoint: RandPubKey(t), + DelayedPaymentPoint: RandPubKey(t), + HtlcPoint: RandPubKey(t), + FirstCommitmentPoint: RandPubKey(t), + UpfrontShutdownScript: RandDeliveryAddress(t), + ChannelType: channelType, + LeaseExpiry: leaseExpiry, + LocalNonce: localNonce, + ExtraData: RandExtraOpaqueData(t, nil), + } +} + +// A compile time check to ensure AnnounceSignatures1 implements the +// lnwire.TestMessage interface. +var _ TestMessage = (*AnnounceSignatures1)(nil) + +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (a *AnnounceSignatures1) RandTestMessage(t *rapid.T) Message { + return &AnnounceSignatures1{ + ChannelID: RandChannelID(t), + ShortChannelID: RandShortChannelID(t), + NodeSignature: RandSignature(t), + BitcoinSignature: RandSignature(t), + ExtraOpaqueData: RandExtraOpaqueData(t, nil), + } +} + +// A compile time check to ensure AnnounceSignatures2 implements the +// lnwire.TestMessage interface. +var _ TestMessage = (*AnnounceSignatures2)(nil) + +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (a *AnnounceSignatures2) RandTestMessage(t *rapid.T) Message { + return &AnnounceSignatures2{ + ChannelID: RandChannelID(t), + ShortChannelID: RandShortChannelID(t), + PartialSignature: *RandPartialSig(t), + ExtraOpaqueData: RandExtraOpaqueData(t, nil), + } +} + +// A compile time check to ensure ChannelAnnouncement1 implements the +// TestMessage interface. +var _ TestMessage = (*ChannelAnnouncement1)(nil) + +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (a *ChannelAnnouncement1) RandTestMessage(t *rapid.T) Message { + // Generate Node IDs and Bitcoin keys (compressed public keys) + node1PubKey := RandPubKey(t) + node2PubKey := RandPubKey(t) + bitcoin1PubKey := RandPubKey(t) + bitcoin2PubKey := RandPubKey(t) + + // Convert to byte arrays + var nodeID1, nodeID2, bitcoinKey1, bitcoinKey2 [33]byte + copy(nodeID1[:], node1PubKey.SerializeCompressed()) + copy(nodeID2[:], node2PubKey.SerializeCompressed()) + copy(bitcoinKey1[:], bitcoin1PubKey.SerializeCompressed()) + copy(bitcoinKey2[:], bitcoin2PubKey.SerializeCompressed()) + + // Ensure nodeID1 is numerically less than nodeID2 + // This is a requirement stated in the field description + if bytes.Compare(nodeID1[:], nodeID2[:]) > 0 { + nodeID1, nodeID2 = nodeID2, nodeID1 + } + + // Generate chain hash + chainHash := RandChainHash(t) + var hash chainhash.Hash + copy(hash[:], chainHash[:]) + + return &ChannelAnnouncement1{ + NodeSig1: RandSignature(t), + NodeSig2: RandSignature(t), + BitcoinSig1: RandSignature(t), + BitcoinSig2: RandSignature(t), + Features: RandFeatureVector(t), + ChainHash: hash, + ShortChannelID: RandShortChannelID(t), + NodeID1: nodeID1, + NodeID2: nodeID2, + BitcoinKey1: bitcoinKey1, + BitcoinKey2: bitcoinKey2, + ExtraOpaqueData: RandExtraOpaqueData(t, nil), + } +} + +// A compile time check to ensure ChannelAnnouncement2 implements the +// lnwire.TestMessage interface. +var _ TestMessage = (*ChannelAnnouncement2)(nil) + +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (c *ChannelAnnouncement2) RandTestMessage(t *rapid.T) Message { + features := RandFeatureVector(t) + shortChanID := RandShortChannelID(t) + capacity := uint64(rapid.IntRange(1, 16777215).Draw(t, "capacity")) + + var nodeID1, nodeID2 [33]byte + copy(nodeID1[:], RandPubKey(t).SerializeCompressed()) + copy(nodeID2[:], RandPubKey(t).SerializeCompressed()) + + // Make sure nodeID1 is numerically less than nodeID2 (as per spec). + if bytes.Compare(nodeID1[:], nodeID2[:]) > 0 { + nodeID1, nodeID2 = nodeID2, nodeID1 + } + + chainHash := RandChainHash(t) + var chainHashObj chainhash.Hash + copy(chainHashObj[:], chainHash[:]) + + msg := &ChannelAnnouncement2{ + Signature: RandSignature(t), + ChainHash: tlv.NewPrimitiveRecord[tlv.TlvType0, chainhash.Hash]( + chainHashObj, + ), + Features: tlv.NewRecordT[tlv.TlvType2, RawFeatureVector]( + *features, + ), + ShortChannelID: tlv.NewRecordT[tlv.TlvType4, ShortChannelID]( + shortChanID, + ), + Capacity: tlv.NewPrimitiveRecord[tlv.TlvType6, uint64]( + capacity, + ), + NodeID1: tlv.NewPrimitiveRecord[tlv.TlvType8, [33]byte]( + nodeID1, + ), + NodeID2: tlv.NewPrimitiveRecord[tlv.TlvType10, [33]byte]( + nodeID2, + ), + ExtraOpaqueData: RandExtraOpaqueData(t, nil), + } + + msg.Signature.ForceSchnorr() + + // Randomly include optional fields + if rapid.Bool().Draw(t, "includeBitcoinKey1") { + var bitcoinKey1 [33]byte + copy(bitcoinKey1[:], RandPubKey(t).SerializeCompressed()) + msg.BitcoinKey1 = tlv.SomeRecordT( + tlv.NewPrimitiveRecord[tlv.TlvType12, [33]byte]( + bitcoinKey1, + ), + ) + } + + if rapid.Bool().Draw(t, "includeBitcoinKey2") { + var bitcoinKey2 [33]byte + copy(bitcoinKey2[:], RandPubKey(t).SerializeCompressed()) + msg.BitcoinKey2 = tlv.SomeRecordT( + tlv.NewPrimitiveRecord[tlv.TlvType14, [33]byte]( + bitcoinKey2, + ), + ) + } + + if rapid.Bool().Draw(t, "includeMerkleRootHash") { + hash := RandSHA256Hash(t) + var merkleRootHash [32]byte + copy(merkleRootHash[:], hash[:]) + msg.MerkleRootHash = tlv.SomeRecordT( + tlv.NewPrimitiveRecord[tlv.TlvType16, [32]byte]( + merkleRootHash, + ), + ) + } + + return msg +} + +// A compile time check to ensure ChannelReady implements the lnwire.TestMessage +// interface. +var _ TestMessage = (*ChannelReady)(nil) + +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (c *ChannelReady) RandTestMessage(t *rapid.T) Message { + msg := &ChannelReady{ + ChanID: RandChannelID(t), + NextPerCommitmentPoint: RandPubKey(t), + ExtraData: RandExtraOpaqueData(t, nil), + } + + includeAliasScid := rapid.Bool().Draw(t, "includeAliasScid") + includeNextLocalNonce := rapid.Bool().Draw(t, "includeNextLocalNonce") + includeAnnouncementNodeNonce := rapid.Bool().Draw( + t, "includeAnnouncementNodeNonce", + ) + includeAnnouncementBitcoinNonce := rapid.Bool().Draw( + t, "includeAnnouncementBitcoinNonce", + ) + + if includeAliasScid { + scid := RandShortChannelID(t) + msg.AliasScid = &scid + } + + if includeNextLocalNonce { + nonce := RandMusig2Nonce(t) + msg.NextLocalNonce = SomeMusig2Nonce(nonce) + } + + if includeAnnouncementNodeNonce { + nonce := RandMusig2Nonce(t) + msg.AnnouncementNodeNonce = tlv.SomeRecordT( + tlv.NewRecordT[tlv.TlvType0, Musig2Nonce](nonce), + ) + } + + if includeAnnouncementBitcoinNonce { + nonce := RandMusig2Nonce(t) + msg.AnnouncementBitcoinNonce = tlv.SomeRecordT( + tlv.NewRecordT[tlv.TlvType2, Musig2Nonce](nonce), + ) + } + + return msg +} + +// A compile time check to ensure ChannelReestablish implements the +// lnwire.TestMessage interface. +var _ TestMessage = (*ChannelReestablish)(nil) + +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (a *ChannelReestablish) RandTestMessage(t *rapid.T) Message { + msg := &ChannelReestablish{ + ChanID: RandChannelID(t), + NextLocalCommitHeight: rapid.Uint64().Draw( + t, "nextLocalCommitHeight", + ), + RemoteCommitTailHeight: rapid.Uint64().Draw( + t, "remoteCommitTailHeight", + ), + LastRemoteCommitSecret: RandPaymentPreimage(t), + LocalUnrevokedCommitPoint: RandPubKey(t), + ExtraData: RandExtraOpaqueData(t, nil), + } + + // Randomly decide whether to include optional fields + includeLocalNonce := rapid.Bool().Draw(t, "includeLocalNonce") + includeDynHeight := rapid.Bool().Draw(t, "includeDynHeight") + + if includeLocalNonce { + nonce := RandMusig2Nonce(t) + msg.LocalNonce = SomeMusig2Nonce(nonce) + } + + if includeDynHeight { + height := DynHeight(rapid.Uint64().Draw(t, "dynHeight")) + msg.DynHeight = fn.Some(height) + } + + return msg +} + +// A compile time check to ensure ChannelUpdate1 implements the TestMessage +// interface. +var _ TestMessage = (*ChannelUpdate1)(nil) + +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (a *ChannelUpdate1) RandTestMessage(t *rapid.T) Message { + // Generate random message flags + // Randomly decide whether to include max HTLC field + includeMaxHtlc := rapid.Bool().Draw(t, "includeMaxHtlc") + var msgFlags ChanUpdateMsgFlags + if includeMaxHtlc { + msgFlags |= ChanUpdateRequiredMaxHtlc + } + + // Generate random channel flags + // Randomly decide direction (node1 or node2) + isNode2 := rapid.Bool().Draw(t, "isNode2") + var chanFlags ChanUpdateChanFlags + if isNode2 { + chanFlags |= ChanUpdateDirection + } + + // Randomly decide if channel is disabled + isDisabled := rapid.Bool().Draw(t, "isDisabled") + if isDisabled { + chanFlags |= ChanUpdateDisabled + } + + // Generate chain hash + chainHash := RandChainHash(t) + var hash chainhash.Hash + copy(hash[:], chainHash[:]) + + // Generate other random fields + maxHtlc := MilliSatoshi(rapid.Uint64().Draw(t, "maxHtlc")) + + // If max HTLC flag is not set, we need to zero the value + if !includeMaxHtlc { + maxHtlc = 0 + } + + return &ChannelUpdate1{ + Signature: RandSignature(t), + ChainHash: hash, + ShortChannelID: RandShortChannelID(t), + Timestamp: uint32(rapid.IntRange(0, 0x7FFFFFFF).Draw( + t, "timestamp"), + ), + MessageFlags: msgFlags, + ChannelFlags: chanFlags, + TimeLockDelta: uint16(rapid.IntRange(0, 65535).Draw( + t, "timelockDelta"), + ), + HtlcMinimumMsat: MilliSatoshi(rapid.Uint64().Draw( + t, "htlcMinimum"), + ), + BaseFee: uint32(rapid.IntRange(0, 0x7FFFFFFF).Draw( + t, "baseFee"), + ), + FeeRate: uint32(rapid.IntRange(0, 0x7FFFFFFF).Draw( + t, "feeRate"), + ), + HtlcMaximumMsat: maxHtlc, + ExtraOpaqueData: RandExtraOpaqueData(t, nil), + } +} + +// A compile time check to ensure ChannelUpdate2 implements the +// lnwire.TestMessage interface. +var _ TestMessage = (*ChannelUpdate2)(nil) + +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (c *ChannelUpdate2) RandTestMessage(t *rapid.T) Message { + shortChanID := RandShortChannelID(t) + blockHeight := uint32(rapid.IntRange(0, 1000000).Draw(t, "blockHeight")) + + var disabledFlags ChanUpdateDisableFlags + if rapid.Bool().Draw(t, "disableIncoming") { + disabledFlags |= ChanUpdateDisableIncoming + } + if rapid.Bool().Draw(t, "disableOutgoing") { + disabledFlags |= ChanUpdateDisableOutgoing + } + + cltvExpiryDelta := uint16(rapid.IntRange(10, 200).Draw( + t, "cltvExpiryDelta"), + ) + + htlcMinMsat := MilliSatoshi(rapid.IntRange(1, 10000).Draw( + t, "htlcMinMsat"), + ) + htlcMaxMsat := MilliSatoshi(rapid.IntRange(10000, 100000000).Draw( + t, "htlcMaxMsat"), + ) + feeBaseMsat := uint32(rapid.IntRange(0, 10000).Draw(t, "feeBaseMsat")) + feeProportionalMillionths := uint32(rapid.IntRange(0, 10000).Draw( + t, "feeProportionalMillionths"), + ) + + chainHash := RandChainHash(t) + var chainHashObj chainhash.Hash + copy(chainHashObj[:], chainHash[:]) + + //nolint:ll + msg := &ChannelUpdate2{ + Signature: RandSignature(t), + ChainHash: tlv.NewPrimitiveRecord[tlv.TlvType0, chainhash.Hash]( + chainHashObj, + ), + ShortChannelID: tlv.NewRecordT[tlv.TlvType2, ShortChannelID]( + shortChanID, + ), + BlockHeight: tlv.NewPrimitiveRecord[tlv.TlvType4, uint32]( + blockHeight, + ), + DisabledFlags: tlv.NewPrimitiveRecord[tlv.TlvType6, ChanUpdateDisableFlags]( //nolint:ll + disabledFlags, + ), + CLTVExpiryDelta: tlv.NewPrimitiveRecord[tlv.TlvType10, uint16]( + cltvExpiryDelta, + ), + HTLCMinimumMsat: tlv.NewPrimitiveRecord[tlv.TlvType12, MilliSatoshi]( + htlcMinMsat, + ), + HTLCMaximumMsat: tlv.NewPrimitiveRecord[tlv.TlvType14, MilliSatoshi]( + htlcMaxMsat, + ), + FeeBaseMsat: tlv.NewPrimitiveRecord[tlv.TlvType16, uint32]( + feeBaseMsat, + ), + FeeProportionalMillionths: tlv.NewPrimitiveRecord[tlv.TlvType18, uint32]( + feeProportionalMillionths, + ), + ExtraOpaqueData: RandExtraOpaqueData(t, nil), + } + + msg.Signature.ForceSchnorr() + + if rapid.Bool().Draw(t, "isSecondPeer") { + msg.SecondPeer = tlv.SomeRecordT( + tlv.RecordT[tlv.TlvType8, TrueBoolean]{}, + ) + } + + return msg +} + +// A compile time check to ensure ClosingComplete implements the +// lnwire.TestMessage interface. +var _ TestMessage = (*ClosingComplete)(nil) + +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (c *ClosingComplete) RandTestMessage(t *rapid.T) Message { + msg := &ClosingComplete{ + ChannelID: RandChannelID(t), + FeeSatoshis: btcutil.Amount(rapid.Int64Range(0, 1000000).Draw( + t, "feeSatoshis"), + ), + LockTime: rapid.Uint32Range(0, 0xffffffff).Draw( + t, "lockTime", + ), + CloseeScript: RandDeliveryAddress(t), + CloserScript: RandDeliveryAddress(t), + ExtraData: RandExtraOpaqueData(t, nil), + } + + includeCloserNoClosee := rapid.Bool().Draw(t, "includeCloserNoClosee") + includeNoCloserClosee := rapid.Bool().Draw(t, "includeNoCloserClosee") + includeCloserAndClosee := rapid.Bool().Draw(t, "includeCloserAndClosee") + + // Ensure at least one signature is present. + if !includeCloserNoClosee && !includeNoCloserClosee && + !includeCloserAndClosee { + + // If all are false, enable at least one randomly. + choice := rapid.IntRange(0, 2).Draw(t, "sigChoice") + switch choice { + case 0: + includeCloserNoClosee = true + case 1: + includeNoCloserClosee = true + case 2: + includeCloserAndClosee = true + } + } + + if includeCloserNoClosee { + sig := RandSignature(t) + msg.CloserNoClosee = tlv.SomeRecordT( + tlv.NewRecordT[tlv.TlvType1, Sig](sig), + ) + } + + if includeNoCloserClosee { + sig := RandSignature(t) + msg.NoCloserClosee = tlv.SomeRecordT( + tlv.NewRecordT[tlv.TlvType2, Sig](sig), + ) + } + + if includeCloserAndClosee { + sig := RandSignature(t) + msg.CloserAndClosee = tlv.SomeRecordT( + tlv.NewRecordT[tlv.TlvType3, Sig](sig), + ) + } + + return msg +} + +// A compile time check to ensure ClosingSig implements the lnwire.TestMessage +// interface. +var _ TestMessage = (*ClosingSig)(nil) + +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (c *ClosingSig) RandTestMessage(t *rapid.T) Message { + msg := &ClosingSig{ + ChannelID: RandChannelID(t), + CloseeScript: RandDeliveryAddress(t), + CloserScript: RandDeliveryAddress(t), + ExtraData: RandExtraOpaqueData(t, nil), + } + + includeCloserNoClosee := rapid.Bool().Draw(t, "includeCloserNoClosee") + includeNoCloserClosee := rapid.Bool().Draw(t, "includeNoCloserClosee") + includeCloserAndClosee := rapid.Bool().Draw(t, "includeCloserAndClosee") + + // Ensure at least one signature is present. + if !includeCloserNoClosee && !includeNoCloserClosee && + !includeCloserAndClosee { + + // If all are false, enable at least one randomly. + choice := rapid.IntRange(0, 2).Draw(t, "sigChoice") + switch choice { + case 0: + includeCloserNoClosee = true + case 1: + includeNoCloserClosee = true + case 2: + includeCloserAndClosee = true + } + } + + if includeCloserNoClosee { + sig := RandSignature(t) + msg.CloserNoClosee = tlv.SomeRecordT( + tlv.NewRecordT[tlv.TlvType1, Sig](sig), + ) + } + + if includeNoCloserClosee { + sig := RandSignature(t) + msg.NoCloserClosee = tlv.SomeRecordT( + tlv.NewRecordT[tlv.TlvType2, Sig](sig), + ) + } + + if includeCloserAndClosee { + sig := RandSignature(t) + msg.CloserAndClosee = tlv.SomeRecordT( + tlv.NewRecordT[tlv.TlvType3, Sig](sig), + ) + } + + return msg +} + +// A compile time check to ensure ClosingSigned implements the +// lnwire.TestMessage interface. +var _ TestMessage = (*ClosingSigned)(nil) + +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (c *ClosingSigned) RandTestMessage(t *rapid.T) Message { + // Generate a random boolean to decide whether to include CommitSig or + // PartialSig Since they're mutually exclusive, when one is populated, + // the other must be blank. + usePartialSig := rapid.Bool().Draw(t, "usePartialSig") + + msg := &ClosingSigned{ + ChannelID: RandChannelID(t), + FeeSatoshis: btcutil.Amount( + rapid.Int64Range(0, 1000000).Draw(t, "feeSatoshis"), + ), + ExtraData: RandExtraOpaqueData(t, nil), + } + + if usePartialSig { + sigBytes := rapid.SliceOfN(rapid.Byte(), 32, 32).Draw( + t, "sigScalar", + ) + var s btcec.ModNScalar + _ = s.SetByteSlice(sigBytes) + + msg.PartialSig = SomePartialSig(NewPartialSig(s)) + msg.Signature = Sig{} + } else { + msg.Signature = RandSignature(t) + } + + return msg +} + +// A compile time check to ensure CommitSig implements the lnwire.TestMessage +// interface. +var _ TestMessage = (*CommitSig)(nil) + +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (c *CommitSig) RandTestMessage(t *rapid.T) Message { + cr, _ := RandCustomRecords(t, nil, true) + sig := &CommitSig{ + ChanID: RandChannelID(t), + CommitSig: RandSignature(t), + CustomRecords: cr, + } + + numHtlcSigs := rapid.IntRange(0, 20).Draw(t, "numHtlcSigs") + htlcSigs := make([]Sig, numHtlcSigs) + for i := 0; i < numHtlcSigs; i++ { + htlcSigs[i] = RandSignature(t) + } + + if len(htlcSigs) > 0 { + sig.HtlcSigs = htlcSigs + } + + includePartialSig := rapid.Bool().Draw(t, "includePartialSig") + if includePartialSig { + sigWithNonce := RandPartialSigWithNonce(t) + sig.PartialSig = MaybePartialSigWithNonce(sigWithNonce) + } + + return sig +} + +// A compile time check to ensure Custom implements the lnwire.TestMessage +// interface. +var _ TestMessage = (*Custom)(nil) + +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (c *Custom) RandTestMessage(t *rapid.T) Message { + msgType := MessageType( + rapid.IntRange(int(CustomTypeStart), 65535).Draw( + t, "customMsgType", + ), + ) + + dataLen := rapid.IntRange(0, 1000).Draw(t, "customDataLength") + data := rapid.SliceOfN(rapid.Byte(), dataLen, dataLen).Draw( + t, "customData", + ) + + msg, err := NewCustom(msgType, data) + if err != nil { + panic(fmt.Sprintf("Error creating custom message: %v", err)) + } + + return msg +} + +// A compile time check to ensure DynAck implements the lnwire.TestMessage +// interface. +var _ TestMessage = (*DynAck)(nil) + +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (da *DynAck) RandTestMessage(t *rapid.T) Message { + msg := &DynAck{ + ChanID: RandChannelID(t), + ExtraData: RandExtraOpaqueData(t, nil), + } + + includeLocalNonce := rapid.Bool().Draw(t, "includeLocalNonce") + + if includeLocalNonce { + msg.LocalNonce = fn.Some(RandMusig2Nonce(t)) + } + + return msg +} + +// A compile time check to ensure DynPropose implements the lnwire.TestMessage +// interface. +var _ TestMessage = (*DynPropose)(nil) + +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (dp *DynPropose) RandTestMessage(t *rapid.T) Message { + msg := &DynPropose{ + ChanID: RandChannelID(t), + Initiator: rapid.Bool().Draw(t, "initiator"), + ExtraData: RandExtraOpaqueData(t, nil), + } + + // Randomly decide which optional fields to include + includeDustLimit := rapid.Bool().Draw(t, "includeDustLimit") + includeMaxValueInFlight := rapid.Bool().Draw( + t, "includeMaxValueInFlight", + ) + includeChannelReserve := rapid.Bool().Draw(t, "includeChannelReserve") + includeCsvDelay := rapid.Bool().Draw(t, "includeCsvDelay") + includeMaxAcceptedHTLCs := rapid.Bool().Draw( + t, "includeMaxAcceptedHTLCs", + ) + includeFundingKey := rapid.Bool().Draw(t, "includeFundingKey") + includeChannelType := rapid.Bool().Draw(t, "includeChannelType") + includeKickoffFeerate := rapid.Bool().Draw(t, "includeKickoffFeerate") + + // Generate random values for each included field + if includeDustLimit { + dl := btcutil.Amount(rapid.Uint32().Draw(t, "dustLimit")) + msg.DustLimit = fn.Some(dl) + } + + if includeMaxValueInFlight { + mvif := MilliSatoshi(rapid.Uint64().Draw(t, "maxValueInFlight")) + msg.MaxValueInFlight = fn.Some(mvif) + } + + if includeChannelReserve { + cr := btcutil.Amount(rapid.Uint32().Draw(t, "channelReserve")) + msg.ChannelReserve = fn.Some(cr) + } + + if includeCsvDelay { + cd := rapid.Uint16().Draw(t, "csvDelay") + msg.CsvDelay = fn.Some(cd) + } + + if includeMaxAcceptedHTLCs { + mah := rapid.Uint16().Draw(t, "maxAcceptedHTLCs") + msg.MaxAcceptedHTLCs = fn.Some(mah) + } + + if includeFundingKey { + msg.FundingKey = fn.Some(*RandPubKey(t)) + } + + if includeChannelType { + msg.ChannelType = fn.Some(*RandChannelType(t)) + } + + if includeKickoffFeerate { + kf := chainfee.SatPerKWeight(rapid.Uint32().Draw( + t, "kickoffFeerate"), + ) + msg.KickoffFeerate = fn.Some(kf) + } + + return msg +} + +// A compile time check to ensure DynReject implements the lnwire.TestMessage +// interface. +var _ TestMessage = (*DynReject)(nil) + +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (dr *DynReject) RandTestMessage(t *rapid.T) Message { + featureVec := NewRawFeatureVector() + + numFeatures := rapid.IntRange(0, 8).Draw(t, "numRejections") + for i := 0; i < numFeatures; i++ { + bit := FeatureBit( + rapid.IntRange(0, 31).Draw( + t, fmt.Sprintf("rejectionBit-%d", i), + ), + ) + featureVec.Set(bit) + } + + var extraData ExtraOpaqueData + randData := RandExtraOpaqueData(t, nil) + if len(randData) > 0 { + extraData = randData + } + + return &DynReject{ + ChanID: RandChannelID(t), + UpdateRejections: *featureVec, + ExtraData: extraData, + } +} + +// A compile time check to ensure FundingCreated implements the TestMessage +// interface. +var _ TestMessage = (*FundingCreated)(nil) + +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (f *FundingCreated) RandTestMessage(t *rapid.T) Message { + var pendingChanID [32]byte + pendingChanIDBytes := rapid.SliceOfN(rapid.Byte(), 32, 32).Draw( + t, "pendingChanID", + ) + copy(pendingChanID[:], pendingChanIDBytes) + + includePartialSig := rapid.Bool().Draw(t, "includePartialSig") + var partialSig OptPartialSigWithNonceTLV + var commitSig Sig + + if includePartialSig { + sigWithNonce := RandPartialSigWithNonce(t) + partialSig = MaybePartialSigWithNonce(sigWithNonce) + + // When using partial sig, CommitSig should be empty/blank. + commitSig = Sig{} + } else { + commitSig = RandSignature(t) + } + + return &FundingCreated{ + PendingChannelID: pendingChanID, + FundingPoint: RandOutPoint(t), + CommitSig: commitSig, + PartialSig: partialSig, + ExtraData: RandExtraOpaqueData(t, nil), + } +} + +// A compile time check to ensure FundingSigned implements the +// lnwire.TestMessage interface. +var _ TestMessage = (*FundingSigned)(nil) + +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (f *FundingSigned) RandTestMessage(t *rapid.T) Message { + usePartialSig := rapid.Bool().Draw(t, "usePartialSig") + + msg := &FundingSigned{ + ChanID: RandChannelID(t), + ExtraData: RandExtraOpaqueData(t, nil), + } + + if usePartialSig { + sigWithNonce := RandPartialSigWithNonce(t) + msg.PartialSig = MaybePartialSigWithNonce(sigWithNonce) + + msg.CommitSig = Sig{} + } else { + msg.CommitSig = RandSignature(t) + } + + return msg +} + +// A compile time check to ensure GossipTimestampRange implements the +// lnwire.TestMessage interface. +var _ TestMessage = (*GossipTimestampRange)(nil) + +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (g *GossipTimestampRange) RandTestMessage(t *rapid.T) Message { + var chainHash chainhash.Hash + hashBytes := rapid.SliceOfN(rapid.Byte(), 32, 32).Draw(t, "chainHash") + copy(chainHash[:], hashBytes) + + msg := &GossipTimestampRange{ + ChainHash: chainHash, + FirstTimestamp: rapid.Uint32().Draw(t, "firstTimestamp"), + TimestampRange: rapid.Uint32().Draw(t, "timestampRange"), + ExtraData: RandExtraOpaqueData(t, nil), + } + + includeFirstBlockHeight := rapid.Bool().Draw( + t, "includeFirstBlockHeight", + ) + includeBlockRange := rapid.Bool().Draw(t, "includeBlockRange") + + if includeFirstBlockHeight { + height := rapid.Uint32().Draw(t, "firstBlockHeight") + msg.FirstBlockHeight = tlv.SomeRecordT( + tlv.RecordT[tlv.TlvType2, uint32]{Val: height}, + ) + } + + if includeBlockRange { + blockRange := rapid.Uint32().Draw(t, "blockRange") + msg.BlockRange = tlv.SomeRecordT( + tlv.RecordT[tlv.TlvType4, uint32]{Val: blockRange}, + ) + } + + return msg +} + +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (msg *Init) RandTestMessage(t *rapid.T) Message { + global := NewRawFeatureVector() + local := NewRawFeatureVector() + + numGlobalFeatures := rapid.IntRange(0, 20).Draw(t, "numGlobalFeatures") + for i := 0; i < numGlobalFeatures; i++ { + bit := FeatureBit( + rapid.IntRange(0, 100).Draw( + t, fmt.Sprintf("globalFeatureBit%d", i), + ), + ) + global.Set(bit) + } + + numLocalFeatures := rapid.IntRange(0, 20).Draw(t, "numLocalFeatures") + for i := 0; i < numLocalFeatures; i++ { + bit := FeatureBit( + rapid.IntRange(0, 100).Draw( + t, fmt.Sprintf("localFeatureBit%d", i), + ), + ) + local.Set(bit) + } + + return NewInitMessage(global, local) +} + +// A compile time check to ensure KickoffSig implements the lnwire.TestMessage +// interface. +var _ TestMessage = (*KickoffSig)(nil) + +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (ks *KickoffSig) RandTestMessage(t *rapid.T) Message { + return &KickoffSig{ + ChanID: RandChannelID(t), + Signature: RandSignature(t), + ExtraData: RandExtraOpaqueData(t, nil), + } +} + +// A compile time check to ensure NodeAnnouncement implements the +// lnwire.TestMessage interface. +var _ TestMessage = (*NodeAnnouncement)(nil) + +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (a *NodeAnnouncement) RandTestMessage(t *rapid.T) Message { + // Generate random compressed public key for node ID + pubKey := RandPubKey(t) + var nodeID [33]byte + copy(nodeID[:], pubKey.SerializeCompressed()) + + // Generate random RGB color + rgbColor := color.RGBA{ + R: uint8(rapid.IntRange(0, 255).Draw(t, "rgbR")), + G: uint8(rapid.IntRange(0, 255).Draw(t, "rgbG")), + B: uint8(rapid.IntRange(0, 255).Draw(t, "rgbB")), + } + + return &NodeAnnouncement{ + Signature: RandSignature(t), + Features: RandFeatureVector(t), + Timestamp: uint32(rapid.IntRange(0, 0x7FFFFFFF).Draw( + t, "timestamp"), + ), + NodeID: nodeID, + RGBColor: rgbColor, + Alias: RandNodeAlias(t), + Addresses: RandNetAddrs(t), + ExtraOpaqueData: RandExtraOpaqueData(t, nil), + } +} + +// A compile time check to ensure OpenChannel implements the TestMessage +// interface. +var _ TestMessage = (*OpenChannel)(nil) + +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (o *OpenChannel) RandTestMessage(t *rapid.T) Message { + chainHash := RandChainHash(t) + var hash chainhash.Hash + copy(hash[:], chainHash[:]) + + var pendingChanID [32]byte + pendingChanIDBytes := rapid.SliceOfN(rapid.Byte(), 32, 32).Draw( + t, "pendingChanID", + ) + copy(pendingChanID[:], pendingChanIDBytes) + + includeChannelType := rapid.Bool().Draw(t, "includeChannelType") + includeLeaseExpiry := rapid.Bool().Draw(t, "includeLeaseExpiry") + includeLocalNonce := rapid.Bool().Draw(t, "includeLocalNonce") + + var channelFlags FundingFlag + if rapid.Bool().Draw(t, "announceChannel") { + channelFlags |= FFAnnounceChannel + } + + var localNonce OptMusig2NonceTLV + if includeLocalNonce { + nonce := RandMusig2Nonce(t) + localNonce = tlv.SomeRecordT( + tlv.NewRecordT[NonceRecordTypeT, Musig2Nonce](nonce), + ) + } + + var channelType *ChannelType + if includeChannelType { + channelType = RandChannelType(t) + } + + var leaseExpiry *LeaseExpiry + if includeLeaseExpiry { + leaseExpiry = RandLeaseExpiry(t) + } + + return &OpenChannel{ + ChainHash: hash, + PendingChannelID: pendingChanID, + FundingAmount: btcutil.Amount( + rapid.IntRange(5000, 10000000).Draw(t, "fundingAmount"), + ), + PushAmount: MilliSatoshi( + rapid.IntRange(0, 1000000).Draw(t, "pushAmount"), + ), + DustLimit: btcutil.Amount( + rapid.IntRange(100, 1000).Draw(t, "dustLimit"), + ), + MaxValueInFlight: MilliSatoshi( + rapid.IntRange(10000, 1000000).Draw( + t, "maxValueInFlight", + ), + ), + ChannelReserve: btcutil.Amount( + rapid.IntRange(1000, 10000).Draw(t, "channelReserve"), + ), + HtlcMinimum: MilliSatoshi( + rapid.IntRange(1, 1000).Draw(t, "htlcMinimum"), + ), + FeePerKiloWeight: uint32( + rapid.IntRange(250, 10000).Draw(t, "feePerKw"), + ), + CsvDelay: uint16( + rapid.IntRange(144, 1000).Draw(t, "csvDelay"), + ), + MaxAcceptedHTLCs: uint16( + rapid.IntRange(10, 500).Draw(t, "maxAcceptedHTLCs"), + ), + FundingKey: RandPubKey(t), + RevocationPoint: RandPubKey(t), + PaymentPoint: RandPubKey(t), + DelayedPaymentPoint: RandPubKey(t), + HtlcPoint: RandPubKey(t), + FirstCommitmentPoint: RandPubKey(t), + ChannelFlags: channelFlags, + UpfrontShutdownScript: RandDeliveryAddress(t), + ChannelType: channelType, + LeaseExpiry: leaseExpiry, + LocalNonce: localNonce, + ExtraData: RandExtraOpaqueData(t, nil), + } +} + +// A compile time check to ensure Ping implements the lnwire.TestMessage +// interface. +var _ TestMessage = (*Ping)(nil) + +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (p *Ping) RandTestMessage(t *rapid.T) Message { + numPongBytes := uint16(rapid.IntRange(0, int(MaxPongBytes)).Draw( + t, "numPongBytes"), + ) + + // Generate padding bytes (but keeping within allowed message size) + // MaxMsgBody - 2 (for NumPongBytes) - 2 (for padding length) + maxPaddingLen := MaxMsgBody - 4 + paddingLen := rapid.IntRange(0, maxPaddingLen).Draw( + t, "paddingLen", + ) + padding := make(PingPayload, paddingLen) + + // Fill padding with random bytes + for i := 0; i < paddingLen; i++ { + padding[i] = byte(rapid.IntRange(0, 255).Draw( + t, fmt.Sprintf("paddingByte%d", i)), + ) + } + + return &Ping{ + NumPongBytes: numPongBytes, + PaddingBytes: padding, + } +} + +// A compile time check to ensure Pong implements the lnwire.TestMessage +// interface. +var _ TestMessage = (*Pong)(nil) + +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (p *Pong) RandTestMessage(t *rapid.T) Message { + payloadLen := rapid.IntRange(0, 1000).Draw(t, "pongPayloadLength") + payload := rapid.SliceOfN(rapid.Byte(), payloadLen, payloadLen).Draw( + t, "pongPayload", + ) + + return &Pong{ + PongBytes: payload, + } +} + +// A compile time check to ensure QueryChannelRange implements the +// lnwire.TestMessage interface. +var _ TestMessage = (*QueryChannelRange)(nil) + +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (q *QueryChannelRange) RandTestMessage(t *rapid.T) Message { + msg := &QueryChannelRange{ + FirstBlockHeight: uint32(rapid.IntRange(0, 1000000).Draw( + t, "firstBlockHeight"), + ), + NumBlocks: uint32(rapid.IntRange(1, 10000).Draw( + t, "numBlocks"), + ), + ExtraData: RandExtraOpaqueData(t, nil), + } + + // Generate chain hash + chainHash := RandChainHash(t) + var chainHashObj chainhash.Hash + copy(chainHashObj[:], chainHash[:]) + msg.ChainHash = chainHashObj + + // Randomly include QueryOptions + if rapid.Bool().Draw(t, "includeQueryOptions") { + queryOptions := &QueryOptions{} + *queryOptions = QueryOptions(*RandFeatureVector(t)) + msg.QueryOptions = queryOptions + } + + return msg +} + +// A compile time check to ensure QueryShortChanIDs implements the +// lnwire.TestMessage interface. +var _ TestMessage = (*QueryShortChanIDs)(nil) + +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (q *QueryShortChanIDs) RandTestMessage(t *rapid.T) Message { + var chainHash chainhash.Hash + hashBytes := rapid.SliceOfN(rapid.Byte(), 32, 32).Draw(t, "chainHash") + copy(chainHash[:], hashBytes) + + encodingType := EncodingSortedPlain + if rapid.Bool().Draw(t, "useZlibEncoding") { + encodingType = EncodingSortedZlib + } + + msg := &QueryShortChanIDs{ + ChainHash: chainHash, + EncodingType: encodingType, + ExtraData: RandExtraOpaqueData(t, nil), + noSort: false, + } + + numIDs := rapid.IntRange(2, 20).Draw(t, "numShortChanIDs") + + // Generate sorted short channel IDs. + shortChanIDs := make([]ShortChannelID, numIDs) + for i := 0; i < numIDs; i++ { + shortChanIDs[i] = RandShortChannelID(t) + + // Ensure they're properly sorted. + if i > 0 && shortChanIDs[i].ToUint64() <= + shortChanIDs[i-1].ToUint64() { + + // Ensure this ID is larger than the previous one. + shortChanIDs[i] = NewShortChanIDFromInt( + shortChanIDs[i-1].ToUint64() + 1, + ) + } + } + + msg.ShortChanIDs = shortChanIDs + + return msg +} + +// A compile time check to ensure ReplyChannelRange implements the +// lnwire.TestMessage interface. +var _ TestMessage = (*ReplyChannelRange)(nil) + +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (c *ReplyChannelRange) RandTestMessage(t *rapid.T) Message { + msg := &ReplyChannelRange{ + FirstBlockHeight: uint32(rapid.IntRange(0, 1000000).Draw( + t, "firstBlockHeight"), + ), + NumBlocks: uint32(rapid.IntRange(1, 10000).Draw( + t, "numBlocks"), + ), + Complete: uint8(rapid.IntRange(0, 1).Draw(t, "complete")), + EncodingType: QueryEncoding( + rapid.IntRange(0, 1).Draw(t, "encodingType"), + ), + ExtraData: RandExtraOpaqueData(t, nil), + } + + msg.ChainHash = RandChainHash(t) + + numShortChanIDs := rapid.IntRange(0, 20).Draw(t, "numShortChanIDs") + if numShortChanIDs == 0 { + return msg + } + + scidSet := fn.NewSet[ShortChannelID]() + scids := make([]ShortChannelID, numShortChanIDs) + for i := 0; i < numShortChanIDs; i++ { + scid := RandShortChannelID(t) + for scidSet.Contains(scid) { + scid = RandShortChannelID(t) + } + + scids[i] = scid + + scidSet.Add(scid) + } + + // Make sure there're no duplicates. + msg.ShortChanIDs = scids + + if rapid.Bool().Draw(t, "includeTimestamps") && numShortChanIDs > 0 { + msg.Timestamps = make(Timestamps, numShortChanIDs) + for i := 0; i < numShortChanIDs; i++ { + msg.Timestamps[i] = ChanUpdateTimestamps{ + Timestamp1: uint32(rapid.IntRange(0, math.MaxInt32).Draw(t, fmt.Sprintf("timestamp-1-%d", i))), //nolint:ll + Timestamp2: uint32(rapid.IntRange(0, math.MaxInt32).Draw(t, fmt.Sprintf("timestamp-2-%d", i))), //nolint:ll + } + } + } + + return msg +} + +// A compile time check to ensure ReplyShortChanIDsEnd implements the +// lnwire.TestMessage interface. +var _ TestMessage = (*ReplyShortChanIDsEnd)(nil) + +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (c *ReplyShortChanIDsEnd) RandTestMessage(t *rapid.T) Message { + var chainHash chainhash.Hash + hashBytes := rapid.SliceOfN(rapid.Byte(), 32, 32).Draw(t, "chainHash") + copy(chainHash[:], hashBytes) + + complete := uint8(rapid.IntRange(0, 1).Draw(t, "complete")) + + return &ReplyShortChanIDsEnd{ + ChainHash: chainHash, + Complete: complete, + ExtraData: RandExtraOpaqueData(t, nil), + } +} + +// RandTestMessage returns a RevokeAndAck message populated with random data. +// +// This is part of the TestMessage interface. +func (c *RevokeAndAck) RandTestMessage(t *rapid.T) Message { + msg := NewRevokeAndAck() + + var chanID ChannelID + bytes := rapid.SliceOfN(rapid.Byte(), 32, 32).Draw(t, "channelID") + copy(chanID[:], bytes) + msg.ChanID = chanID + + revBytes := rapid.SliceOfN(rapid.Byte(), 32, 32).Draw(t, "revocation") + copy(msg.Revocation[:], revBytes) + + msg.NextRevocationKey = RandPubKey(t) + + if rapid.Bool().Draw(t, "includeLocalNonce") { + var nonce Musig2Nonce + nonceBytes := rapid.SliceOfN(rapid.Byte(), 32, 32).Draw( + t, "nonce", + ) + copy(nonce[:], nonceBytes) + + msg.LocalNonce = tlv.SomeRecordT( + tlv.NewRecordT[NonceRecordTypeT, Musig2Nonce](nonce), + ) + } + + return msg +} + +// A compile-time check to ensure Shutdown implements the lnwire.TestMessage +// interface. +var _ TestMessage = (*Shutdown)(nil) + +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (s *Shutdown) RandTestMessage(t *rapid.T) Message { + // Generate random delivery address + // First decide the address type (P2PKH, P2SH, P2WPKH, P2WSH, P2TR) + addrType := rapid.IntRange(0, 4).Draw(t, "addrType") + + // Generate random address length based on type + var addrLen int + switch addrType { + // P2PKH + case 0: + addrLen = 25 + // P2SH + case 1: + addrLen = 23 + // P2WPKH + case 2: + addrLen = 22 + // P2WSH + case 3: + addrLen = 34 + // P2TR + case 4: + addrLen = 34 + } + + addr := rapid.SliceOfN(rapid.Byte(), addrLen, addrLen).Draw( + t, "address", + ) + + // Randomly decide whether to include a shutdown nonce + includeNonce := rapid.Bool().Draw(t, "includeNonce") + var shutdownNonce ShutdownNonceTLV + + if includeNonce { + shutdownNonce = SomeShutdownNonce(RandMusig2Nonce(t)) + } + + cr, _ := RandCustomRecords(t, nil, true) + + return &Shutdown{ + ChannelID: RandChannelID(t), + Address: addr, + ShutdownNonce: shutdownNonce, + CustomRecords: cr, + } +} + +// A compile time check to ensure Stfu implements the lnwire.TestMessage +// interface. +var _ TestMessage = (*Stfu)(nil) + +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (s *Stfu) RandTestMessage(t *rapid.T) Message { + m := &Stfu{ + ChanID: RandChannelID(t), + Initiator: rapid.Bool().Draw(t, "initiator"), + } + + extraData := RandExtraOpaqueData(t, nil) + if len(extraData) > 0 { + m.ExtraData = extraData + } + + return m +} + +// A compile time check to ensure UpdateAddHTLC implements the +// lnwire.TestMessage interface. +var _ TestMessage = (*UpdateAddHTLC)(nil) + +// RandTestMessage returns an UpdateAddHTLC message populated with random data. +// +// This is part of the TestMessage interface. +func (c *UpdateAddHTLC) RandTestMessage(t *rapid.T) Message { + msg := &UpdateAddHTLC{ + ChanID: RandChannelID(t), + ID: rapid.Uint64().Draw(t, "id"), + Amount: MilliSatoshi(rapid.Uint64().Draw(t, "amount")), + Expiry: rapid.Uint32().Draw(t, "expiry"), + } + + hashBytes := rapid.SliceOfN(rapid.Byte(), 32, 32).Draw(t, "paymentHash") + copy(msg.PaymentHash[:], hashBytes) + + onionBytes := rapid.SliceOfN( + rapid.Byte(), OnionPacketSize, OnionPacketSize, + ).Draw(t, "onionBlob") + copy(msg.OnionBlob[:], onionBytes) + + numRecords := rapid.IntRange(0, 5).Draw(t, "numRecords") + if numRecords > 0 { + msg.CustomRecords, _ = RandCustomRecords(t, nil, true) + } + + // 50/50 chance to add a blinding point + if rapid.Bool().Draw(t, "includeBlindingPoint") { + pubKey := RandPubKey(t) + + msg.BlindingPoint = tlv.SomeRecordT( + tlv.NewPrimitiveRecord[BlindingPointTlvType](pubKey), + ) + } + + return msg +} + +// A compile time check to ensure UpdateFailHTLC implements the TestMessage +// interface. +var _ TestMessage = (*UpdateFailHTLC)(nil) + +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (c *UpdateFailHTLC) RandTestMessage(t *rapid.T) Message { + return &UpdateFailHTLC{ + ChanID: RandChannelID(t), + ID: rapid.Uint64().Draw(t, "id"), + Reason: RandOpaqueReason(t), + ExtraData: RandExtraOpaqueData(t, nil), + } +} + +// A compile time check to ensure UpdateFailMalformedHTLC implements the +// TestMessage interface. +var _ TestMessage = (*UpdateFailMalformedHTLC)(nil) + +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (c *UpdateFailMalformedHTLC) RandTestMessage(t *rapid.T) Message { + return &UpdateFailMalformedHTLC{ + ChanID: RandChannelID(t), + ID: rapid.Uint64().Draw(t, "id"), + ShaOnionBlob: RandSHA256Hash(t), + FailureCode: RandFailCode(t), + ExtraData: RandExtraOpaqueData(t, nil), + } +} + +// A compile time check to ensure UpdateFee implements the TestMessage +// interface. +var _ TestMessage = (*UpdateFee)(nil) + +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (c *UpdateFee) RandTestMessage(t *rapid.T) Message { + return &UpdateFee{ + ChanID: RandChannelID(t), + FeePerKw: uint32(rapid.IntRange(1, 10000).Draw(t, "feePerKw")), + ExtraData: RandExtraOpaqueData(t, nil), + } +} + +// A compile time check to ensure UpdateFulfillHTLC implements the TestMessage +// interface. +var _ TestMessage = (*UpdateFulfillHTLC)(nil) + +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (c *UpdateFulfillHTLC) RandTestMessage(t *rapid.T) Message { + msg := &UpdateFulfillHTLC{ + ChanID: RandChannelID(t), + ID: rapid.Uint64().Draw(t, "id"), + PaymentPreimage: RandPaymentPreimage(t), + } + + cr, ignoreRecords := RandCustomRecords(t, nil, true) + msg.CustomRecords = cr + + randData := RandExtraOpaqueData(t, ignoreRecords) + if len(randData) > 0 { + msg.ExtraData = randData + } + + return msg +} + +// A compile time check to ensure Warning implements the lnwire.TestMessage +// interface. +var _ TestMessage = (*Warning)(nil) + +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (c *Warning) RandTestMessage(t *rapid.T) Message { + msg := &Warning{ + ChanID: RandChannelID(t), + } + + useASCII := rapid.Bool().Draw(t, "useASCII") + if useASCII { + length := rapid.IntRange(1, 100).Draw(t, "warningDataLength") + data := make([]byte, length) + for i := 0; i < length; i++ { + data[i] = byte( + rapid.IntRange(32, 126).Draw( + t, fmt.Sprintf("warningDataByte-%d", i), + ), + ) + } + msg.Data = data + } else { + length := rapid.IntRange(1, 100).Draw(t, "warningDataLength") + msg.Data = rapid.SliceOfN(rapid.Byte(), length, length).Draw( + t, "warningData", + ) + } + + return msg +} + +// A compile time check to ensure Error implements the lnwire.TestMessage +// interface. +var _ TestMessage = (*Error)(nil) + +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (c *Error) RandTestMessage(t *rapid.T) Message { + msg := &Error{ + ChanID: RandChannelID(t), + } + + useASCII := rapid.Bool().Draw(t, "useASCII") + if useASCII { + length := rapid.IntRange(1, 100).Draw(t, "errorDataLength") + data := make([]byte, length) + for i := 0; i < length; i++ { + data[i] = byte( + rapid.IntRange(32, 126).Draw( + t, fmt.Sprintf("errorDataByte-%d", i), + ), + ) + } + msg.Data = data + } else { + // Generate random binary data + length := rapid.IntRange(1, 100).Draw(t, "errorDataLength") + msg.Data = rapid.SliceOfN( + rapid.Byte(), length, length, + ).Draw(t, "errorData") + } + + return msg +} diff --git a/lnwire/test_utils.go b/lnwire/test_utils.go new file mode 100644 index 000000000..1065cbacf --- /dev/null +++ b/lnwire/test_utils.go @@ -0,0 +1,360 @@ +package lnwire + +import ( + "crypto/sha256" + "fmt" + "net" + + "github.com/btcsuite/btcd/btcec/v2" + "github.com/btcsuite/btcd/btcec/v2/ecdsa" + "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcd/wire" + "github.com/lightningnetwork/lnd/fn/v2" + "github.com/stretchr/testify/require" + "pgregory.net/rapid" +) + +// RandChannelUpdate generates a random ChannelUpdate message using rapid's +// generators. +func RandPartialSig(t *rapid.T) *PartialSig { + // Generate random private key bytes + sigBytes := rapid.SliceOfN(rapid.Byte(), 32, 32).Draw(t, "privKeyBytes") + + var s btcec.ModNScalar + s.SetByteSlice(sigBytes) + + return &PartialSig{ + Sig: s, + } +} + +// RandPartialSigWithNonce generates a random PartialSigWithNonce using rapid +// generators. +func RandPartialSigWithNonce(t *rapid.T) *PartialSigWithNonce { + sigLen := rapid.IntRange(1, 65).Draw(t, "partialSigLen") + sigBytes := rapid.SliceOfN( + rapid.Byte(), sigLen, sigLen, + ).Draw(t, "partialSig") + + sigScalar := new(btcec.ModNScalar) + sigScalar.SetByteSlice(sigBytes) + + return NewPartialSigWithNonce( + RandMusig2Nonce(t), *sigScalar, + ) +} + +// RandPubKey generates a random public key using rapid's generators. +func RandPubKey(t *rapid.T) *btcec.PublicKey { + privKeyBytes := rapid.SliceOfN(rapid.Byte(), 32, 32).Draw( + t, "privKeyBytes", + ) + _, pub := btcec.PrivKeyFromBytes(privKeyBytes) + + return pub +} + +// RandChannelID generates a random channel ID. +func RandChannelID(t *rapid.T) ChannelID { + var c ChannelID + bytes := rapid.SliceOfN(rapid.Byte(), 32, 32).Draw(t, "channelID") + copy(c[:], bytes) + + return c +} + +// RandShortChannelID generates a random short channel ID. +func RandShortChannelID(t *rapid.T) ShortChannelID { + return NewShortChanIDFromInt( + uint64(rapid.IntRange(1, 100000).Draw(t, "shortChanID")), + ) +} + +// RandFeatureVector generates a random feature vector. +func RandFeatureVector(t *rapid.T) *RawFeatureVector { + featureVec := NewRawFeatureVector() + + // Add a random number of random feature bits + numFeatures := rapid.IntRange(0, 20).Draw(t, "numFeatures") + for i := 0; i < numFeatures; i++ { + bit := FeatureBit(rapid.IntRange(0, 100).Draw( + t, fmt.Sprintf("featureBit-%d", i)), + ) + featureVec.Set(bit) + } + + return featureVec +} + +// RandSignature generates a signature for testing. +func RandSignature(t *rapid.T) Sig { + testRScalar := new(btcec.ModNScalar) + testSScalar := new(btcec.ModNScalar) + + // Generate random bytes for R and S + rBytes := rapid.SliceOfN(rapid.Byte(), 32, 32).Draw(t, "rBytes") + sBytes := rapid.SliceOfN(rapid.Byte(), 32, 32).Draw(t, "sBytes") + _ = testRScalar.SetByteSlice(rBytes) + _ = testSScalar.SetByteSlice(sBytes) + + testSig := ecdsa.NewSignature(testRScalar, testSScalar) + + sig, err := NewSigFromSignature(testSig) + if err != nil { + panic(fmt.Sprintf("unable to create signature: %v", err)) + } + + return sig +} + +// RandPaymentHash generates a random payment hash. +func RandPaymentHash(t *rapid.T) [32]byte { + var hash [32]byte + bytes := rapid.SliceOfN(rapid.Byte(), 32, 32).Draw(t, "paymentHash") + copy(hash[:], bytes) + + return hash +} + +// RandPaymentPreimage generates a random payment preimage. +func RandPaymentPreimage(t *rapid.T) [32]byte { + var preimage [32]byte + bytes := rapid.SliceOfN(rapid.Byte(), 32, 32).Draw(t, "preimage") + copy(preimage[:], bytes) + + return preimage +} + +// RandChainHash generates a random chain hash. +func RandChainHash(t *rapid.T) chainhash.Hash { + var hash [32]byte + bytes := rapid.SliceOfN(rapid.Byte(), 32, 32).Draw(t, "chainHash") + copy(hash[:], bytes) + + return hash +} + +// RandNodeAlias generates a random node alias. +func RandNodeAlias(t *rapid.T) NodeAlias { + var alias NodeAlias + aliasLength := rapid.IntRange(0, 32).Draw(t, "aliasLength") + + aliasBytes := rapid.StringN( + 0, aliasLength, aliasLength, + ).Draw(t, "alias") + + copy(alias[:], aliasBytes) + + return alias +} + +// RandNetAddrs generates random network addresses. +func RandNetAddrs(t *rapid.T) []net.Addr { + numAddresses := rapid.IntRange(0, 5).Draw(t, "numAddresses") + if numAddresses == 0 { + return nil + } + + addresses := make([]net.Addr, numAddresses) + for i := 0; i < numAddresses; i++ { + addressType := rapid.IntRange(0, 1).Draw( + t, fmt.Sprintf("addressType-%d", i), + ) + + switch addressType { + // IPv4. + case 0: + ipBytes := rapid.SliceOfN(rapid.Byte(), 4, 4).Draw( + t, fmt.Sprintf("ipv4-%d", i), + ) + port := rapid.IntRange(1, 65535).Draw( + t, fmt.Sprintf("port-%d", i), + ) + addresses[i] = &net.TCPAddr{ + IP: ipBytes, + Port: port, + } + + // IPv6. + case 1: + ipBytes := rapid.SliceOfN(rapid.Byte(), 16, 16).Draw( + t, fmt.Sprintf("ipv6-%d", i), + ) + port := rapid.IntRange(1, 65535).Draw( + t, fmt.Sprintf("port-%d", i), + ) + addresses[i] = &net.TCPAddr{ + IP: ipBytes, + Port: port, + } + } + } + + return addresses +} + +// RandCustomRecords generates random custom TLV records. +func RandCustomRecords(t *rapid.T, + ignoreRecords fn.Set[uint64], + custom bool) (CustomRecords, fn.Set[uint64]) { + + numRecords := rapid.IntRange(0, 5).Draw(t, "numCustomRecords") + customRecords := make(CustomRecords) + + if numRecords == 0 { + return nil, nil + } + + rangeStart := 0 + rangeStop := int(CustomTypeStart) + if custom { + rangeStart = 70_000 + rangeStop = 100_000 + } + + ignoreSet := fn.NewSet[uint64]() + for i := 0; i < numRecords; i++ { + recordType := uint64( + rapid.IntRange(rangeStart, rangeStop). + Filter(func(i int) bool { + return !ignoreRecords.Contains( + uint64(i), + ) + }). + Draw( + t, fmt.Sprintf("recordType-%d", i), + ), + ) + recordLen := rapid.IntRange(4, 64).Draw( + t, fmt.Sprintf("recordLen-%d", i), + ) + record := rapid.SliceOfN( + rapid.Byte(), recordLen, recordLen, + ).Draw(t, fmt.Sprintf("record-%d", i)) + + customRecords[recordType] = record + + ignoreSet.Add(recordType) + } + + return customRecords, ignoreSet +} + +// RandMusig2Nonce generates a random musig2 nonce. +func RandMusig2Nonce(t *rapid.T) Musig2Nonce { + var nonce Musig2Nonce + bytes := rapid.SliceOfN(rapid.Byte(), 32, 32).Draw(t, "nonce") + copy(nonce[:], bytes) + + return nonce +} + +// RandExtraOpaqueData generates random extra opaque data. +func RandExtraOpaqueData(t *rapid.T, + ignoreRecords fn.Set[uint64]) ExtraOpaqueData { + + // Make some random records. + cRecords, _ := RandCustomRecords(t, ignoreRecords, false) + if cRecords == nil { + return ExtraOpaqueData{} + } + + // Encode those records as opaque data. + recordBytes, err := cRecords.Serialize() + require.NoError(t, err) + + return ExtraOpaqueData(recordBytes) +} + +// RandOpaqueReason generates a random opaque reason for HTLC failures. +func RandOpaqueReason(t *rapid.T) OpaqueReason { + reasonLen := rapid.IntRange(32, 300).Draw(t, "reasonLen") + return rapid.SliceOfN(rapid.Byte(), reasonLen, reasonLen).Draw( + t, "opaqueReason", + ) +} + +// RandFailCode generates a random HTLC failure code. +func RandFailCode(t *rapid.T) FailCode { + // List of known failure codes to choose from Using only the documented + // codes. + validCodes := []FailCode{ + CodeInvalidRealm, + CodeTemporaryNodeFailure, + CodePermanentNodeFailure, + CodeRequiredNodeFeatureMissing, + CodePermanentChannelFailure, + CodeRequiredChannelFeatureMissing, + CodeUnknownNextPeer, + CodeIncorrectOrUnknownPaymentDetails, + CodeIncorrectPaymentAmount, + CodeFinalExpiryTooSoon, + CodeInvalidOnionVersion, + CodeInvalidOnionHmac, + CodeInvalidOnionKey, + CodeTemporaryChannelFailure, + CodeChannelDisabled, + CodeExpiryTooSoon, + CodeMPPTimeout, + CodeInvalidOnionPayload, + CodeFeeInsufficient, + } + + // Choose a random code from the list. + idx := rapid.IntRange(0, len(validCodes)-1).Draw(t, "failCodeIndex") + + return validCodes[idx] +} + +// RandSHA256Hash generates a random SHA256 hash. +func RandSHA256Hash(t *rapid.T) [sha256.Size]byte { + var hash [sha256.Size]byte + bytes := rapid.SliceOfN(rapid.Byte(), sha256.Size, sha256.Size).Draw( + t, "sha256Hash", + ) + copy(hash[:], bytes) + + return hash +} + +// RandDeliveryAddress generates a random delivery address (script). +func RandDeliveryAddress(t *rapid.T) DeliveryAddress { + addrLen := rapid.IntRange(1, 34).Draw(t, "addrLen") + + return rapid.SliceOfN(rapid.Byte(), addrLen, addrLen).Draw( + t, "deliveryAddress", + ) +} + +// RandChannelType generates a random channel type. +func RandChannelType(t *rapid.T) *ChannelType { + vec := RandFeatureVector(t) + chanType := ChannelType(*vec) + + return &chanType +} + +// RandLeaseExpiry generates a random lease expiry. +func RandLeaseExpiry(t *rapid.T) *LeaseExpiry { + exp := LeaseExpiry( + uint32(rapid.IntRange(1000, 1000000).Draw(t, "leaseExpiry")), + ) + + return &exp +} + +// RandOutPoint generates a random transaction outpoint. +func RandOutPoint(t *rapid.T) wire.OutPoint { + // Generate a random transaction ID + var txid chainhash.Hash + txidBytes := rapid.SliceOfN(rapid.Byte(), 32, 32).Draw(t, "txid") + copy(txid[:], txidBytes) + + // Generate a random output index + vout := uint32(rapid.IntRange(0, 10).Draw(t, "vout")) + + return wire.OutPoint{ + Hash: txid, + Index: vout, + } +} diff --git a/lnwire/update_add_htlc.go b/lnwire/update_add_htlc.go index 7976a13c5..e627dbf4e 100644 --- a/lnwire/update_add_htlc.go +++ b/lnwire/update_add_htlc.go @@ -110,10 +110,6 @@ func NewUpdateAddHTLC() *UpdateAddHTLC { // interface. var _ Message = (*UpdateAddHTLC)(nil) -// A compile time check to ensure UpdateAddHTLC implements the lnwire.SizeableMessage -// interface. -var _ SizeableMessage = (*UpdateAddHTLC)(nil) - // Decode deserializes a serialized UpdateAddHTLC message stored in the passed // io.Reader observing the specified protocol version. // @@ -223,3 +219,7 @@ func (c *UpdateAddHTLC) TargetChanID() ChannelID { func (c *UpdateAddHTLC) SerializedSize() (uint32, error) { return MessageSerializedSize(c) } + +// A compile time check to ensure UpdateAddHTLC implements the +// lnwire.SizeableMessage interface. +var _ SizeableMessage = (*UpdateAddHTLC)(nil) diff --git a/lnwire/update_fail_htlc.go b/lnwire/update_fail_htlc.go index 397c70084..1d26444ba 100644 --- a/lnwire/update_fail_htlc.go +++ b/lnwire/update_fail_htlc.go @@ -38,8 +38,8 @@ type UpdateFailHTLC struct { // interface. var _ Message = (*UpdateFailHTLC)(nil) -// A compile time check to ensure UpdateFailHTLC implements the lnwire.SizeableMessage -// interface. +// A compile time check to ensure UpdateFailHTLC implements the +// lnwire.SizeableMessage interface. var _ SizeableMessage = (*UpdateFailHTLC)(nil) // Decode deserializes a serialized UpdateFailHTLC message stored in the passed @@ -55,8 +55,8 @@ func (c *UpdateFailHTLC) Decode(r io.Reader, pver uint32) error { ) } -// Encode serializes the target UpdateFailHTLC into the passed io.Writer observing -// the protocol version specified. +// Encode serializes the target UpdateFailHTLC into the passed io.Writer +// observing the protocol version specified. // // This is part of the lnwire.Message interface. func (c *UpdateFailHTLC) Encode(w *bytes.Buffer, pver uint32) error {