github.com/ethw3/go-ethereuma@v0.0.0-20221013053120-c14602a4c23c/tests/fuzzers/snap/fuzz_handler.go (about) 1 // Copyright 2021 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package snap 18 19 import ( 20 "bytes" 21 "encoding/binary" 22 "fmt" 23 "math/big" 24 "time" 25 26 "github.com/ethw3/go-ethereuma/common" 27 "github.com/ethw3/go-ethereuma/consensus/ethash" 28 "github.com/ethw3/go-ethereuma/core" 29 "github.com/ethw3/go-ethereuma/core/rawdb" 30 "github.com/ethw3/go-ethereuma/core/vm" 31 "github.com/ethw3/go-ethereuma/eth/protocols/snap" 32 "github.com/ethw3/go-ethereuma/p2p" 33 "github.com/ethw3/go-ethereuma/p2p/enode" 34 "github.com/ethw3/go-ethereuma/params" 35 "github.com/ethw3/go-ethereuma/rlp" 36 fuzz "github.com/google/gofuzz" 37 ) 38 39 var trieRoot common.Hash 40 41 func getChain() *core.BlockChain { 42 db := rawdb.NewMemoryDatabase() 43 ga := make(core.GenesisAlloc, 1000) 44 var a = make([]byte, 20) 45 var mkStorage = func(k, v int) (common.Hash, common.Hash) { 46 var kB = make([]byte, 32) 47 var vB = make([]byte, 32) 48 binary.LittleEndian.PutUint64(kB, uint64(k)) 49 binary.LittleEndian.PutUint64(vB, uint64(v)) 50 return common.BytesToHash(kB), common.BytesToHash(vB) 51 } 52 storage := make(map[common.Hash]common.Hash) 53 for i := 0; i < 10; i++ { 54 k, v := mkStorage(i, i) 55 storage[k] = v 56 } 57 for i := 0; i < 1000; i++ { 58 binary.LittleEndian.PutUint64(a, uint64(i+0xff)) 59 acc := core.GenesisAccount{Balance: big.NewInt(int64(i))} 60 if i%2 == 1 { 61 acc.Storage = storage 62 } 63 ga[common.BytesToAddress(a)] = acc 64 } 65 gspec := core.Genesis{ 66 Config: params.TestChainConfig, 67 Alloc: ga, 68 } 69 genesis := gspec.MustCommit(db) 70 blocks, _ := core.GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 2, 71 func(i int, gen *core.BlockGen) {}) 72 cacheConf := &core.CacheConfig{ 73 TrieCleanLimit: 0, 74 TrieDirtyLimit: 0, 75 TrieTimeLimit: 5 * time.Minute, 76 TrieCleanNoPrefetch: true, 77 TrieCleanRejournal: 0, 78 SnapshotLimit: 100, 79 SnapshotWait: true, 80 } 81 trieRoot = blocks[len(blocks)-1].Root() 82 bc, _ := core.NewBlockChain(db, cacheConf, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) 83 if _, err := bc.InsertChain(blocks); err != nil { 84 panic(err) 85 } 86 return bc 87 } 88 89 type dummyBackend struct { 90 chain *core.BlockChain 91 } 92 93 func (d *dummyBackend) Chain() *core.BlockChain { return d.chain } 94 func (d *dummyBackend) RunPeer(*snap.Peer, snap.Handler) error { return nil } 95 func (d *dummyBackend) PeerInfo(enode.ID) interface{} { return "Foo" } 96 func (d *dummyBackend) Handle(*snap.Peer, snap.Packet) error { return nil } 97 98 type dummyRW struct { 99 code uint64 100 data []byte 101 writeCount int 102 } 103 104 func (d *dummyRW) ReadMsg() (p2p.Msg, error) { 105 return p2p.Msg{ 106 Code: d.code, 107 Payload: bytes.NewReader(d.data), 108 ReceivedAt: time.Now(), 109 Size: uint32(len(d.data)), 110 }, nil 111 } 112 113 func (d *dummyRW) WriteMsg(msg p2p.Msg) error { 114 d.writeCount++ 115 return nil 116 } 117 118 func doFuzz(input []byte, obj interface{}, code int) int { 119 if len(input) > 1024*4 { 120 return -1 121 } 122 bc := getChain() 123 defer bc.Stop() 124 backend := &dummyBackend{bc} 125 fuzz.NewFromGoFuzz(input).Fuzz(obj) 126 var data []byte 127 switch p := obj.(type) { 128 case *snap.GetTrieNodesPacket: 129 p.Root = trieRoot 130 data, _ = rlp.EncodeToBytes(obj) 131 default: 132 data, _ = rlp.EncodeToBytes(obj) 133 } 134 cli := &dummyRW{ 135 code: uint64(code), 136 data: data, 137 } 138 peer := snap.NewFakePeer(65, "gazonk01", cli) 139 err := snap.HandleMessage(backend, peer) 140 switch { 141 case err == nil && cli.writeCount != 1: 142 panic(fmt.Sprintf("Expected 1 response, got %d", cli.writeCount)) 143 case err != nil && cli.writeCount != 0: 144 panic(fmt.Sprintf("Expected 0 response, got %d", cli.writeCount)) 145 } 146 return 1 147 } 148 149 // To run a fuzzer, do 150 // $ CGO_ENABLED=0 go-fuzz-build -func FuzzTrieNodes 151 // $ go-fuzz 152 153 func FuzzARange(input []byte) int { 154 return doFuzz(input, &snap.GetAccountRangePacket{}, snap.GetAccountRangeMsg) 155 } 156 func FuzzSRange(input []byte) int { 157 return doFuzz(input, &snap.GetStorageRangesPacket{}, snap.GetStorageRangesMsg) 158 } 159 func FuzzByteCodes(input []byte) int { 160 return doFuzz(input, &snap.GetByteCodesPacket{}, snap.GetByteCodesMsg) 161 } 162 func FuzzTrieNodes(input []byte) int { 163 return doFuzz(input, &snap.GetTrieNodesPacket{}, snap.GetTrieNodesMsg) 164 }