github.com/marconiprotocol/go-methereum-lite@v0.0.0-20190918214227-3cd8b06fcf99/consensus/ethash/ethash_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 "io/ioutil" 21 "math/big" 22 "math/rand" 23 "os" 24 "sync" 25 "testing" 26 "time" 27 28 "github.com/MarconiProtocol/go-methereum-lite/common" 29 "github.com/MarconiProtocol/go-methereum-lite/common/hexutil" 30 "github.com/MarconiProtocol/go-methereum-lite/core/types" 31 ) 32 33 // Tests that ethash works correctly in test mode. 34 func TestTestMode(t *testing.T) { 35 header := &types.Header{Number: big.NewInt(1), Difficulty: big.NewInt(100)} 36 37 ethash := NewTester(nil, false) 38 defer ethash.Close() 39 40 results := make(chan *types.Block) 41 err := ethash.Seal(nil, types.NewBlockWithHeader(header), results, nil) 42 if err != nil { 43 t.Fatalf("failed to seal block: %v", err) 44 } 45 select { 46 case block := <-results: 47 header.Nonce = types.EncodeNonce(block.Nonce()) 48 header.MixDigest = block.MixDigest() 49 if err := ethash.VerifySeal(nil, header); err != nil { 50 t.Fatalf("unexpected verification error: %v", err) 51 } 52 case <-time.NewTimer(time.Second).C: 53 t.Error("sealing result timeout") 54 } 55 } 56 57 // Tests that block sealing and seal verification works correctly in 58 // quick test mode. 59 func TestQuickTestMode(t *testing.T) { 60 head := &types.Header{Number: big.NewInt(1), Difficulty: big.NewInt(100)} 61 62 ethash := NewQuickTest(nil, false) 63 defer ethash.Close() 64 65 // Override the randomness used for nonce generation to have a 66 // constant seed, that way this test is deterministic. 67 ethash.rand = rand.New(rand.NewSource(0)) 68 results := make(chan *types.Block) 69 err := ethash.Seal(nil, types.NewBlockWithHeader(head), results, nil) 70 if err != nil { 71 t.Fatalf("failed to seal block: %v", err) 72 } 73 var block *types.Block = nil 74 select { 75 case block = <-results: 76 head.Nonce = types.EncodeNonce(block.Nonce()) 77 head.MixDigest = block.MixDigest() 78 case <-time.NewTimer(time.Second).C: 79 t.Fatalf("sealing result timeout") 80 } 81 82 if err := ethash.VerifySeal(nil, head); err != nil { 83 t.Fatalf("unexpected verification error: %v", err) 84 } 85 // If we change the nonce, verification should now fail. 86 head.Nonce = types.EncodeNonce(block.Nonce() + 1) 87 if err := ethash.VerifySeal(nil, head); err != errInvalidMixDigest { 88 t.Fatalf("expected invalid mix digest but got: %v", err) 89 } 90 // As a sanity check, changing the nonce back should succeed again. 91 head.Nonce = types.EncodeNonce(block.Nonce()) 92 if err := ethash.VerifySeal(nil, head); err != nil { 93 t.Fatalf("unexpected verification error: %v", err) 94 } 95 } 96 97 // Tests that block sealing and seal verification works correctly in 98 // cryptonight mode. 99 func TestCryptonightMode(t *testing.T) { 100 // Note if the difficulty is too high, since cryptonight gets a much 101 // lower hash rate than other algorithms, on slower machines the 102 // test may time out without finding a valid nonce. If that happens, 103 // you can decrease the difficulty or increase the NewTimer's 104 // timeout below. 105 head := &types.Header{Number: big.NewInt(1), Difficulty: big.NewInt(100)} 106 107 ethash := NewCryptonight(nil, false) 108 defer ethash.Close() 109 110 // Override the randomness used for nonce generation to have a 111 // constant seed, that way this test is deterministic. 112 ethash.rand = rand.New(rand.NewSource(0)) 113 results := make(chan *types.Block) 114 err := ethash.Seal(nil, types.NewBlockWithHeader(head), results, nil) 115 if err != nil { 116 t.Fatalf("failed to seal block: %v", err) 117 } 118 var block *types.Block = nil 119 select { 120 case block = <-results: 121 head.Nonce = types.EncodeNonce(block.Nonce()) 122 head.MixDigest = block.MixDigest() 123 case <-time.NewTimer(time.Second * 30).C: 124 t.Fatalf("sealing result timeout") 125 } 126 127 if err := ethash.VerifySeal(nil, head); err != nil { 128 t.Fatalf("unexpected verification error: %v", err) 129 } 130 // If we change the nonce, verification should now fail. 131 head.Nonce = types.EncodeNonce(block.Nonce() + 1) 132 if err := ethash.VerifySeal(nil, head); err != errInvalidMixDigest { 133 t.Fatalf("expected invalid mix digest but got: %v", err) 134 } 135 // As a sanity check, changing the nonce back should succeed again. 136 head.Nonce = types.EncodeNonce(block.Nonce()) 137 if err := ethash.VerifySeal(nil, head); err != nil { 138 t.Fatalf("unexpected verification error: %v", err) 139 } 140 } 141 142 // This test checks that cache lru logic doesn't crash under load. 143 // It reproduces https://github.com/ethereum/go-ethereum/issues/14943 144 func TestCacheFileEvict(t *testing.T) { 145 tmpdir, err := ioutil.TempDir("", "ethash-test") 146 if err != nil { 147 t.Fatal(err) 148 } 149 defer os.RemoveAll(tmpdir) 150 e := New(Config{CachesInMem: 3, CachesOnDisk: 10, CacheDir: tmpdir, PowMode: ModeTest}, nil, false) 151 defer e.Close() 152 153 workers := 8 154 epochs := 100 155 var wg sync.WaitGroup 156 wg.Add(workers) 157 for i := 0; i < workers; i++ { 158 go verifyTest(&wg, e, i, epochs) 159 } 160 wg.Wait() 161 } 162 163 func verifyTest(wg *sync.WaitGroup, e *Ethash, workerIndex, epochs int) { 164 defer wg.Done() 165 166 const wiggle = 4 * epochLength 167 r := rand.New(rand.NewSource(int64(workerIndex))) 168 for epoch := 0; epoch < epochs; epoch++ { 169 block := int64(epoch)*epochLength - wiggle/2 + r.Int63n(wiggle) 170 if block < 0 { 171 block = 0 172 } 173 header := &types.Header{Number: big.NewInt(block), Difficulty: big.NewInt(100)} 174 e.VerifySeal(nil, header) 175 } 176 } 177 178 func TestRemoteSealer(t *testing.T) { 179 ethash := NewTester(nil, false) 180 defer ethash.Close() 181 182 api := &API{ethash} 183 if _, err := api.GetWork(); err != errNoMiningWork { 184 t.Error("expect to return an error indicate there is no mining work") 185 } 186 header := &types.Header{Number: big.NewInt(1), Difficulty: big.NewInt(100)} 187 block := types.NewBlockWithHeader(header) 188 sealhash := ethash.SealHash(header) 189 190 // Push new work. 191 results := make(chan *types.Block) 192 ethash.Seal(nil, block, results, nil) 193 194 var ( 195 work [4]string 196 err error 197 ) 198 if work, err = api.GetWork(); err != nil || work[0] != sealhash.Hex() { 199 t.Error("expect to return a mining work has same hash") 200 } 201 202 if res := api.SubmitWork(types.BlockNonce{}, sealhash, common.Hash{}); res { 203 t.Error("expect to return false when submit a fake solution") 204 } 205 // Push new block with same block number to replace the original one. 206 header = &types.Header{Number: big.NewInt(1), Difficulty: big.NewInt(1000)} 207 block = types.NewBlockWithHeader(header) 208 sealhash = ethash.SealHash(header) 209 ethash.Seal(nil, block, results, nil) 210 211 if work, err = api.GetWork(); err != nil || work[0] != sealhash.Hex() { 212 t.Error("expect to return the latest pushed work") 213 } 214 } 215 216 func TestHashRate(t *testing.T) { 217 var ( 218 hashrate = []hexutil.Uint64{100, 200, 300} 219 expect uint64 220 ids = []common.Hash{common.HexToHash("a"), common.HexToHash("b"), common.HexToHash("c")} 221 ) 222 ethash := NewTester(nil, false) 223 defer ethash.Close() 224 225 if tot := ethash.Hashrate(); tot != 0 { 226 t.Error("expect the result should be zero") 227 } 228 229 api := &API{ethash} 230 for i := 0; i < len(hashrate); i += 1 { 231 if res := api.SubmitHashRate(hashrate[i], ids[i]); !res { 232 t.Error("remote miner submit hashrate failed") 233 } 234 expect += uint64(hashrate[i]) 235 } 236 if tot := ethash.Hashrate(); tot != float64(expect) { 237 t.Error("expect total hashrate should be same") 238 } 239 } 240 241 func TestClosedRemoteSealer(t *testing.T) { 242 ethash := NewTester(nil, false) 243 time.Sleep(1 * time.Second) // ensure exit channel is listening 244 ethash.Close() 245 246 api := &API{ethash} 247 if _, err := api.GetWork(); err != errEthashStopped { 248 t.Error("expect to return an error to indicate ethash is stopped") 249 } 250 251 if res := api.SubmitHashRate(hexutil.Uint64(100), common.HexToHash("a")); res { 252 t.Error("expect to return false when submit hashrate to a stopped ethash") 253 } 254 }