github.com/jimmyx0x/go-ethereum@v1.10.28/tests/fuzzers/les/les-fuzzer.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 les 18 19 import ( 20 "bytes" 21 "encoding/binary" 22 "io" 23 "math/big" 24 25 "github.com/ethereum/go-ethereum/common" 26 "github.com/ethereum/go-ethereum/consensus/ethash" 27 "github.com/ethereum/go-ethereum/core" 28 "github.com/ethereum/go-ethereum/core/rawdb" 29 "github.com/ethereum/go-ethereum/core/txpool" 30 "github.com/ethereum/go-ethereum/core/types" 31 "github.com/ethereum/go-ethereum/core/vm" 32 "github.com/ethereum/go-ethereum/crypto" 33 l "github.com/ethereum/go-ethereum/les" 34 "github.com/ethereum/go-ethereum/params" 35 "github.com/ethereum/go-ethereum/rlp" 36 "github.com/ethereum/go-ethereum/trie" 37 ) 38 39 var ( 40 bankKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 41 bankAddr = crypto.PubkeyToAddress(bankKey.PublicKey) 42 bankFunds = new(big.Int).Mul(big.NewInt(100), big.NewInt(params.Ether)) 43 44 testChainLen = 256 45 testContractCode = common.Hex2Bytes("606060405260cc8060106000396000f360606040526000357c01000000000000000000000000000000000000000000000000000000009004806360cd2685146041578063c16431b914606b57603f565b005b6055600480803590602001909190505060a9565b6040518082815260200191505060405180910390f35b60886004808035906020019091908035906020019091905050608a565b005b80600060005083606481101560025790900160005b50819055505b5050565b6000600060005082606481101560025790900160005b5054905060c7565b91905056") 46 47 chain *core.BlockChain 48 addrHashes []common.Hash 49 txHashes []common.Hash 50 51 chtTrie *trie.Trie 52 bloomTrie *trie.Trie 53 chtKeys [][]byte 54 bloomKeys [][]byte 55 ) 56 57 func makechain() (bc *core.BlockChain, addrHashes, txHashes []common.Hash) { 58 gspec := &core.Genesis{ 59 Config: params.TestChainConfig, 60 Alloc: core.GenesisAlloc{bankAddr: {Balance: bankFunds}}, 61 GasLimit: 100000000, 62 } 63 signer := types.HomesteadSigner{} 64 _, blocks, _ := core.GenerateChainWithGenesis(gspec, ethash.NewFaker(), testChainLen, 65 func(i int, gen *core.BlockGen) { 66 var ( 67 tx *types.Transaction 68 addr common.Address 69 ) 70 nonce := uint64(i) 71 if i%4 == 0 { 72 tx, _ = types.SignTx(types.NewContractCreation(nonce, big.NewInt(0), 200000, big.NewInt(0), testContractCode), signer, bankKey) 73 addr = crypto.CreateAddress(bankAddr, nonce) 74 } else { 75 addr = common.BigToAddress(big.NewInt(int64(i))) 76 tx, _ = types.SignTx(types.NewTransaction(nonce, addr, big.NewInt(10000), params.TxGas, big.NewInt(params.GWei), nil), signer, bankKey) 77 } 78 gen.AddTx(tx) 79 addrHashes = append(addrHashes, crypto.Keccak256Hash(addr[:])) 80 txHashes = append(txHashes, tx.Hash()) 81 }) 82 bc, _ = core.NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) 83 if _, err := bc.InsertChain(blocks); err != nil { 84 panic(err) 85 } 86 return 87 } 88 89 func makeTries() (chtTrie *trie.Trie, bloomTrie *trie.Trie, chtKeys, bloomKeys [][]byte) { 90 chtTrie = trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase())) 91 bloomTrie = trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase())) 92 for i := 0; i < testChainLen; i++ { 93 // The element in CHT is <big-endian block number> -> <block hash> 94 key := make([]byte, 8) 95 binary.BigEndian.PutUint64(key, uint64(i+1)) 96 chtTrie.Update(key, []byte{0x1, 0xf}) 97 chtKeys = append(chtKeys, key) 98 99 // The element in Bloom trie is <2 byte bit index> + <big-endian block number> -> bloom 100 key2 := make([]byte, 10) 101 binary.BigEndian.PutUint64(key2[2:], uint64(i+1)) 102 bloomTrie.Update(key2, []byte{0x2, 0xe}) 103 bloomKeys = append(bloomKeys, key2) 104 } 105 return 106 } 107 108 func init() { 109 chain, addrHashes, txHashes = makechain() 110 chtTrie, bloomTrie, chtKeys, bloomKeys = makeTries() 111 } 112 113 type fuzzer struct { 114 chain *core.BlockChain 115 pool *txpool.TxPool 116 117 chainLen int 118 addr, txs []common.Hash 119 nonce uint64 120 121 chtKeys [][]byte 122 bloomKeys [][]byte 123 chtTrie *trie.Trie 124 bloomTrie *trie.Trie 125 126 input io.Reader 127 exhausted bool 128 } 129 130 func newFuzzer(input []byte) *fuzzer { 131 return &fuzzer{ 132 chain: chain, 133 chainLen: testChainLen, 134 addr: addrHashes, 135 txs: txHashes, 136 chtTrie: chtTrie, 137 bloomTrie: bloomTrie, 138 chtKeys: chtKeys, 139 bloomKeys: bloomKeys, 140 nonce: uint64(len(txHashes)), 141 pool: txpool.NewTxPool(txpool.DefaultConfig, params.TestChainConfig, chain), 142 input: bytes.NewReader(input), 143 } 144 } 145 146 func (f *fuzzer) read(size int) []byte { 147 out := make([]byte, size) 148 if _, err := f.input.Read(out); err != nil { 149 f.exhausted = true 150 } 151 return out 152 } 153 154 func (f *fuzzer) randomByte() byte { 155 d := f.read(1) 156 return d[0] 157 } 158 159 func (f *fuzzer) randomBool() bool { 160 d := f.read(1) 161 return d[0]&1 == 1 162 } 163 164 func (f *fuzzer) randomInt(max int) int { 165 if max == 0 { 166 return 0 167 } 168 if max <= 256 { 169 return int(f.randomByte()) % max 170 } 171 var a uint16 172 if err := binary.Read(f.input, binary.LittleEndian, &a); err != nil { 173 f.exhausted = true 174 } 175 return int(a % uint16(max)) 176 } 177 178 func (f *fuzzer) randomX(max int) uint64 { 179 var a uint16 180 if err := binary.Read(f.input, binary.LittleEndian, &a); err != nil { 181 f.exhausted = true 182 } 183 if a < 0x8000 { 184 return uint64(a%uint16(max+1)) - 1 185 } 186 return (uint64(1)<<(a%64+1) - 1) & (uint64(a) * 343897772345826595) 187 } 188 189 func (f *fuzzer) randomBlockHash() common.Hash { 190 h := f.chain.GetCanonicalHash(uint64(f.randomInt(3 * f.chainLen))) 191 if h != (common.Hash{}) { 192 return h 193 } 194 return common.BytesToHash(f.read(common.HashLength)) 195 } 196 197 func (f *fuzzer) randomAddrHash() []byte { 198 i := f.randomInt(3 * len(f.addr)) 199 if i < len(f.addr) { 200 return f.addr[i].Bytes() 201 } 202 return f.read(common.HashLength) 203 } 204 205 func (f *fuzzer) randomCHTTrieKey() []byte { 206 i := f.randomInt(3 * len(f.chtKeys)) 207 if i < len(f.chtKeys) { 208 return f.chtKeys[i] 209 } 210 return f.read(8) 211 } 212 213 func (f *fuzzer) randomBloomTrieKey() []byte { 214 i := f.randomInt(3 * len(f.bloomKeys)) 215 if i < len(f.bloomKeys) { 216 return f.bloomKeys[i] 217 } 218 return f.read(10) 219 } 220 221 func (f *fuzzer) randomTxHash() common.Hash { 222 i := f.randomInt(3 * len(f.txs)) 223 if i < len(f.txs) { 224 return f.txs[i] 225 } 226 return common.BytesToHash(f.read(common.HashLength)) 227 } 228 229 func (f *fuzzer) BlockChain() *core.BlockChain { 230 return f.chain 231 } 232 233 func (f *fuzzer) TxPool() *txpool.TxPool { 234 return f.pool 235 } 236 237 func (f *fuzzer) ArchiveMode() bool { 238 return false 239 } 240 241 func (f *fuzzer) AddTxsSync() bool { 242 return false 243 } 244 245 func (f *fuzzer) GetHelperTrie(typ uint, index uint64) *trie.Trie { 246 if typ == 0 { 247 return f.chtTrie 248 } else if typ == 1 { 249 return f.bloomTrie 250 } 251 return nil 252 } 253 254 type dummyMsg struct { 255 data []byte 256 } 257 258 func (d dummyMsg) Decode(val interface{}) error { 259 return rlp.DecodeBytes(d.data, val) 260 } 261 262 func (f *fuzzer) doFuzz(msgCode uint64, packet interface{}) { 263 enc, err := rlp.EncodeToBytes(packet) 264 if err != nil { 265 panic(err) 266 } 267 version := f.randomInt(3) + 2 // [LES2, LES3, LES4] 268 peer, closeFn := l.NewFuzzerPeer(version) 269 defer closeFn() 270 fn, _, _, err := l.Les3[msgCode].Handle(dummyMsg{enc}) 271 if err != nil { 272 panic(err) 273 } 274 fn(f, peer, func() bool { return true }) 275 } 276 277 func Fuzz(input []byte) int { 278 // We expect some large inputs 279 if len(input) < 100 { 280 return -1 281 } 282 f := newFuzzer(input) 283 if f.exhausted { 284 return -1 285 } 286 for !f.exhausted { 287 switch f.randomInt(8) { 288 case 0: 289 req := &l.GetBlockHeadersPacket{ 290 Query: l.GetBlockHeadersData{ 291 Amount: f.randomX(l.MaxHeaderFetch + 1), 292 Skip: f.randomX(10), 293 Reverse: f.randomBool(), 294 }, 295 } 296 if f.randomBool() { 297 req.Query.Origin.Hash = f.randomBlockHash() 298 } else { 299 req.Query.Origin.Number = uint64(f.randomInt(f.chainLen * 2)) 300 } 301 f.doFuzz(l.GetBlockHeadersMsg, req) 302 303 case 1: 304 req := &l.GetBlockBodiesPacket{Hashes: make([]common.Hash, f.randomInt(l.MaxBodyFetch+1))} 305 for i := range req.Hashes { 306 req.Hashes[i] = f.randomBlockHash() 307 } 308 f.doFuzz(l.GetBlockBodiesMsg, req) 309 310 case 2: 311 req := &l.GetCodePacket{Reqs: make([]l.CodeReq, f.randomInt(l.MaxCodeFetch+1))} 312 for i := range req.Reqs { 313 req.Reqs[i] = l.CodeReq{ 314 BHash: f.randomBlockHash(), 315 AccKey: f.randomAddrHash(), 316 } 317 } 318 f.doFuzz(l.GetCodeMsg, req) 319 320 case 3: 321 req := &l.GetReceiptsPacket{Hashes: make([]common.Hash, f.randomInt(l.MaxReceiptFetch+1))} 322 for i := range req.Hashes { 323 req.Hashes[i] = f.randomBlockHash() 324 } 325 f.doFuzz(l.GetReceiptsMsg, req) 326 327 case 4: 328 req := &l.GetProofsPacket{Reqs: make([]l.ProofReq, f.randomInt(l.MaxProofsFetch+1))} 329 for i := range req.Reqs { 330 if f.randomBool() { 331 req.Reqs[i] = l.ProofReq{ 332 BHash: f.randomBlockHash(), 333 AccKey: f.randomAddrHash(), 334 Key: f.randomAddrHash(), 335 FromLevel: uint(f.randomX(3)), 336 } 337 } else { 338 req.Reqs[i] = l.ProofReq{ 339 BHash: f.randomBlockHash(), 340 Key: f.randomAddrHash(), 341 FromLevel: uint(f.randomX(3)), 342 } 343 } 344 } 345 f.doFuzz(l.GetProofsV2Msg, req) 346 347 case 5: 348 req := &l.GetHelperTrieProofsPacket{Reqs: make([]l.HelperTrieReq, f.randomInt(l.MaxHelperTrieProofsFetch+1))} 349 for i := range req.Reqs { 350 switch f.randomInt(3) { 351 case 0: 352 // Canonical hash trie 353 req.Reqs[i] = l.HelperTrieReq{ 354 Type: 0, 355 TrieIdx: f.randomX(3), 356 Key: f.randomCHTTrieKey(), 357 FromLevel: uint(f.randomX(3)), 358 AuxReq: uint(2), 359 } 360 case 1: 361 // Bloom trie 362 req.Reqs[i] = l.HelperTrieReq{ 363 Type: 1, 364 TrieIdx: f.randomX(3), 365 Key: f.randomBloomTrieKey(), 366 FromLevel: uint(f.randomX(3)), 367 AuxReq: 0, 368 } 369 default: 370 // Random trie 371 req.Reqs[i] = l.HelperTrieReq{ 372 Type: 2, 373 TrieIdx: f.randomX(3), 374 Key: f.randomCHTTrieKey(), 375 FromLevel: uint(f.randomX(3)), 376 AuxReq: 0, 377 } 378 } 379 } 380 f.doFuzz(l.GetHelperTrieProofsMsg, req) 381 382 case 6: 383 req := &l.SendTxPacket{Txs: make([]*types.Transaction, f.randomInt(l.MaxTxSend+1))} 384 signer := types.HomesteadSigner{} 385 for i := range req.Txs { 386 var nonce uint64 387 if f.randomBool() { 388 nonce = uint64(f.randomByte()) 389 } else { 390 nonce = f.nonce 391 f.nonce += 1 392 } 393 req.Txs[i], _ = types.SignTx(types.NewTransaction(nonce, common.Address{}, big.NewInt(10000), params.TxGas, big.NewInt(1000000000*int64(f.randomByte())), nil), signer, bankKey) 394 } 395 f.doFuzz(l.SendTxV2Msg, req) 396 397 case 7: 398 req := &l.GetTxStatusPacket{Hashes: make([]common.Hash, f.randomInt(l.MaxTxStatus+1))} 399 for i := range req.Hashes { 400 req.Hashes[i] = f.randomTxHash() 401 } 402 f.doFuzz(l.GetTxStatusMsg, req) 403 } 404 } 405 return 0 406 }