github.com/ethereum/go-ethereum@v1.14.3/consensus/ethash/consensus_test.go (about) 1 // Copyright 2017 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 ethash 18 19 import ( 20 crand "crypto/rand" 21 "encoding/binary" 22 "encoding/json" 23 "math/big" 24 "math/rand" 25 "os" 26 "path/filepath" 27 "testing" 28 29 "github.com/ethereum/go-ethereum/common" 30 "github.com/ethereum/go-ethereum/common/math" 31 "github.com/ethereum/go-ethereum/core/types" 32 "github.com/ethereum/go-ethereum/params" 33 ) 34 35 type diffTest struct { 36 ParentTimestamp uint64 37 ParentDifficulty *big.Int 38 CurrentTimestamp uint64 39 CurrentBlocknumber *big.Int 40 CurrentDifficulty *big.Int 41 } 42 43 func (d *diffTest) UnmarshalJSON(b []byte) (err error) { 44 var ext struct { 45 ParentTimestamp string 46 ParentDifficulty string 47 CurrentTimestamp string 48 CurrentBlocknumber string 49 CurrentDifficulty string 50 } 51 if err := json.Unmarshal(b, &ext); err != nil { 52 return err 53 } 54 55 d.ParentTimestamp = math.MustParseUint64(ext.ParentTimestamp) 56 d.ParentDifficulty = math.MustParseBig256(ext.ParentDifficulty) 57 d.CurrentTimestamp = math.MustParseUint64(ext.CurrentTimestamp) 58 d.CurrentBlocknumber = math.MustParseBig256(ext.CurrentBlocknumber) 59 d.CurrentDifficulty = math.MustParseBig256(ext.CurrentDifficulty) 60 61 return nil 62 } 63 64 func TestCalcDifficulty(t *testing.T) { 65 file, err := os.Open(filepath.Join("..", "..", "tests", "testdata", "BasicTests", "difficulty.json")) 66 if err != nil { 67 t.Skip(err) 68 } 69 defer file.Close() 70 71 tests := make(map[string]diffTest) 72 err = json.NewDecoder(file).Decode(&tests) 73 if err != nil { 74 t.Fatal(err) 75 } 76 77 config := ¶ms.ChainConfig{HomesteadBlock: big.NewInt(1150000)} 78 79 for name, test := range tests { 80 number := new(big.Int).Sub(test.CurrentBlocknumber, big.NewInt(1)) 81 diff := CalcDifficulty(config, test.CurrentTimestamp, &types.Header{ 82 Number: number, 83 Time: test.ParentTimestamp, 84 Difficulty: test.ParentDifficulty, 85 }) 86 if diff.Cmp(test.CurrentDifficulty) != 0 { 87 t.Error(name, "failed. Expected", test.CurrentDifficulty, "and calculated", diff) 88 } 89 } 90 } 91 92 func randSlice(min, max uint32) []byte { 93 var b = make([]byte, 4) 94 crand.Read(b) 95 a := binary.LittleEndian.Uint32(b) 96 size := min + a%(max-min) 97 out := make([]byte, size) 98 crand.Read(out) 99 return out 100 } 101 102 func TestDifficultyCalculators(t *testing.T) { 103 for i := 0; i < 5000; i++ { 104 // 1 to 300 seconds diff 105 var timeDelta = uint64(1 + rand.Uint32()%3000) 106 diffBig := new(big.Int).SetBytes(randSlice(2, 10)) 107 if diffBig.Cmp(params.MinimumDifficulty) < 0 { 108 diffBig.Set(params.MinimumDifficulty) 109 } 110 //rand.Read(difficulty) 111 header := &types.Header{ 112 Difficulty: diffBig, 113 Number: new(big.Int).SetUint64(rand.Uint64() % 50_000_000), 114 Time: rand.Uint64() - timeDelta, 115 } 116 if rand.Uint32()&1 == 0 { 117 header.UncleHash = types.EmptyUncleHash 118 } 119 bombDelay := new(big.Int).SetUint64(rand.Uint64() % 50_000_000) 120 for i, pair := range []struct { 121 bigFn func(time uint64, parent *types.Header) *big.Int 122 u256Fn func(time uint64, parent *types.Header) *big.Int 123 }{ 124 {FrontierDifficultyCalculator, CalcDifficultyFrontierU256}, 125 {HomesteadDifficultyCalculator, CalcDifficultyHomesteadU256}, 126 {DynamicDifficultyCalculator(bombDelay), MakeDifficultyCalculatorU256(bombDelay)}, 127 } { 128 time := header.Time + timeDelta 129 want := pair.bigFn(time, header) 130 have := pair.u256Fn(time, header) 131 if want.BitLen() > 256 { 132 continue 133 } 134 if want.Cmp(have) != 0 { 135 t.Fatalf("pair %d: want %x have %x\nparent.Number: %x\np.Time: %x\nc.Time: %x\nBombdelay: %v\n", i, want, have, 136 header.Number, header.Time, time, bombDelay) 137 } 138 } 139 } 140 } 141 142 func BenchmarkDifficultyCalculator(b *testing.B) { 143 x1 := makeDifficultyCalculator(big.NewInt(1000000)) 144 x2 := MakeDifficultyCalculatorU256(big.NewInt(1000000)) 145 h := &types.Header{ 146 ParentHash: common.Hash{}, 147 UncleHash: types.EmptyUncleHash, 148 Difficulty: big.NewInt(0xffffff), 149 Number: big.NewInt(500000), 150 Time: 1000000, 151 } 152 b.Run("big-frontier", func(b *testing.B) { 153 b.ReportAllocs() 154 for i := 0; i < b.N; i++ { 155 calcDifficultyFrontier(1000014, h) 156 } 157 }) 158 b.Run("u256-frontier", func(b *testing.B) { 159 b.ReportAllocs() 160 for i := 0; i < b.N; i++ { 161 CalcDifficultyFrontierU256(1000014, h) 162 } 163 }) 164 b.Run("big-homestead", func(b *testing.B) { 165 b.ReportAllocs() 166 for i := 0; i < b.N; i++ { 167 calcDifficultyHomestead(1000014, h) 168 } 169 }) 170 b.Run("u256-homestead", func(b *testing.B) { 171 b.ReportAllocs() 172 for i := 0; i < b.N; i++ { 173 CalcDifficultyHomesteadU256(1000014, h) 174 } 175 }) 176 b.Run("big-generic", func(b *testing.B) { 177 b.ReportAllocs() 178 for i := 0; i < b.N; i++ { 179 x1(1000014, h) 180 } 181 }) 182 b.Run("u256-generic", func(b *testing.B) { 183 b.ReportAllocs() 184 for i := 0; i < b.N; i++ { 185 x2(1000014, h) 186 } 187 }) 188 }