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