github.com/ethereum/go-ethereum@v1.14.3/tests/fuzzers/txfetcher/txfetcher_fuzzer.go (about) 1 // Copyright 2020 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 txfetcher 18 19 import ( 20 "bytes" 21 "fmt" 22 "math/big" 23 "math/rand" 24 "time" 25 26 "github.com/ethereum/go-ethereum/common" 27 "github.com/ethereum/go-ethereum/common/mclock" 28 "github.com/ethereum/go-ethereum/core/types" 29 "github.com/ethereum/go-ethereum/eth/fetcher" 30 ) 31 32 var ( 33 peers []string 34 txs []*types.Transaction 35 ) 36 37 func init() { 38 // Random is nice, but we need it deterministic 39 rand := rand.New(rand.NewSource(0x3a29)) 40 41 peers = make([]string, 10) 42 for i := 0; i < len(peers); i++ { 43 peers[i] = fmt.Sprintf("Peer #%d", i) 44 } 45 txs = make([]*types.Transaction, 65536) // We need to bump enough to hit all the limits 46 for i := 0; i < len(txs); i++ { 47 txs[i] = types.NewTransaction(rand.Uint64(), common.Address{byte(rand.Intn(256))}, new(big.Int), 0, new(big.Int), nil) 48 } 49 } 50 51 func fuzz(input []byte) int { 52 // Don't generate insanely large test cases, not much value in them 53 if len(input) > 16*1024 { 54 return 0 55 } 56 verbose := false 57 r := bytes.NewReader(input) 58 59 // Reduce the problem space for certain fuzz runs. Small tx space is better 60 // for testing clashes and in general the fetcher, but we should still run 61 // some tests with large spaces to hit potential issues on limits. 62 limit, err := r.ReadByte() 63 if err != nil { 64 return 0 65 } 66 switch limit % 4 { 67 case 0: 68 txs = txs[:4] 69 case 1: 70 txs = txs[:256] 71 case 2: 72 txs = txs[:4096] 73 case 3: 74 // Full run 75 } 76 // Create a fetcher and hook into it's simulated fields 77 clock := new(mclock.Simulated) 78 rand := rand.New(rand.NewSource(0x3a29)) // Same used in package tests!!! 79 80 f := fetcher.NewTxFetcherForTests( 81 func(common.Hash) bool { return false }, 82 func(txs []*types.Transaction) []error { 83 return make([]error, len(txs)) 84 }, 85 func(string, []common.Hash) error { return nil }, 86 nil, 87 clock, rand, 88 ) 89 f.Start() 90 defer f.Stop() 91 92 // Try to throw random junk at the fetcher 93 for { 94 // Read the next command and abort if we're done 95 cmd, err := r.ReadByte() 96 if err != nil { 97 return 0 98 } 99 switch cmd % 4 { 100 case 0: 101 // Notify a new set of transactions: 102 // Byte 1: Peer index to announce with 103 // Byte 2: Number of hashes to announce 104 // Byte 3-4, 5-6, etc: Transaction indices (2 byte) to announce 105 peerIdx, err := r.ReadByte() 106 if err != nil { 107 return 0 108 } 109 peer := peers[int(peerIdx)%len(peers)] 110 111 announceCnt, err := r.ReadByte() 112 if err != nil { 113 return 0 114 } 115 announce := int(announceCnt) % (2 * len(txs)) // No point in generating too many duplicates 116 117 var ( 118 announceIdxs = make([]int, announce) 119 announces = make([]common.Hash, announce) 120 types = make([]byte, announce) 121 sizes = make([]uint32, announce) 122 ) 123 for i := 0; i < len(announces); i++ { 124 annBuf := make([]byte, 2) 125 if n, err := r.Read(annBuf); err != nil || n != 2 { 126 return 0 127 } 128 announceIdxs[i] = (int(annBuf[0])*256 + int(annBuf[1])) % len(txs) 129 announces[i] = txs[announceIdxs[i]].Hash() 130 types[i] = txs[announceIdxs[i]].Type() 131 sizes[i] = uint32(txs[announceIdxs[i]].Size()) 132 } 133 if verbose { 134 fmt.Println("Notify", peer, announceIdxs) 135 } 136 if err := f.Notify(peer, types, sizes, announces); err != nil { 137 panic(err) 138 } 139 140 case 1: 141 // Deliver a new set of transactions: 142 // Byte 1: Peer index to announce with 143 // Byte 2: Number of hashes to announce 144 // Byte 3-4, 5-6, etc: Transaction indices (2 byte) to announce 145 peerIdx, err := r.ReadByte() 146 if err != nil { 147 return 0 148 } 149 peer := peers[int(peerIdx)%len(peers)] 150 151 deliverCnt, err := r.ReadByte() 152 if err != nil { 153 return 0 154 } 155 deliver := int(deliverCnt) % (2 * len(txs)) // No point in generating too many duplicates 156 157 var ( 158 deliverIdxs = make([]int, deliver) 159 deliveries = make([]*types.Transaction, deliver) 160 ) 161 for i := 0; i < len(deliveries); i++ { 162 deliverBuf := make([]byte, 2) 163 if n, err := r.Read(deliverBuf); err != nil || n != 2 { 164 return 0 165 } 166 deliverIdxs[i] = (int(deliverBuf[0])*256 + int(deliverBuf[1])) % len(txs) 167 deliveries[i] = txs[deliverIdxs[i]] 168 } 169 directFlag, err := r.ReadByte() 170 if err != nil { 171 return 0 172 } 173 direct := (directFlag % 2) == 0 174 if verbose { 175 fmt.Println("Enqueue", peer, deliverIdxs, direct) 176 } 177 if err := f.Enqueue(peer, deliveries, direct); err != nil { 178 panic(err) 179 } 180 181 case 2: 182 // Drop a peer: 183 // Byte 1: Peer index to drop 184 peerIdx, err := r.ReadByte() 185 if err != nil { 186 return 0 187 } 188 peer := peers[int(peerIdx)%len(peers)] 189 if verbose { 190 fmt.Println("Drop", peer) 191 } 192 if err := f.Drop(peer); err != nil { 193 panic(err) 194 } 195 196 case 3: 197 // Move the simulated clock forward 198 // Byte 1: 100ms increment to move forward 199 tickCnt, err := r.ReadByte() 200 if err != nil { 201 return 0 202 } 203 tick := time.Duration(tickCnt) * 100 * time.Millisecond 204 if verbose { 205 fmt.Println("Sleep", tick) 206 } 207 clock.Run(tick) 208 } 209 } 210 }