# Prysm Fuzz Testing [![fuzzit](https://app.fuzzit.dev/badge?org_id=prysmaticlabs-gh)](https://app.fuzzit.dev/orgs/prysmaticlabs-gh/dashboard) ## Adding a fuzz test Fuzz testing attempts to find crash level bugs within the tested code paths, but could also be used as a sanity check certain logic. ### 1) Determining an ideal target A fuzz test inputs pseudo-random data to a given method and attempts to find input data that tests as many code branches as possible. When choosing a target to test, consider that the method under test should be as stateless as possible. While stateful methods (i.e. methods that use a cache), can be tested, they are often hard to reproduce in a regression test. Consider disabling any caches or persistence layers if possible. ### 2) Writing a fuzz test First, you need to determine in your input data. The current test suite uses SSZ encoded bytes to deserialize to input objects. _Example: Block header input data_ ```go type InputBlockHeader struct { StateID uint16 Block *ethpb.BeaconBlock } ``` You'll also want to add that struct to `//fuzz:ssz_generated_files` to generate the custom fast SSZ methods for serialization to improve test performance. Your fuzz test must accept a single argument of type `[]byte`. The return types are ignored by libfuzzer, but might be useful for other applications such as [beacon-fuzz](https://github.com/sigp/beacon-fuzz). Be sure to name your test file with the `_fuzz.go` suffix for consistency. ```go func MyExampleFuzz(b []byte) { input := &MyFuzzInputData{} if err := ssz.Unmarshal(b, input); err != nil { return // Input bytes doesn't serialize to input object. } result, err := somePackage.MethodUnderTest(input) if err != nil { // Input was invalid for processing, but the method didn't panic so that's OK. return } // Optional: sanity check the resulting data. if result < 0 { panic("MethodUnderTest should never return a negative number") // Fail! } } ``` ### 3) Add your fuzz target to fuzz/BUILD.bazel Since we are using some custom rules to generate the fuzz test instrumentation and appropriate libfuzz testing suite, we cannot rely on gazelle to generate these targets for us. ```starlark go_fuzz_test( name = "example_fuzz_test", srcs = [ "example_fuzz.go", ] + COMMON_SRCS, # common and input type files. corpus = "example_corpus", corpus_path = "fuzz/example_corpus", # Path from root of project func = "MyExampleFuzz", importpath = IMPORT_PATH, deps = [ # Deps used in your fuzz test. ] + COMMON_DEPS, ) ``` Be sure to add your target to the test suite at `//fuzz:fuzz_tests`. ### 4) Run your fuzz test To run your fuzz test you must manually target it with bazel test and run with the config flag `--config=fuzz`. ``` bazel test //fuzz:example_fuzz_test --config=fuzz ``` ## Running fuzzit regression tests To run fuzzit regression tests, you can run the fuzz test suite with the 1--config=fuzzit` configuration flag. Note: This requires docker installed on your machine. See [fuzzitdev/fuzzit#58](https://github.com/fuzzitdev/fuzzit/issues/58). ``` bazel test //fuzz:fuzz_tests --config=fuzzit ``` If the same command above is run with the FUZZIT_API_KEY environment variable set, then the fuzzit test targets will be uploaded and restarted at https://app.fuzzit.dev.