123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952 |
- package lnwire
- import (
- "bytes"
- "compress/zlib"
- "encoding/binary"
- "reflect"
- "testing"
- "github.com/stretchr/testify/require"
- )
- // prefixWithMsgType takes []byte and adds a wire protocol prefix
- // to make the []byte into an actual message to be used in fuzzing.
- func prefixWithMsgType(data []byte, prefix MessageType) []byte {
- var prefixBytes [2]byte
- binary.BigEndian.PutUint16(prefixBytes[:], uint16(prefix))
- data = append(prefixBytes[:], data...)
- return data
- }
- // harness performs the actual fuzz testing of the appropriate wire message.
- // This function will check that the passed-in message passes wire length
- // checks, is a valid message once deserialized, and passes a sequence of
- // serialization and deserialization checks.
- func harness(t *testing.T, data []byte) {
- t.Helper()
- // Create a reader with the byte array.
- r := bytes.NewReader(data)
- // Check that the created message is not greater than the maximum
- // message size.
- if len(data) > MaxSliceLength {
- return
- }
- msg, err := ReadMessage(r, 0)
- if err != nil {
- return
- }
- // We will serialize the message into a new bytes buffer.
- var b bytes.Buffer
- _, err = WriteMessage(&b, msg, 0)
- require.NoError(t, err)
- // Deserialize the message from the serialized bytes buffer, and then
- // assert that the original message is equal to the newly deserialized
- // message.
- newMsg, err := ReadMessage(&b, 0)
- require.NoError(t, err)
- require.Equal(t, msg, newMsg)
- }
- func FuzzAcceptChannel(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- data = prefixWithMsgType(data, MsgAcceptChannel)
- // Create a reader with the byte array.
- r := bytes.NewReader(data)
- // Make sure byte array length (excluding 2 bytes for message
- // type) is less than max payload size for the wire message.
- payloadLen := uint32(len(data)) - 2
- if payloadLen > MaxMsgBody {
- return
- }
- msg, err := ReadMessage(r, 0)
- if err != nil {
- return
- }
- // We will serialize the message into a new bytes buffer.
- var b bytes.Buffer
- _, err = WriteMessage(&b, msg, 0)
- require.NoError(t, err)
- // Deserialize the message from the serialized bytes buffer, and
- // then assert that the original message is equal to the newly
- // deserialized message.
- newMsg, err := ReadMessage(&b, 0)
- require.NoError(t, err)
- require.IsType(t, &AcceptChannel{}, msg)
- first, _ := msg.(*AcceptChannel)
- require.IsType(t, &AcceptChannel{}, newMsg)
- second, _ := newMsg.(*AcceptChannel)
- // We can't use require.Equal for UpfrontShutdownScript, since
- // we consider the empty slice and nil to be equivalent.
- require.True(
- t, bytes.Equal(
- first.UpfrontShutdownScript,
- second.UpfrontShutdownScript,
- ),
- )
- first.UpfrontShutdownScript = nil
- second.UpfrontShutdownScript = nil
- require.Equal(t, first, second)
- })
- }
- func FuzzAnnounceSignatures(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- // Prefix with MsgAnnounceSignatures.
- data = prefixWithMsgType(data, MsgAnnounceSignatures)
- // Pass the message into our general fuzz harness for wire
- // messages!
- harness(t, data)
- })
- }
- func FuzzChannelAnnouncement(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- // Prefix with MsgChannelAnnouncement.
- data = prefixWithMsgType(data, MsgChannelAnnouncement)
- // Pass the message into our general fuzz harness for wire
- // messages!
- harness(t, data)
- })
- }
- func FuzzChannelReestablish(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- // Prefix with MsgChannelReestablish.
- data = prefixWithMsgType(data, MsgChannelReestablish)
- // Pass the message into our general fuzz harness for wire
- // messages!
- harness(t, data)
- })
- }
- func FuzzChannelUpdate(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- // Prefix with MsgChannelUpdate.
- data = prefixWithMsgType(data, MsgChannelUpdate)
- // Pass the message into our general fuzz harness for wire
- // messages!
- harness(t, data)
- })
- }
- func FuzzClosingSigned(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- // Prefix with MsgClosingSigned.
- data = prefixWithMsgType(data, MsgClosingSigned)
- // Pass the message into our general fuzz harness for wire
- // messages!
- harness(t, data)
- })
- }
- func FuzzCommitSig(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- // Prefix with MsgCommitSig.
- data = prefixWithMsgType(data, MsgCommitSig)
- // Pass the message into our general fuzz harness for wire
- // messages!
- harness(t, data)
- })
- }
- func FuzzError(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- // Prefix with MsgError.
- data = prefixWithMsgType(data, MsgError)
- // Pass the message into our general fuzz harness for wire
- // messages!
- harness(t, data)
- })
- }
- func FuzzWarning(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- // Prefix with MsgWarning.
- data = prefixWithMsgType(data, MsgWarning)
- // Pass the message into our general fuzz harness for wire
- // messages!
- harness(t, data)
- })
- }
- func FuzzStfu(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- // Prefix with MsgStfu.
- data = prefixWithMsgType(data, MsgStfu)
- // Pass the message into our general fuzz harness for wire
- // messages.
- harness(t, data)
- })
- }
- func FuzzFundingCreated(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- // Prefix with MsgFundingCreated.
- data = prefixWithMsgType(data, MsgFundingCreated)
- // Pass the message into our general fuzz harness for wire
- // messages!
- harness(t, data)
- })
- }
- func FuzzChannelReady(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- // Prefix with MsgChannelReady.
- data = prefixWithMsgType(data, MsgChannelReady)
- // Pass the message into our general fuzz harness for wire
- // messages!
- harness(t, data)
- })
- }
- func FuzzFundingSigned(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- // Prefix with MsgFundingSigned.
- data = prefixWithMsgType(data, MsgFundingSigned)
- // Pass the message into our general fuzz harness for wire
- // messages!
- harness(t, data)
- })
- }
- func FuzzGossipTimestampRange(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- // Prefix with MsgGossipTimestampRange.
- data = prefixWithMsgType(data, MsgGossipTimestampRange)
- // Pass the message into our general fuzz harness for wire
- // messages!
- harness(t, data)
- })
- }
- func FuzzInit(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- // Prefix with MsgInit.
- data = prefixWithMsgType(data, MsgInit)
- // Pass the message into our general fuzz harness for wire
- // messages!
- harness(t, data)
- })
- }
- func FuzzNodeAnnouncement(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- // Prefix with MsgNodeAnnouncement.
- data = prefixWithMsgType(data, MsgNodeAnnouncement)
- // We have to do this here instead of in harness so that
- // reflect.DeepEqual isn't called. Address (de)serialization
- // messes up the fuzzing assertions.
- // Create a reader with the byte array.
- r := bytes.NewReader(data)
- // Make sure byte array length (excluding 2 bytes for message
- // type) is less than max payload size for the wire message.
- payloadLen := uint32(len(data)) - 2
- if payloadLen > MaxMsgBody {
- return
- }
- msg, err := ReadMessage(r, 0)
- if err != nil {
- return
- }
- // We will serialize the message into a new bytes buffer.
- var b bytes.Buffer
- _, err = WriteMessage(&b, msg, 0)
- require.NoError(t, err)
- // Deserialize the message from the serialized bytes buffer, and
- // then assert that the original message is equal to the newly
- // deserialized message.
- newMsg, err := ReadMessage(&b, 0)
- require.NoError(t, err)
- require.IsType(t, &NodeAnnouncement{}, msg)
- first, _ := msg.(*NodeAnnouncement)
- require.IsType(t, &NodeAnnouncement{}, newMsg)
- second, _ := newMsg.(*NodeAnnouncement)
- // We can't use require.Equal for Addresses, since the same IP
- // can be represented by different underlying bytes. Instead, we
- // compare the normalized string representation of each address.
- require.Equal(t, len(first.Addresses), len(second.Addresses))
- for i := range first.Addresses {
- require.Equal(
- t, first.Addresses[i].String(),
- second.Addresses[i].String(),
- )
- }
- first.Addresses = nil
- second.Addresses = nil
- require.Equal(t, first, second)
- })
- }
- func FuzzOpenChannel(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- // Prefix with MsgOpenChannel.
- data = prefixWithMsgType(data, MsgOpenChannel)
- // We have to do this here instead of in harness so that
- // reflect.DeepEqual isn't called. Because of the
- // UpfrontShutdownScript encoding, the first message and second
- // message aren't deeply equal since the first has a nil slice
- // and the other has an empty slice.
- // Create a reader with the byte array.
- r := bytes.NewReader(data)
- // Make sure byte array length (excluding 2 bytes for message
- // type) is less than max payload size for the wire message.
- payloadLen := uint32(len(data)) - 2
- if payloadLen > MaxMsgBody {
- return
- }
- msg, err := ReadMessage(r, 0)
- if err != nil {
- return
- }
- // We will serialize the message into a new bytes buffer.
- var b bytes.Buffer
- _, err = WriteMessage(&b, msg, 0)
- require.NoError(t, err)
- // Deserialize the message from the serialized bytes buffer, and
- // then assert that the original message is equal to the newly
- // deserialized message.
- newMsg, err := ReadMessage(&b, 0)
- require.NoError(t, err)
- require.IsType(t, &OpenChannel{}, msg)
- first, _ := msg.(*OpenChannel)
- require.IsType(t, &OpenChannel{}, newMsg)
- second, _ := newMsg.(*OpenChannel)
- // We can't use require.Equal for UpfrontShutdownScript, since
- // we consider the empty slice and nil to be equivalent.
- require.True(
- t, bytes.Equal(
- first.UpfrontShutdownScript,
- second.UpfrontShutdownScript,
- ),
- )
- first.UpfrontShutdownScript = nil
- second.UpfrontShutdownScript = nil
- require.Equal(t, first, second)
- })
- }
- func FuzzPing(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- // Prefix with MsgPing.
- data = prefixWithMsgType(data, MsgPing)
- // Pass the message into our general fuzz harness for wire
- // messages!
- harness(t, data)
- })
- }
- func FuzzPong(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- // Prefix with MsgPong.
- data = prefixWithMsgType(data, MsgPong)
- // Pass the message into our general fuzz harness for wire
- // messages!
- harness(t, data)
- })
- }
- func FuzzQueryChannelRange(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- // Prefix with MsgQueryChannelRange.
- data = prefixWithMsgType(data, MsgQueryChannelRange)
- // Pass the message into our general fuzz harness for wire
- // messages!
- harness(t, data)
- })
- }
- func FuzzZlibQueryShortChanIDs(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- var buf bytes.Buffer
- zlibWriter := zlib.NewWriter(&buf)
- _, err := zlibWriter.Write(data)
- require.NoError(t, err) // Zlib bug?
- err = zlibWriter.Close()
- require.NoError(t, err) // Zlib bug?
- compressedPayload := buf.Bytes()
- chainhash := []byte("00000000000000000000000000000000")
- numBytesInBody := len(compressedPayload) + 1
- zlibByte := []byte("\x01")
- bodyBytes := make([]byte, 2)
- binary.BigEndian.PutUint16(bodyBytes, uint16(numBytesInBody))
- payload := chainhash
- payload = append(payload, bodyBytes...)
- payload = append(payload, zlibByte...)
- payload = append(payload, compressedPayload...)
- // Prefix with MsgQueryShortChanIDs.
- payload = prefixWithMsgType(payload, MsgQueryShortChanIDs)
- // Pass the message into our general fuzz harness for wire
- // messages!
- harness(t, payload)
- })
- }
- func FuzzQueryShortChanIDs(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- // Prefix with MsgQueryShortChanIDs.
- data = prefixWithMsgType(data, MsgQueryShortChanIDs)
- // Pass the message into our general fuzz harness for wire
- // messages!
- harness(t, data)
- })
- }
- func FuzzZlibReplyChannelRange(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- var buf bytes.Buffer
- zlibWriter := zlib.NewWriter(&buf)
- _, err := zlibWriter.Write(data)
- require.NoError(t, err) // Zlib bug?
- err = zlibWriter.Close()
- require.NoError(t, err) // Zlib bug?
- compressedPayload := buf.Bytes()
- // Initialize some []byte vars which will prefix our payload
- chainhash := []byte("00000000000000000000000000000000")
- firstBlockHeight := []byte("\x00\x00\x00\x00")
- numBlocks := []byte("\x00\x00\x00\x00")
- completeByte := []byte("\x00")
- numBytesInBody := len(compressedPayload) + 1
- zlibByte := []byte("\x01")
- bodyBytes := make([]byte, 2)
- binary.BigEndian.PutUint16(bodyBytes, uint16(numBytesInBody))
- payload := chainhash
- payload = append(payload, firstBlockHeight...)
- payload = append(payload, numBlocks...)
- payload = append(payload, completeByte...)
- payload = append(payload, bodyBytes...)
- payload = append(payload, zlibByte...)
- payload = append(payload, compressedPayload...)
- // Prefix with MsgReplyChannelRange.
- payload = prefixWithMsgType(payload, MsgReplyChannelRange)
- // Pass the message into our general fuzz harness for wire
- // messages!
- harness(t, payload)
- })
- }
- func FuzzReplyChannelRange(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- // Prefix with MsgReplyChannelRange.
- data = prefixWithMsgType(data, MsgReplyChannelRange)
- // Because require.Equal considers nil slices and empty slices
- // to be non-equal, we must manually compare the Timestamps
- // field rather than using the harness.
- if len(data) > MaxSliceLength {
- return
- }
- r := bytes.NewReader(data)
- msg, err := ReadMessage(r, 0)
- if err != nil {
- return
- }
- // We will serialize the message into a new bytes buffer.
- var b bytes.Buffer
- _, err = WriteMessage(&b, msg, 0)
- require.NoError(t, err)
- // Deserialize the message from the serialized bytes buffer, and
- // then assert that the original message is equal to the newly
- // deserialized message.
- newMsg, err := ReadMessage(&b, 0)
- require.NoError(t, err)
- require.IsType(t, &ReplyChannelRange{}, msg)
- first, _ := msg.(*ReplyChannelRange)
- require.IsType(t, &ReplyChannelRange{}, newMsg)
- second, _ := newMsg.(*ReplyChannelRange)
- // We can't use require.Equal for Timestamps, since we consider
- // the empty slice and nil to be equivalent.
- require.Equal(t, len(first.Timestamps), len(second.Timestamps))
- for i, ts1 := range first.Timestamps {
- ts2 := second.Timestamps[i]
- require.Equal(t, ts1, ts2)
- }
- first.Timestamps = nil
- second.Timestamps = nil
- require.Equal(t, first, second)
- })
- }
- func FuzzReplyShortChanIDsEnd(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- // Prefix with MsgReplyShortChanIDsEnd.
- data = prefixWithMsgType(data, MsgReplyShortChanIDsEnd)
- // Pass the message into our general fuzz harness for wire
- // messages!
- harness(t, data)
- })
- }
- func FuzzRevokeAndAck(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- // Prefix with MsgRevokeAndAck.
- data = prefixWithMsgType(data, MsgRevokeAndAck)
- // Pass the message into our general fuzz harness for wire
- // messages!
- harness(t, data)
- })
- }
- func FuzzShutdown(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- // Prefix with MsgShutdown.
- data = prefixWithMsgType(data, MsgShutdown)
- // Pass the message into our general fuzz harness for wire
- // messages!
- harness(t, data)
- })
- }
- func FuzzUpdateAddHTLC(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- // Prefix with MsgUpdateAddHTLC.
- data = prefixWithMsgType(data, MsgUpdateAddHTLC)
- // Pass the message into our general fuzz harness for wire
- // messages!
- harness(t, data)
- })
- }
- func FuzzUpdateFailHTLC(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- // Prefix with MsgUpdateFailHTLC.
- data = prefixWithMsgType(data, MsgUpdateFailHTLC)
- // Pass the message into our general fuzz harness for wire
- // messages!
- harness(t, data)
- })
- }
- func FuzzUpdateFailMalformedHTLC(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- // Prefix with MsgUpdateFailMalformedHTLC.
- data = prefixWithMsgType(data, MsgUpdateFailMalformedHTLC)
- // Pass the message into our general fuzz harness for wire
- // messages!
- harness(t, data)
- })
- }
- func FuzzUpdateFee(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- // Prefix with MsgUpdateFee.
- data = prefixWithMsgType(data, MsgUpdateFee)
- // Pass the message into our general fuzz harness for wire
- // messages!
- harness(t, data)
- })
- }
- func FuzzUpdateFulfillHTLC(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- // Prefix with MsgUpdateFulFillHTLC.
- data = prefixWithMsgType(data, MsgUpdateFulfillHTLC)
- // Pass the message into our general fuzz harness for wire
- // messages!
- harness(t, data)
- })
- }
- func FuzzDynPropose(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- // Prefix with DynPropose.
- data = prefixWithMsgType(data, MsgDynPropose)
- // Pass the message into our general fuzz harness for wire
- // messages!
- harness(t, data)
- })
- }
- func FuzzDynReject(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- // Prefix with DynReject.
- data = prefixWithMsgType(data, MsgDynReject)
- // Pass the message into our general fuzz harness for wire
- // messages!
- harness(t, data)
- })
- }
- func FuzzDynAck(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- // Prefix with DynReject.
- data = prefixWithMsgType(data, MsgDynAck)
- // Pass the message into our general fuzz harness for wire
- // messages!
- harness(t, data)
- })
- }
- func FuzzKickoffSig(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- // Prefix with KickoffSig
- data = prefixWithMsgType(data, MsgKickoffSig)
- // Pass the message into our general fuzz harness for wire
- // messages!
- harness(t, data)
- })
- }
- func FuzzCustomMessage(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte, customMessageType uint16) {
- if customMessageType < uint16(CustomTypeStart) {
- customMessageType += uint16(CustomTypeStart)
- }
- // Prefix with CustomMessage.
- data = prefixWithMsgType(data, MessageType(customMessageType))
- // Pass the message into our general fuzz harness for wire
- // messages!
- harness(t, data)
- })
- }
- // FuzzParseRawSignature tests that our DER-encoded signature parsing does not
- // panic for arbitrary inputs and that serializing and reparsing the signatures
- // does not mutate them.
- func FuzzParseRawSignature(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- sig, err := NewSigFromECDSARawSignature(data)
- if err != nil {
- return
- }
- sig2, err := NewSigFromECDSARawSignature(sig.ToSignatureBytes())
- require.NoError(t, err, "failed to reparse signature")
- require.Equal(t, sig, sig2, "signature mismatch")
- })
- }
- // FuzzConvertFixedSignature tests that conversion of fixed 64-byte signatures
- // to DER-encoded signatures does not panic and that parsing and reconverting
- // the signatures does not mutate them.
- func FuzzConvertFixedSignature(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- var sig Sig
- if len(data) > len(sig.bytes[:]) {
- return
- }
- copy(sig.bytes[:], data)
- derSig, err := sig.ToSignature()
- if err != nil {
- return
- }
- sig2, err := NewSigFromSignature(derSig)
- require.NoError(t, err, "failed to parse signature")
- derSig2, err := sig2.ToSignature()
- require.NoError(t, err, "failed to reconvert signature to DER")
- derBytes := derSig.Serialize()
- derBytes2 := derSig2.Serialize()
- require.Equal(t, derBytes, derBytes2, "signature mismatch")
- })
- }
- // prefixWithFailCode adds a failure code prefix to data.
- func prefixWithFailCode(data []byte, code FailCode) []byte {
- var codeBytes [2]byte
- binary.BigEndian.PutUint16(codeBytes[:], uint16(code))
- data = append(codeBytes[:], data...)
- return data
- }
- // equalFunc is a function used to determine whether two deserialized messages
- // are equivalent.
- type equalFunc func(x, y any) bool
- // onionFailureHarnessCustom performs the actual fuzz testing of the appropriate
- // onion failure message. This function will check that the passed-in message
- // passes wire length checks, is a valid message once deserialized, and passes a
- // sequence of serialization and deserialization checks.
- func onionFailureHarnessCustom(t *testing.T, data []byte, code FailCode,
- eq equalFunc) {
- data = prefixWithFailCode(data, code)
- // Don't waste time fuzzing messages larger than we'll ever accept.
- if len(data) > MaxSliceLength {
- return
- }
- // First check whether the failure message can be decoded.
- r := bytes.NewReader(data)
- msg, err := DecodeFailureMessage(r, 0)
- if err != nil {
- return
- }
- // We now have a valid decoded message. Verify that encoding and
- // decoding the message does not mutate it.
- var b bytes.Buffer
- err = EncodeFailureMessage(&b, msg, 0)
- require.NoError(t, err, "failed to encode failure message")
- newMsg, err := DecodeFailureMessage(&b, 0)
- require.NoError(t, err, "failed to decode serialized failure message")
- require.True(
- t, eq(msg, newMsg),
- "original message and deserialized message are not equal: "+
- "%v != %v",
- msg, newMsg,
- )
- // Now verify that encoding/decoding full packets works as expected.
- var pktBuf bytes.Buffer
- if err := EncodeFailure(&pktBuf, msg, 0); err != nil {
- // EncodeFailure returns an error if the encoded message would
- // exceed FailureMessageLength bytes, as LND always encodes
- // fixed-size packets for privacy. But it is valid to decode
- // messages longer than this, so we should not report an error
- // if the original message was longer.
- //
- // We add 2 to the length of the original message since it may
- // have omitted a channel_update type prefix of 2 bytes. When
- // we re-encode such a message, we will add the 2-byte prefix
- // as prescribed by the spec.
- if len(data)+2 > FailureMessageLength {
- return
- }
- t.Fatalf("failed to encode failure packet: %v", err)
- }
- // We should use FailureMessageLength sized packets plus 2 bytes to
- // encode the message length and 2 bytes to encode the padding length,
- // as recommended by the spec.
- require.Equal(
- t, pktBuf.Len(), FailureMessageLength+4,
- "wrong failure message length",
- )
- pktMsg, err := DecodeFailure(&pktBuf, 0)
- require.NoError(t, err, "failed to decode failure packet")
- require.True(
- t, eq(msg, pktMsg),
- "original message and decoded packet message are not equal: "+
- "%v != %v",
- msg, pktMsg,
- )
- }
- func onionFailureHarness(t *testing.T, data []byte, code FailCode) {
- t.Helper()
- onionFailureHarnessCustom(t, data, code, reflect.DeepEqual)
- }
- func FuzzFailIncorrectDetails(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- // Since FailIncorrectDetails.Decode can leave extraOpaqueData
- // as nil while FailIncorrectDetails.Encode writes an empty
- // slice, we need to use a custom equality function.
- eq := func(x, y any) bool {
- msg1, ok := x.(*FailIncorrectDetails)
- require.True(
- t, ok, "msg1 was not FailIncorrectDetails",
- )
- msg2, ok := y.(*FailIncorrectDetails)
- require.True(
- t, ok, "msg2 was not FailIncorrectDetails",
- )
- return msg1.amount == msg2.amount &&
- msg1.height == msg2.height &&
- bytes.Equal(
- msg1.extraOpaqueData,
- msg2.extraOpaqueData,
- )
- }
- onionFailureHarnessCustom(
- t, data, CodeIncorrectOrUnknownPaymentDetails, eq,
- )
- })
- }
- func FuzzFailInvalidOnionVersion(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- onionFailureHarness(t, data, CodeInvalidOnionVersion)
- })
- }
- func FuzzFailInvalidOnionHmac(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- onionFailureHarness(t, data, CodeInvalidOnionHmac)
- })
- }
- func FuzzFailInvalidOnionKey(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- onionFailureHarness(t, data, CodeInvalidOnionKey)
- })
- }
- func FuzzFailTemporaryChannelFailure(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- onionFailureHarness(t, data, CodeTemporaryChannelFailure)
- })
- }
- func FuzzFailAmountBelowMinimum(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- onionFailureHarness(t, data, CodeAmountBelowMinimum)
- })
- }
- func FuzzFailFeeInsufficient(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- onionFailureHarness(t, data, CodeFeeInsufficient)
- })
- }
- func FuzzFailIncorrectCltvExpiry(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- onionFailureHarness(t, data, CodeIncorrectCltvExpiry)
- })
- }
- func FuzzFailExpiryTooSoon(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- onionFailureHarness(t, data, CodeExpiryTooSoon)
- })
- }
- func FuzzFailChannelDisabled(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- onionFailureHarness(t, data, CodeChannelDisabled)
- })
- }
- func FuzzFailFinalIncorrectCltvExpiry(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- onionFailureHarness(t, data, CodeFinalIncorrectCltvExpiry)
- })
- }
- func FuzzFailFinalIncorrectHtlcAmount(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- onionFailureHarness(t, data, CodeFinalIncorrectHtlcAmount)
- })
- }
- func FuzzInvalidOnionPayload(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- onionFailureHarness(t, data, CodeInvalidOnionPayload)
- })
- }
- func FuzzClosingSig(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- // Prefix with ClosingSig.
- data = prefixWithMsgType(data, MsgClosingSig)
- // Pass the message into our general fuzz harness for wire
- // messages!
- harness(t, data)
- })
- }
- func FuzzClosingComplete(f *testing.F) {
- f.Fuzz(func(t *testing.T, data []byte) {
- // Prefix with ClosingComplete.
- data = prefixWithMsgType(data, MsgClosingComplete)
- // Pass the message into our general fuzz harness for wire
- // messages!
- harness(t, data)
- })
- }
|