github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/miner/worker_test.go (about) 1 2 //此源码被清华学神尹成大魔王专业翻译分析并修改 3 //尹成QQ77025077 4 //尹成微信18510341407 5 //尹成所在QQ群721929980 6 //尹成邮箱 yinc13@mails.tsinghua.edu.cn 7 //尹成毕业于清华大学,微软区块链领域全球最有价值专家 8 //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620 9 //版权所有2018 Go Ethereum作者 10 //此文件是Go以太坊库的一部分。 11 // 12 //Go-Ethereum库是免费软件:您可以重新分发它和/或修改 13 //根据GNU发布的较低通用公共许可证的条款 14 //自由软件基金会,或者许可证的第3版,或者 15 //(由您选择)任何更高版本。 16 // 17 //Go以太坊图书馆的发行目的是希望它会有用, 18 //但没有任何保证;甚至没有 19 //适销性或特定用途的适用性。见 20 //GNU较低的通用公共许可证,了解更多详细信息。 21 // 22 //你应该收到一份GNU较低级别的公共许可证副本 23 //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。 24 25 package miner 26 27 import ( 28 "math/big" 29 "testing" 30 "time" 31 32 "github.com/ethereum/go-ethereum/common" 33 "github.com/ethereum/go-ethereum/consensus" 34 "github.com/ethereum/go-ethereum/consensus/clique" 35 "github.com/ethereum/go-ethereum/consensus/ethash" 36 "github.com/ethereum/go-ethereum/core" 37 "github.com/ethereum/go-ethereum/core/types" 38 "github.com/ethereum/go-ethereum/core/vm" 39 "github.com/ethereum/go-ethereum/crypto" 40 "github.com/ethereum/go-ethereum/ethdb" 41 "github.com/ethereum/go-ethereum/event" 42 "github.com/ethereum/go-ethereum/params" 43 ) 44 45 var ( 46 //测试链配置 47 testTxPoolConfig core.TxPoolConfig 48 ethashChainConfig *params.ChainConfig 49 cliqueChainConfig *params.ChainConfig 50 51 //测试帐目 52 testBankKey, _ = crypto.GenerateKey() 53 testBankAddress = crypto.PubkeyToAddress(testBankKey.PublicKey) 54 testBankFunds = big.NewInt(1000000000000000000) 55 56 acc1Key, _ = crypto.GenerateKey() 57 acc1Addr = crypto.PubkeyToAddress(acc1Key.PublicKey) 58 59 //测试事务 60 pendingTxs []*types.Transaction 61 newTxs []*types.Transaction 62 ) 63 64 func init() { 65 testTxPoolConfig = core.DefaultTxPoolConfig 66 testTxPoolConfig.Journal = "" 67 ethashChainConfig = params.TestChainConfig 68 cliqueChainConfig = params.TestChainConfig 69 cliqueChainConfig.Clique = ¶ms.CliqueConfig{ 70 Period: 10, 71 Epoch: 30000, 72 } 73 tx1, _ := types.SignTx(types.NewTransaction(0, acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), types.HomesteadSigner{}, testBankKey) 74 pendingTxs = append(pendingTxs, tx1) 75 tx2, _ := types.SignTx(types.NewTransaction(1, acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), types.HomesteadSigner{}, testBankKey) 76 newTxs = append(newTxs, tx2) 77 } 78 79 //TestWorkerBackend实现worker.backend接口,并包装测试期间所需的所有信息。 80 type testWorkerBackend struct { 81 db ethdb.Database 82 txPool *core.TxPool 83 chain *core.BlockChain 84 testTxFeed event.Feed 85 uncleBlock *types.Block 86 } 87 88 func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) *testWorkerBackend { 89 var ( 90 db = ethdb.NewMemDatabase() 91 gspec = core.Genesis{ 92 Config: chainConfig, 93 Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}, 94 } 95 ) 96 97 switch engine.(type) { 98 case *clique.Clique: 99 gspec.ExtraData = make([]byte, 32+common.AddressLength+65) 100 copy(gspec.ExtraData[32:], testBankAddress[:]) 101 case *ethash.Ethash: 102 default: 103 t.Fatal("unexpect consensus engine type") 104 } 105 genesis := gspec.MustCommit(db) 106 107 chain, _ := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}) 108 txpool := core.NewTxPool(testTxPoolConfig, chainConfig, chain) 109 blocks, _ := core.GenerateChain(chainConfig, genesis, engine, db, 1, func(i int, gen *core.BlockGen) { 110 gen.SetCoinbase(acc1Addr) 111 }) 112 113 return &testWorkerBackend{ 114 db: db, 115 chain: chain, 116 txPool: txpool, 117 uncleBlock: blocks[0], 118 } 119 } 120 121 func (b *testWorkerBackend) BlockChain() *core.BlockChain { return b.chain } 122 func (b *testWorkerBackend) TxPool() *core.TxPool { return b.txPool } 123 func (b *testWorkerBackend) PostChainEvents(events []interface{}) { 124 b.chain.PostChainEvents(events, nil) 125 } 126 127 func newTestWorker(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) (*worker, *testWorkerBackend) { 128 backend := newTestWorkerBackend(t, chainConfig, engine) 129 backend.txPool.AddLocals(pendingTxs) 130 w := newWorker(chainConfig, engine, backend, new(event.TypeMux), time.Second) 131 w.setEtherbase(testBankAddress) 132 return w, backend 133 } 134 135 func TestPendingStateAndBlockEthash(t *testing.T) { 136 testPendingStateAndBlock(t, ethashChainConfig, ethash.NewFaker()) 137 } 138 func TestPendingStateAndBlockClique(t *testing.T) { 139 testPendingStateAndBlock(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, ethdb.NewMemDatabase())) 140 } 141 142 func testPendingStateAndBlock(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) { 143 defer engine.Close() 144 145 w, b := newTestWorker(t, chainConfig, engine) 146 defer w.close() 147 148 //确保快照已更新。 149 time.Sleep(100 * time.Millisecond) 150 block, state := w.pending() 151 if block.NumberU64() != 1 { 152 t.Errorf("block number mismatch, has %d, want %d", block.NumberU64(), 1) 153 } 154 if balance := state.GetBalance(acc1Addr); balance.Cmp(big.NewInt(1000)) != 0 { 155 t.Errorf("account balance mismatch, has %d, want %d", balance, 1000) 156 } 157 b.txPool.AddLocals(newTxs) 158 //确保已处理新的Tx事件 159 time.Sleep(100 * time.Millisecond) 160 block, state = w.pending() 161 if balance := state.GetBalance(acc1Addr); balance.Cmp(big.NewInt(2000)) != 0 { 162 t.Errorf("account balance mismatch, has %d, want %d", balance, 2000) 163 } 164 } 165 166 func TestEmptyWorkEthash(t *testing.T) { 167 testEmptyWork(t, ethashChainConfig, ethash.NewFaker()) 168 } 169 func TestEmptyWorkClique(t *testing.T) { 170 testEmptyWork(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, ethdb.NewMemDatabase())) 171 } 172 173 func testEmptyWork(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) { 174 defer engine.Close() 175 176 w, _ := newTestWorker(t, chainConfig, engine) 177 defer w.close() 178 179 var ( 180 taskCh = make(chan struct{}, 2) 181 taskIndex int 182 ) 183 184 checkEqual := func(t *testing.T, task *task, index int) { 185 receiptLen, balance := 0, big.NewInt(0) 186 if index == 1 { 187 receiptLen, balance = 1, big.NewInt(1000) 188 } 189 if len(task.receipts) != receiptLen { 190 t.Errorf("receipt number mismatch has %d, want %d", len(task.receipts), receiptLen) 191 } 192 if task.state.GetBalance(acc1Addr).Cmp(balance) != 0 { 193 t.Errorf("account balance mismatch has %d, want %d", task.state.GetBalance(acc1Addr), balance) 194 } 195 } 196 197 w.newTaskHook = func(task *task) { 198 if task.block.NumberU64() == 1 { 199 checkEqual(t, task, taskIndex) 200 taskIndex += 1 201 taskCh <- struct{}{} 202 } 203 } 204 w.fullTaskHook = func() { 205 time.Sleep(100 * time.Millisecond) 206 } 207 208 //确保工作进程已完成初始化 209 for { 210 b := w.pendingBlock() 211 if b != nil && b.NumberU64() == 1 { 212 break 213 } 214 } 215 216 w.start() 217 for i := 0; i < 2; i += 1 { 218 select { 219 case <-taskCh: 220 case <-time.NewTimer(time.Second).C: 221 t.Error("new task timeout") 222 } 223 } 224 } 225 226 func TestStreamUncleBlock(t *testing.T) { 227 ethash := ethash.NewFaker() 228 defer ethash.Close() 229 230 w, b := newTestWorker(t, ethashChainConfig, ethash) 231 defer w.close() 232 233 var taskCh = make(chan struct{}) 234 235 taskIndex := 0 236 w.newTaskHook = func(task *task) { 237 if task.block.NumberU64() == 1 { 238 if taskIndex == 2 { 239 has := task.block.Header().UncleHash 240 want := types.CalcUncleHash([]*types.Header{b.uncleBlock.Header()}) 241 if has != want { 242 t.Errorf("uncle hash mismatch, has %s, want %s", has.Hex(), want.Hex()) 243 } 244 } 245 taskCh <- struct{}{} 246 taskIndex += 1 247 } 248 } 249 w.skipSealHook = func(task *task) bool { 250 return true 251 } 252 w.fullTaskHook = func() { 253 time.Sleep(100 * time.Millisecond) 254 } 255 256 //确保工作进程已完成初始化 257 for { 258 b := w.pendingBlock() 259 if b != nil && b.NumberU64() == 1 { 260 break 261 } 262 } 263 264 w.start() 265 //忽略前两个作品 266 for i := 0; i < 2; i += 1 { 267 select { 268 case <-taskCh: 269 case <-time.NewTimer(time.Second).C: 270 t.Error("new task timeout") 271 } 272 } 273 b.PostChainEvents([]interface{}{core.ChainSideEvent{Block: b.uncleBlock}}) 274 275 select { 276 case <-taskCh: 277 case <-time.NewTimer(time.Second).C: 278 t.Error("new task timeout") 279 } 280 } 281 282 func TestRegenerateMiningBlockEthash(t *testing.T) { 283 testRegenerateMiningBlock(t, ethashChainConfig, ethash.NewFaker()) 284 } 285 286 func TestRegenerateMiningBlockClique(t *testing.T) { 287 testRegenerateMiningBlock(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, ethdb.NewMemDatabase())) 288 } 289 290 func testRegenerateMiningBlock(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) { 291 defer engine.Close() 292 293 w, b := newTestWorker(t, chainConfig, engine) 294 defer w.close() 295 296 var taskCh = make(chan struct{}) 297 298 taskIndex := 0 299 w.newTaskHook = func(task *task) { 300 if task.block.NumberU64() == 1 { 301 if taskIndex == 2 { 302 receiptLen, balance := 2, big.NewInt(2000) 303 if len(task.receipts) != receiptLen { 304 t.Errorf("receipt number mismatch has %d, want %d", len(task.receipts), receiptLen) 305 } 306 if task.state.GetBalance(acc1Addr).Cmp(balance) != 0 { 307 t.Errorf("account balance mismatch has %d, want %d", task.state.GetBalance(acc1Addr), balance) 308 } 309 } 310 taskCh <- struct{}{} 311 taskIndex += 1 312 } 313 } 314 w.skipSealHook = func(task *task) bool { 315 return true 316 } 317 w.fullTaskHook = func() { 318 time.Sleep(100 * time.Millisecond) 319 } 320 //确保工作进程已完成初始化 321 for { 322 b := w.pendingBlock() 323 if b != nil && b.NumberU64() == 1 { 324 break 325 } 326 } 327 328 w.start() 329 //忽略前两个作品 330 for i := 0; i < 2; i += 1 { 331 select { 332 case <-taskCh: 333 case <-time.NewTimer(time.Second).C: 334 t.Error("new task timeout") 335 } 336 } 337 b.txPool.AddLocals(newTxs) 338 time.Sleep(time.Second) 339 340 select { 341 case <-taskCh: 342 case <-time.NewTimer(time.Second).C: 343 t.Error("new task timeout") 344 } 345 } 346 347 func TestAdjustIntervalEthash(t *testing.T) { 348 testAdjustInterval(t, ethashChainConfig, ethash.NewFaker()) 349 } 350 351 func TestAdjustIntervalClique(t *testing.T) { 352 testAdjustInterval(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, ethdb.NewMemDatabase())) 353 } 354 355 func testAdjustInterval(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) { 356 defer engine.Close() 357 358 w, _ := newTestWorker(t, chainConfig, engine) 359 defer w.close() 360 361 w.skipSealHook = func(task *task) bool { 362 return true 363 } 364 w.fullTaskHook = func() { 365 time.Sleep(100 * time.Millisecond) 366 } 367 var ( 368 progress = make(chan struct{}, 10) 369 result = make([]float64, 0, 10) 370 index = 0 371 start = false 372 ) 373 w.resubmitHook = func(minInterval time.Duration, recommitInterval time.Duration) { 374 //如果间隔检查未开始,则短路。 375 if !start { 376 return 377 } 378 var wantMinInterval, wantRecommitInterval time.Duration 379 380 switch index { 381 case 0: 382 wantMinInterval, wantRecommitInterval = 3*time.Second, 3*time.Second 383 case 1: 384 origin := float64(3 * time.Second.Nanoseconds()) 385 estimate := origin*(1-intervalAdjustRatio) + intervalAdjustRatio*(origin/0.8+intervalAdjustBias) 386 wantMinInterval, wantRecommitInterval = 3*time.Second, time.Duration(int(estimate))*time.Nanosecond 387 case 2: 388 estimate := result[index-1] 389 min := float64(3 * time.Second.Nanoseconds()) 390 estimate = estimate*(1-intervalAdjustRatio) + intervalAdjustRatio*(min-intervalAdjustBias) 391 wantMinInterval, wantRecommitInterval = 3*time.Second, time.Duration(int(estimate))*time.Nanosecond 392 case 3: 393 wantMinInterval, wantRecommitInterval = time.Second, time.Second 394 } 395 396 //检查间隔 397 if minInterval != wantMinInterval { 398 t.Errorf("resubmit min interval mismatch want %s has %s", wantMinInterval, minInterval) 399 } 400 if recommitInterval != wantRecommitInterval { 401 t.Errorf("resubmit interval mismatch want %s has %s", wantRecommitInterval, recommitInterval) 402 } 403 result = append(result, float64(recommitInterval.Nanoseconds())) 404 index += 1 405 progress <- struct{}{} 406 } 407 //确保工作进程已完成初始化 408 for { 409 b := w.pendingBlock() 410 if b != nil && b.NumberU64() == 1 { 411 break 412 } 413 } 414 415 w.start() 416 417 time.Sleep(time.Second) 418 419 start = true 420 w.setRecommitInterval(3 * time.Second) 421 select { 422 case <-progress: 423 case <-time.NewTimer(time.Second).C: 424 t.Error("interval reset timeout") 425 } 426 427 w.resubmitAdjustCh <- &intervalAdjust{inc: true, ratio: 0.8} 428 select { 429 case <-progress: 430 case <-time.NewTimer(time.Second).C: 431 t.Error("interval reset timeout") 432 } 433 434 w.resubmitAdjustCh <- &intervalAdjust{inc: false} 435 select { 436 case <-progress: 437 case <-time.NewTimer(time.Second).C: 438 t.Error("interval reset timeout") 439 } 440 441 w.setRecommitInterval(500 * time.Millisecond) 442 select { 443 case <-progress: 444 case <-time.NewTimer(time.Second).C: 445 t.Error("interval reset timeout") 446 } 447 }