github.com/haliliceylan/bsc@v1.1.10-0.20220501224556-eb78d644ebcb/tests/fuzzers/difficulty/difficulty-fuzz.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 difficulty 18 19 import ( 20 "bytes" 21 "encoding/binary" 22 "fmt" 23 "io" 24 "math/big" 25 26 "github.com/ethereum/go-ethereum/consensus/ethash" 27 "github.com/ethereum/go-ethereum/core/types" 28 ) 29 30 type fuzzer struct { 31 input io.Reader 32 exhausted bool 33 debugging bool 34 } 35 36 func (f *fuzzer) read(size int) []byte { 37 out := make([]byte, size) 38 if _, err := f.input.Read(out); err != nil { 39 f.exhausted = true 40 } 41 return out 42 } 43 44 func (f *fuzzer) readSlice(min, max int) []byte { 45 var a uint16 46 binary.Read(f.input, binary.LittleEndian, &a) 47 size := min + int(a)%(max-min) 48 out := make([]byte, size) 49 if _, err := f.input.Read(out); err != nil { 50 f.exhausted = true 51 } 52 return out 53 } 54 55 func (f *fuzzer) readUint64(min, max uint64) uint64 { 56 if min == max { 57 return min 58 } 59 var a uint64 60 if err := binary.Read(f.input, binary.LittleEndian, &a); err != nil { 61 f.exhausted = true 62 } 63 a = min + a%(max-min) 64 return a 65 } 66 func (f *fuzzer) readBool() bool { 67 return f.read(1)[0]&0x1 == 0 68 } 69 70 // The function must return 71 // 1 if the fuzzer should increase priority of the 72 // given input during subsequent fuzzing (for example, the input is lexically 73 // correct and was parsed successfully); 74 // -1 if the input must not be added to corpus even if gives new coverage; and 75 // 0 otherwise 76 // other values are reserved for future use. 77 func Fuzz(data []byte) int { 78 f := fuzzer{ 79 input: bytes.NewReader(data), 80 exhausted: false, 81 } 82 return f.fuzz() 83 } 84 85 var minDifficulty = big.NewInt(0x2000) 86 87 type calculator func(time uint64, parent *types.Header) *big.Int 88 89 func (f *fuzzer) fuzz() int { 90 // A parent header 91 header := &types.Header{} 92 if f.readBool() { 93 header.UncleHash = types.EmptyUncleHash 94 } 95 // Difficulty can range between 0x2000 (2 bytes) and up to 32 bytes 96 { 97 diff := new(big.Int).SetBytes(f.readSlice(2, 32)) 98 if diff.Cmp(minDifficulty) < 0 { 99 diff.Set(minDifficulty) 100 } 101 header.Difficulty = diff 102 } 103 // Number can range between 0 and up to 32 bytes (but not so that the child exceeds it) 104 { 105 // However, if we use astronomic numbers, then the bomb exp karatsuba calculation 106 // in the legacy methods) 107 // times out, so we limit it to fit within reasonable bounds 108 number := new(big.Int).SetBytes(f.readSlice(0, 4)) // 4 bytes: 32 bits: block num max 4 billion 109 header.Number = number 110 } 111 // Both parent and child time must fit within uint64 112 var time uint64 113 { 114 childTime := f.readUint64(1, 0xFFFFFFFFFFFFFFFF) 115 //fmt.Printf("childTime: %x\n",childTime) 116 delta := f.readUint64(1, childTime) 117 //fmt.Printf("delta: %v\n", delta) 118 pTime := childTime - delta 119 header.Time = pTime 120 time = childTime 121 } 122 // Bomb delay will never exceed uint64 123 bombDelay := new(big.Int).SetUint64(f.readUint64(1, 0xFFFFFFFFFFFFFFFe)) 124 125 if f.exhausted { 126 return 0 127 } 128 129 for i, pair := range []struct { 130 bigFn calculator 131 u256Fn calculator 132 }{ 133 {ethash.FrontierDifficultyCalulator, ethash.CalcDifficultyFrontierU256}, 134 {ethash.HomesteadDifficultyCalulator, ethash.CalcDifficultyHomesteadU256}, 135 {ethash.DynamicDifficultyCalculator(bombDelay), ethash.MakeDifficultyCalculatorU256(bombDelay)}, 136 } { 137 want := pair.bigFn(time, header) 138 have := pair.u256Fn(time, header) 139 if want.Cmp(have) != 0 { 140 panic(fmt.Sprintf("pair %d: want %x have %x\nparent.Number: %x\np.Time: %x\nc.Time: %x\nBombdelay: %v\n", i, want, have, 141 header.Number, header.Time, time, bombDelay)) 142 } 143 } 144 return 1 145 }