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