github.com/kisexp/xdchain@v0.0.0-20211206025815-490d6b732aa7/consensus/ethash/sealer_test.go (about) 1 // Copyright 2018 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 "encoding/json" 21 "io/ioutil" 22 "math/big" 23 "net/http" 24 "net/http/httptest" 25 "testing" 26 "time" 27 28 "github.com/kisexp/xdchain/common" 29 "github.com/kisexp/xdchain/core/types" 30 "github.com/kisexp/xdchain/internal/testlog" 31 "github.com/kisexp/xdchain/log" 32 ) 33 34 // Tests whether remote HTTP servers are correctly notified of new work. 35 func TestRemoteNotify(t *testing.T) { 36 // Start a simple web server to capture notifications. 37 sink := make(chan [3]string) 38 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { 39 blob, err := ioutil.ReadAll(req.Body) 40 if err != nil { 41 t.Errorf("failed to read miner notification: %v", err) 42 } 43 var work [3]string 44 if err := json.Unmarshal(blob, &work); err != nil { 45 t.Errorf("failed to unmarshal miner notification: %v", err) 46 } 47 sink <- work 48 })) 49 defer server.Close() 50 51 // Create the custom ethash engine. 52 ethash := NewTester([]string{server.URL}, false) 53 defer ethash.Close() 54 55 // Stream a work task and ensure the notification bubbles out. 56 header := &types.Header{Number: big.NewInt(1), Difficulty: big.NewInt(100)} 57 block := types.NewBlockWithHeader(header) 58 59 ethash.Seal(nil, block, nil, nil) 60 select { 61 case work := <-sink: 62 if want := ethash.SealHash(header).Hex(); work[0] != want { 63 t.Errorf("work packet hash mismatch: have %s, want %s", work[0], want) 64 } 65 if want := common.BytesToHash(SeedHash(header.Number.Uint64())).Hex(); work[1] != want { 66 t.Errorf("work packet seed mismatch: have %s, want %s", work[1], want) 67 } 68 target := new(big.Int).Div(new(big.Int).Lsh(big.NewInt(1), 256), header.Difficulty) 69 if want := common.BytesToHash(target.Bytes()).Hex(); work[2] != want { 70 t.Errorf("work packet target mismatch: have %s, want %s", work[2], want) 71 } 72 case <-time.After(3 * time.Second): 73 t.Fatalf("notification timed out") 74 } 75 } 76 77 // Tests that pushing work packages fast to the miner doesn't cause any data race 78 // issues in the notifications. 79 func TestRemoteMultiNotify(t *testing.T) { 80 // Start a simple web server to capture notifications. 81 sink := make(chan [3]string, 64) 82 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { 83 blob, err := ioutil.ReadAll(req.Body) 84 if err != nil { 85 t.Errorf("failed to read miner notification: %v", err) 86 } 87 var work [3]string 88 if err := json.Unmarshal(blob, &work); err != nil { 89 t.Errorf("failed to unmarshal miner notification: %v", err) 90 } 91 sink <- work 92 })) 93 defer server.Close() 94 95 // Create the custom ethash engine. 96 ethash := NewTester([]string{server.URL}, false) 97 ethash.config.Log = testlog.Logger(t, log.LvlWarn) 98 defer ethash.Close() 99 100 // Provide a results reader. 101 // Otherwise the unread results will be logged asynchronously 102 // and this can happen after the test is finished, causing a panic. 103 results := make(chan *types.Block, cap(sink)) 104 105 // Stream a lot of work task and ensure all the notifications bubble out. 106 for i := 0; i < cap(sink); i++ { 107 header := &types.Header{Number: big.NewInt(int64(i)), Difficulty: big.NewInt(100)} 108 block := types.NewBlockWithHeader(header) 109 ethash.Seal(nil, block, results, nil) 110 } 111 112 for i := 0; i < cap(sink); i++ { 113 select { 114 case <-sink: 115 <-results 116 case <-time.After(10 * time.Second): 117 t.Fatalf("notification %d timed out", i) 118 } 119 } 120 } 121 122 // Tests whether stale solutions are correctly processed. 123 func TestStaleSubmission(t *testing.T) { 124 ethash := NewTester(nil, true) 125 defer ethash.Close() 126 api := &API{ethash} 127 128 fakeNonce, fakeDigest := types.BlockNonce{0x01, 0x02, 0x03}, common.HexToHash("deadbeef") 129 130 testcases := []struct { 131 headers []*types.Header 132 submitIndex int 133 submitRes bool 134 }{ 135 // Case1: submit solution for the latest mining package 136 { 137 []*types.Header{ 138 {ParentHash: common.BytesToHash([]byte{0xa}), Number: big.NewInt(1), Difficulty: big.NewInt(100000000)}, 139 }, 140 0, 141 true, 142 }, 143 // Case2: submit solution for the previous package but have same parent. 144 { 145 []*types.Header{ 146 {ParentHash: common.BytesToHash([]byte{0xb}), Number: big.NewInt(2), Difficulty: big.NewInt(100000000)}, 147 {ParentHash: common.BytesToHash([]byte{0xb}), Number: big.NewInt(2), Difficulty: big.NewInt(100000001)}, 148 }, 149 0, 150 true, 151 }, 152 // Case3: submit stale but acceptable solution 153 { 154 []*types.Header{ 155 {ParentHash: common.BytesToHash([]byte{0xc}), Number: big.NewInt(3), Difficulty: big.NewInt(100000000)}, 156 {ParentHash: common.BytesToHash([]byte{0xd}), Number: big.NewInt(9), Difficulty: big.NewInt(100000000)}, 157 }, 158 0, 159 true, 160 }, 161 // Case4: submit very old solution 162 { 163 []*types.Header{ 164 {ParentHash: common.BytesToHash([]byte{0xe}), Number: big.NewInt(10), Difficulty: big.NewInt(100000000)}, 165 {ParentHash: common.BytesToHash([]byte{0xf}), Number: big.NewInt(17), Difficulty: big.NewInt(100000000)}, 166 }, 167 0, 168 false, 169 }, 170 } 171 results := make(chan *types.Block, 16) 172 173 for id, c := range testcases { 174 for _, h := range c.headers { 175 ethash.Seal(nil, types.NewBlockWithHeader(h), results, nil) 176 } 177 if res := api.SubmitWork(fakeNonce, ethash.SealHash(c.headers[c.submitIndex]), fakeDigest); res != c.submitRes { 178 t.Errorf("case %d submit result mismatch, want %t, get %t", id+1, c.submitRes, res) 179 } 180 if !c.submitRes { 181 continue 182 } 183 select { 184 case res := <-results: 185 if res.Header().Nonce != fakeNonce { 186 t.Errorf("case %d block nonce mismatch, want %x, get %x", id+1, fakeNonce, res.Header().Nonce) 187 } 188 if res.Header().MixDigest != fakeDigest { 189 t.Errorf("case %d block digest mismatch, want %x, get %x", id+1, fakeDigest, res.Header().MixDigest) 190 } 191 if res.Header().Difficulty.Uint64() != c.headers[c.submitIndex].Difficulty.Uint64() { 192 t.Errorf("case %d block difficulty mismatch, want %d, get %d", id+1, c.headers[c.submitIndex].Difficulty, res.Header().Difficulty) 193 } 194 if res.Header().Number.Uint64() != c.headers[c.submitIndex].Number.Uint64() { 195 t.Errorf("case %d block number mismatch, want %d, get %d", id+1, c.headers[c.submitIndex].Number.Uint64(), res.Header().Number.Uint64()) 196 } 197 if res.Header().ParentHash != c.headers[c.submitIndex].ParentHash { 198 t.Errorf("case %d block parent hash mismatch, want %s, get %s", id+1, c.headers[c.submitIndex].ParentHash.Hex(), res.Header().ParentHash.Hex()) 199 } 200 case <-time.NewTimer(time.Second).C: 201 t.Errorf("case %d fetch ethash result timeout", id+1) 202 } 203 } 204 }