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