From a7ee45bea09b518b39deb2865658b96417038a03 Mon Sep 17 00:00:00 2001 From: Matt Morehouse Date: Tue, 2 May 2023 18:07:49 -0500 Subject: [PATCH] lnwire: add FuzzFailIncorrectDetails test The test is identical to other onion failure fuzz tests, except that it uses a custom equality function to get around the nil != []byte{} issue with reflect.DeepEqual. --- lnwire/fuzz_test.go | 53 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 6 deletions(-) diff --git a/lnwire/fuzz_test.go b/lnwire/fuzz_test.go index 41f0f1fb5..95f35884a 100644 --- a/lnwire/fuzz_test.go +++ b/lnwire/fuzz_test.go @@ -646,11 +646,17 @@ func prefixWithFailCode(data []byte, code FailCode) []byte { return data } -// onionFailureHarness 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 +// 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 onionFailureHarness(t *testing.T, data []byte, code FailCode) { +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. @@ -678,7 +684,7 @@ func onionFailureHarness(t *testing.T, data []byte, code FailCode) { t.Fatalf("failed to decode serialized failure message: %v", err) } - if !reflect.DeepEqual(msg, newMsg) { + if !eq(msg, newMsg) { t.Fatalf("original message and deserialized message are not "+ "equal: %v != %v", msg, newMsg) } @@ -716,12 +722,47 @@ func onionFailureHarness(t *testing.T, data []byte, code FailCode) { t.Fatalf("failed to decode failure packet: %v", err) } - if !reflect.DeepEqual(msg, pktMsg) { + if !eq(msg, pktMsg) { t.Fatalf("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) + if !ok { + t.Fatal("msg1 was not FailIncorrectDetails") + } + + msg2, ok := y.(*FailIncorrectDetails) + if !ok { + t.Fatalf("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)