github.com/carter-ya/go-ethereum@v0.0.0-20230628080049-d2309be3983b/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/ethereum/go-ethereum/common" 27 "github.com/ethereum/go-ethereum/consensus/ethash" 28 "github.com/ethereum/go-ethereum/core" 29 "github.com/ethereum/go-ethereum/core/rawdb" 30 "github.com/ethereum/go-ethereum/core/vm" 31 "github.com/ethereum/go-ethereum/eth/protocols/snap" 32 "github.com/ethereum/go-ethereum/p2p" 33 "github.com/ethereum/go-ethereum/p2p/enode" 34 "github.com/ethereum/go-ethereum/params" 35 "github.com/ethereum/go-ethereum/rlp" 36 fuzz "github.com/google/gofuzz" 37 ) 38 39 var trieRoot common.Hash 40 41 func getChain() *core.BlockChain { 42 ga := make(core.GenesisAlloc, 1000) 43 var a = make([]byte, 20) 44 var mkStorage = func(k, v int) (common.Hash, common.Hash) { 45 var kB = make([]byte, 32) 46 var vB = make([]byte, 32) 47 binary.LittleEndian.PutUint64(kB, uint64(k)) 48 binary.LittleEndian.PutUint64(vB, uint64(v)) 49 return common.BytesToHash(kB), common.BytesToHash(vB) 50 } 51 storage := make(map[common.Hash]common.Hash) 52 for i := 0; i < 10; i++ { 53 k, v := mkStorage(i, i) 54 storage[k] = v 55 } 56 for i := 0; i < 1000; i++ { 57 binary.LittleEndian.PutUint64(a, uint64(i+0xff)) 58 acc := core.GenesisAccount{Balance: big.NewInt(int64(i))} 59 if i%2 == 1 { 60 acc.Storage = storage 61 } 62 ga[common.BytesToAddress(a)] = acc 63 } 64 gspec := &core.Genesis{ 65 Config: params.TestChainConfig, 66 Alloc: ga, 67 } 68 _, blocks, _ := core.GenerateChainWithGenesis(gspec, ethash.NewFaker(), 2, func(i int, gen *core.BlockGen) {}) 69 cacheConf := &core.CacheConfig{ 70 TrieCleanLimit: 0, 71 TrieDirtyLimit: 0, 72 TrieTimeLimit: 5 * time.Minute, 73 TrieCleanNoPrefetch: true, 74 TrieCleanRejournal: 0, 75 SnapshotLimit: 100, 76 SnapshotWait: true, 77 } 78 trieRoot = blocks[len(blocks)-1].Root() 79 bc, _ := core.NewBlockChain(rawdb.NewMemoryDatabase(), cacheConf, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) 80 if _, err := bc.InsertChain(blocks); err != nil { 81 panic(err) 82 } 83 return bc 84 } 85 86 type dummyBackend struct { 87 chain *core.BlockChain 88 } 89 90 func (d *dummyBackend) Chain() *core.BlockChain { return d.chain } 91 func (d *dummyBackend) RunPeer(*snap.Peer, snap.Handler) error { return nil } 92 func (d *dummyBackend) PeerInfo(enode.ID) interface{} { return "Foo" } 93 func (d *dummyBackend) Handle(*snap.Peer, snap.Packet) error { return nil } 94 95 type dummyRW struct { 96 code uint64 97 data []byte 98 writeCount int 99 } 100 101 func (d *dummyRW) ReadMsg() (p2p.Msg, error) { 102 return p2p.Msg{ 103 Code: d.code, 104 Payload: bytes.NewReader(d.data), 105 ReceivedAt: time.Now(), 106 Size: uint32(len(d.data)), 107 }, nil 108 } 109 110 func (d *dummyRW) WriteMsg(msg p2p.Msg) error { 111 d.writeCount++ 112 return nil 113 } 114 115 func doFuzz(input []byte, obj interface{}, code int) int { 116 if len(input) > 1024*4 { 117 return -1 118 } 119 bc := getChain() 120 defer bc.Stop() 121 backend := &dummyBackend{bc} 122 fuzz.NewFromGoFuzz(input).Fuzz(obj) 123 var data []byte 124 switch p := obj.(type) { 125 case *snap.GetTrieNodesPacket: 126 p.Root = trieRoot 127 data, _ = rlp.EncodeToBytes(obj) 128 default: 129 data, _ = rlp.EncodeToBytes(obj) 130 } 131 cli := &dummyRW{ 132 code: uint64(code), 133 data: data, 134 } 135 peer := snap.NewFakePeer(65, "gazonk01", cli) 136 err := snap.HandleMessage(backend, peer) 137 switch { 138 case err == nil && cli.writeCount != 1: 139 panic(fmt.Sprintf("Expected 1 response, got %d", cli.writeCount)) 140 case err != nil && cli.writeCount != 0: 141 panic(fmt.Sprintf("Expected 0 response, got %d", cli.writeCount)) 142 } 143 return 1 144 } 145 146 // To run a fuzzer, do 147 // $ CGO_ENABLED=0 go-fuzz-build -func FuzzTrieNodes 148 // $ go-fuzz 149 150 func FuzzARange(input []byte) int { 151 return doFuzz(input, &snap.GetAccountRangePacket{}, snap.GetAccountRangeMsg) 152 } 153 func FuzzSRange(input []byte) int { 154 return doFuzz(input, &snap.GetStorageRangesPacket{}, snap.GetStorageRangesMsg) 155 } 156 func FuzzByteCodes(input []byte) int { 157 return doFuzz(input, &snap.GetByteCodesPacket{}, snap.GetByteCodesMsg) 158 } 159 func FuzzTrieNodes(input []byte) int { 160 return doFuzz(input, &snap.GetTrieNodesPacket{}, snap.GetTrieNodesMsg) 161 }