prysm-pulse/fuzz/block_fuzz.go
Preston Van Loon cebb62997d
Add beacon state unmarshal fuzzer, afl support (#6625)
* Add AFL third_party libraries

* add beacon state fuzzing, add afl fuzz bundle

* rm fuzzing engine

* fix and lint

* Check for array out of bounds when calculating proposer delta

* failing test

* fix

* Checkpoint progress

* Add requirement that inclusion distance is not zero, add regression test

* No need for HTR since that is covered in process slots

* Removing some fuzzit logic, old fuzz tests

* Add ssz encoder test and fix

* Fuzzing checkpoint, adding fuzzing to the p2p layer

* ignore some libfuzzer files

* Full testing of p2p processing of blocks, with some mocked stuff

* use tmpdir and always process blocks

* use checkptr

* Update ethereumapis

* go mod tidy

* benchmarks for ferran's fast ssz hash tree root

* Update fastssz

* fmt

* gaz

* goimports

* Fix

* fix ethereumapis

* fix again

* kafka

* fix gen file

* fix compute signing root

* gofmt

* checkpoint progress

* progress

* checkpoint

* updates

* updates

* merge fix

* WIP

* merge

* fix build

* fix merge related issues

* cleanup

* revert unrelated

* lint

* lint

* lint

* manual tags for fuzz

* Commentary on upload script

* some import fixes, but not all

* fix //fuzz:fuzz_tests

* rm unused test

* update generated ssz

* Set // +build libfuzzer

* remove debug code

* A bit of refactoring ot explain why there is a committee_disabled file

Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2020-09-14 11:42:08 -07:00

196 lines
4.7 KiB
Go

// +build libfuzzer
package fuzz
import (
"bytes"
"context"
"encoding/hex"
"io/ioutil"
"os"
"path"
"github.com/libp2p/go-libp2p-core/peer"
pubsub "github.com/libp2p/go-libp2p-pubsub"
pubsub_pb "github.com/libp2p/go-libp2p-pubsub/pb"
"github.com/prysmaticlabs/go-ssz"
"github.com/prysmaticlabs/prysm/beacon-chain/blockchain"
"github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing"
"github.com/prysmaticlabs/prysm/beacon-chain/cache"
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
"github.com/prysmaticlabs/prysm/beacon-chain/db"
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray"
"github.com/prysmaticlabs/prysm/beacon-chain/operations/attestations"
"github.com/prysmaticlabs/prysm/beacon-chain/operations/slashings"
"github.com/prysmaticlabs/prysm/beacon-chain/operations/voluntaryexits"
"github.com/prysmaticlabs/prysm/beacon-chain/p2p"
p2pt "github.com/prysmaticlabs/prysm/beacon-chain/p2p/testing"
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
"github.com/prysmaticlabs/prysm/beacon-chain/sync"
"github.com/prysmaticlabs/prysm/shared/featureconfig"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/rand"
"github.com/prysmaticlabs/prysm/shared/testutil"
"github.com/sirupsen/logrus"
)
const topic = p2p.BlockSubnetTopicFormat
var db1 db.Database
var ssc *cache.StateSummaryCache
var dbPath = path.Join(os.TempDir(), "fuzz_beacondb", randomHex(6))
func randomHex(n int) string {
bytes := make([]byte, n)
if _, err := rand.NewGenerator().Read(bytes); err != nil {
panic(err)
}
return hex.EncodeToString(bytes)
}
func init() {
featureconfig.Init(&featureconfig.Flags{SkipBLSVerify: true})
logrus.SetLevel(logrus.PanicLevel)
logrus.SetOutput(ioutil.Discard)
ssc = cache.NewStateSummaryCache()
var err error
db1, err = db.NewDB(dbPath, ssc)
if err != nil {
panic(err)
}
}
func setupDB() {
if err := db1.ClearDB(); err != nil {
_ = err
}
ctx := context.Background()
s := testutil.NewBeaconState()
b := testutil.NewBeaconBlock()
if err := db1.SaveBlock(ctx, b); err != nil {
panic(err)
}
br, err := ssz.HashTreeRoot(b)
if err != nil {
panic(err)
}
if err := db1.SaveState(ctx, s, br); err != nil {
panic(err)
}
if err := db1.SaveGenesisBlockRoot(ctx, br); err != nil {
panic(err)
}
}
type fakeChecker struct{}
func (fakeChecker) Syncing() bool {
return false
}
func (fakeChecker) Status() error {
return nil
}
func (fakeChecker) Resync() error {
return nil
}
// BeaconFuzzBlock runs full processing of beacon block against a given state.
func BeaconFuzzBlock(b []byte) {
params.UseMainnetConfig()
input := &InputBlockWithPrestate{}
if err := input.UnmarshalSSZ(b); err != nil {
return
}
st, err := stateTrie.InitializeFromProtoUnsafe(input.State)
if err != nil {
return
}
setupDB()
p2p := p2pt.NewFuzzTestP2P()
sgen := stategen.New(db1, ssc)
sn := &testing.MockStateNotifier{}
bn := &testing.MockBlockNotifier{}
an := &testing.MockOperationNotifier{}
ap := attestations.NewPool()
ep := voluntaryexits.NewPool()
sp := slashings.NewPool()
ops, err := attestations.NewService(context.Background(), &attestations.Config{Pool: ap})
if err != nil {
panic(err)
}
chain, err := blockchain.NewService(context.Background(), &blockchain.Config{
ChainStartFetcher: nil,
BeaconDB: db1,
DepositCache: nil,
AttPool: ap,
ExitPool: ep,
SlashingPool: sp,
P2p: p2p,
StateNotifier: sn,
ForkChoiceStore: protoarray.New(0, 0, [32]byte{}),
OpsService: ops,
StateGen: sgen,
})
if err != nil {
panic(err)
}
chain.Start()
s := sync.NewRegularSyncFuzz(&sync.Config{
DB: db1,
P2P: p2p,
Chain: chain,
InitialSync: fakeChecker{},
StateNotifier: sn,
BlockNotifier: bn,
AttestationNotifier: an,
AttPool: ap,
ExitPool: ep,
SlashingPool: sp,
StateSummaryCache: ssc,
StateGen: sgen,
})
if err := s.InitCaches(); err != nil {
panic(err)
}
buf := new(bytes.Buffer)
_, err = p2p.Encoding().EncodeGossip(buf, input.Block)
if err != nil {
panic(err)
}
ctx := context.Background()
pid := peer.ID("fuzz")
msg := &pubsub.Message{
Message: &pubsub_pb.Message{
Data: buf.Bytes(),
TopicIDs: []string{topic},
},
}
if res := s.FuzzValidateBeaconBlockPubSub(ctx, pid, msg); res != pubsub.ValidationAccept {
return
}
if err := s.FuzzBeaconBlockSubscriber(ctx, msg); err != nil {
_ = err
}
if _, err := state.ProcessBlock(ctx, st, input.Block); err != nil {
_ = err
}
}