github.com/codysnider/go-ethereum@v1.10.18-0.20220420071915-14f4ae99222a/miner/worker_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 miner 18 19 import ( 20 "errors" 21 "math/big" 22 "math/rand" 23 "sync/atomic" 24 "testing" 25 "time" 26 27 "github.com/ethereum/go-ethereum/accounts" 28 "github.com/ethereum/go-ethereum/common" 29 "github.com/ethereum/go-ethereum/consensus" 30 "github.com/ethereum/go-ethereum/consensus/clique" 31 "github.com/ethereum/go-ethereum/consensus/ethash" 32 "github.com/ethereum/go-ethereum/core" 33 "github.com/ethereum/go-ethereum/core/rawdb" 34 "github.com/ethereum/go-ethereum/core/state" 35 "github.com/ethereum/go-ethereum/core/types" 36 "github.com/ethereum/go-ethereum/core/vm" 37 "github.com/ethereum/go-ethereum/crypto" 38 "github.com/ethereum/go-ethereum/ethdb" 39 "github.com/ethereum/go-ethereum/event" 40 "github.com/ethereum/go-ethereum/params" 41 ) 42 43 const ( 44 // testCode is the testing contract binary code which will initialises some 45 // variables in constructor 46 testCode = "0x60806040527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0060005534801561003457600080fd5b5060fc806100436000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c80630c4dae8814603757806398a213cf146053575b600080fd5b603d607e565b6040518082815260200191505060405180910390f35b607c60048036036020811015606757600080fd5b81019080803590602001909291905050506084565b005b60005481565b806000819055507fe9e44f9f7da8c559de847a3232b57364adc0354f15a2cd8dc636d54396f9587a6000546040518082815260200191505060405180910390a15056fea265627a7a723058208ae31d9424f2d0bc2a3da1a5dd659db2d71ec322a17db8f87e19e209e3a1ff4a64736f6c634300050a0032" 47 48 // testGas is the gas required for contract deployment. 49 testGas = 144109 50 ) 51 52 var ( 53 // Test chain configurations 54 testTxPoolConfig core.TxPoolConfig 55 ethashChainConfig *params.ChainConfig 56 cliqueChainConfig *params.ChainConfig 57 58 // Test accounts 59 testBankKey, _ = crypto.GenerateKey() 60 testBankAddress = crypto.PubkeyToAddress(testBankKey.PublicKey) 61 testBankFunds = big.NewInt(1000000000000000000) 62 63 testUserKey, _ = crypto.GenerateKey() 64 testUserAddress = crypto.PubkeyToAddress(testUserKey.PublicKey) 65 66 // Test transactions 67 pendingTxs []*types.Transaction 68 newTxs []*types.Transaction 69 70 testConfig = &Config{ 71 Recommit: time.Second, 72 GasCeil: params.GenesisGasLimit, 73 } 74 ) 75 76 func init() { 77 testTxPoolConfig = core.DefaultTxPoolConfig 78 testTxPoolConfig.Journal = "" 79 ethashChainConfig = new(params.ChainConfig) 80 *ethashChainConfig = *params.TestChainConfig 81 cliqueChainConfig = new(params.ChainConfig) 82 *cliqueChainConfig = *params.TestChainConfig 83 cliqueChainConfig.Clique = ¶ms.CliqueConfig{ 84 Period: 10, 85 Epoch: 30000, 86 } 87 88 signer := types.LatestSigner(params.TestChainConfig) 89 tx1 := types.MustSignNewTx(testBankKey, signer, &types.AccessListTx{ 90 ChainID: params.TestChainConfig.ChainID, 91 Nonce: 0, 92 To: &testUserAddress, 93 Value: big.NewInt(1000), 94 Gas: params.TxGas, 95 GasPrice: big.NewInt(params.InitialBaseFee), 96 }) 97 pendingTxs = append(pendingTxs, tx1) 98 99 tx2 := types.MustSignNewTx(testBankKey, signer, &types.LegacyTx{ 100 Nonce: 1, 101 To: &testUserAddress, 102 Value: big.NewInt(1000), 103 Gas: params.TxGas, 104 GasPrice: big.NewInt(params.InitialBaseFee), 105 }) 106 newTxs = append(newTxs, tx2) 107 108 rand.Seed(time.Now().UnixNano()) 109 } 110 111 // testWorkerBackend implements worker.Backend interfaces and wraps all information needed during the testing. 112 type testWorkerBackend struct { 113 db ethdb.Database 114 txPool *core.TxPool 115 chain *core.BlockChain 116 testTxFeed event.Feed 117 genesis *core.Genesis 118 uncleBlock *types.Block 119 } 120 121 func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, db ethdb.Database, n int) *testWorkerBackend { 122 var gspec = core.Genesis{ 123 Config: chainConfig, 124 Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}, 125 } 126 127 switch e := engine.(type) { 128 case *clique.Clique: 129 gspec.ExtraData = make([]byte, 32+common.AddressLength+crypto.SignatureLength) 130 copy(gspec.ExtraData[32:32+common.AddressLength], testBankAddress.Bytes()) 131 e.Authorize(testBankAddress, func(account accounts.Account, s string, data []byte) ([]byte, error) { 132 return crypto.Sign(crypto.Keccak256(data), testBankKey) 133 }) 134 case *ethash.Ethash: 135 default: 136 t.Fatalf("unexpected consensus engine type: %T", engine) 137 } 138 genesis := gspec.MustCommit(db) 139 140 chain, _ := core.NewBlockChain(db, &core.CacheConfig{TrieDirtyDisabled: true}, gspec.Config, engine, vm.Config{}, nil, nil) 141 txpool := core.NewTxPool(testTxPoolConfig, chainConfig, chain) 142 143 // Generate a small n-block chain and an uncle block for it 144 if n > 0 { 145 blocks, _ := core.GenerateChain(chainConfig, genesis, engine, db, n, func(i int, gen *core.BlockGen) { 146 gen.SetCoinbase(testBankAddress) 147 }) 148 if _, err := chain.InsertChain(blocks); err != nil { 149 t.Fatalf("failed to insert origin chain: %v", err) 150 } 151 } 152 parent := genesis 153 if n > 0 { 154 parent = chain.GetBlockByHash(chain.CurrentBlock().ParentHash()) 155 } 156 blocks, _ := core.GenerateChain(chainConfig, parent, engine, db, 1, func(i int, gen *core.BlockGen) { 157 gen.SetCoinbase(testUserAddress) 158 }) 159 160 return &testWorkerBackend{ 161 db: db, 162 chain: chain, 163 txPool: txpool, 164 genesis: &gspec, 165 uncleBlock: blocks[0], 166 } 167 } 168 169 func (b *testWorkerBackend) BlockChain() *core.BlockChain { return b.chain } 170 func (b *testWorkerBackend) TxPool() *core.TxPool { return b.txPool } 171 func (b *testWorkerBackend) StateAtBlock(block *types.Block, reexec uint64, base *state.StateDB, checkLive bool, preferDisk bool) (statedb *state.StateDB, err error) { 172 return nil, errors.New("not supported") 173 } 174 175 func (b *testWorkerBackend) newRandomUncle() *types.Block { 176 var parent *types.Block 177 cur := b.chain.CurrentBlock() 178 if cur.NumberU64() == 0 { 179 parent = b.chain.Genesis() 180 } else { 181 parent = b.chain.GetBlockByHash(b.chain.CurrentBlock().ParentHash()) 182 } 183 blocks, _ := core.GenerateChain(b.chain.Config(), parent, b.chain.Engine(), b.db, 1, func(i int, gen *core.BlockGen) { 184 var addr = make([]byte, common.AddressLength) 185 rand.Read(addr) 186 gen.SetCoinbase(common.BytesToAddress(addr)) 187 }) 188 return blocks[0] 189 } 190 191 func (b *testWorkerBackend) newRandomTx(creation bool) *types.Transaction { 192 var tx *types.Transaction 193 gasPrice := big.NewInt(10 * params.InitialBaseFee) 194 if creation { 195 tx, _ = types.SignTx(types.NewContractCreation(b.txPool.Nonce(testBankAddress), big.NewInt(0), testGas, gasPrice, common.FromHex(testCode)), types.HomesteadSigner{}, testBankKey) 196 } else { 197 tx, _ = types.SignTx(types.NewTransaction(b.txPool.Nonce(testBankAddress), testUserAddress, big.NewInt(1000), params.TxGas, gasPrice, nil), types.HomesteadSigner{}, testBankKey) 198 } 199 return tx 200 } 201 202 func newTestWorker(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, db ethdb.Database, blocks int) (*worker, *testWorkerBackend) { 203 backend := newTestWorkerBackend(t, chainConfig, engine, db, blocks) 204 backend.txPool.AddLocals(pendingTxs) 205 w := newWorker(testConfig, chainConfig, engine, backend, new(event.TypeMux), nil, false) 206 w.setEtherbase(testBankAddress) 207 return w, backend 208 } 209 210 func TestGenerateBlockAndImportEthash(t *testing.T) { 211 testGenerateBlockAndImport(t, false) 212 } 213 214 func TestGenerateBlockAndImportClique(t *testing.T) { 215 testGenerateBlockAndImport(t, true) 216 } 217 218 func testGenerateBlockAndImport(t *testing.T, isClique bool) { 219 var ( 220 engine consensus.Engine 221 chainConfig *params.ChainConfig 222 db = rawdb.NewMemoryDatabase() 223 ) 224 if isClique { 225 chainConfig = params.AllCliqueProtocolChanges 226 chainConfig.Clique = ¶ms.CliqueConfig{Period: 1, Epoch: 30000} 227 engine = clique.New(chainConfig.Clique, db) 228 } else { 229 chainConfig = params.AllEthashProtocolChanges 230 engine = ethash.NewFaker() 231 } 232 233 chainConfig.LondonBlock = big.NewInt(0) 234 w, b := newTestWorker(t, chainConfig, engine, db, 0) 235 defer w.close() 236 237 // This test chain imports the mined blocks. 238 db2 := rawdb.NewMemoryDatabase() 239 b.genesis.MustCommit(db2) 240 chain, _ := core.NewBlockChain(db2, nil, b.chain.Config(), engine, vm.Config{}, nil, nil) 241 defer chain.Stop() 242 243 // Ignore empty commit here for less noise. 244 w.skipSealHook = func(task *task) bool { 245 return len(task.receipts) == 0 246 } 247 248 // Wait for mined blocks. 249 sub := w.mux.Subscribe(core.NewMinedBlockEvent{}) 250 defer sub.Unsubscribe() 251 252 // Start mining! 253 w.start() 254 255 for i := 0; i < 5; i++ { 256 b.txPool.AddLocal(b.newRandomTx(true)) 257 b.txPool.AddLocal(b.newRandomTx(false)) 258 w.postSideBlock(core.ChainSideEvent{Block: b.newRandomUncle()}) 259 w.postSideBlock(core.ChainSideEvent{Block: b.newRandomUncle()}) 260 261 select { 262 case ev := <-sub.Chan(): 263 block := ev.Data.(core.NewMinedBlockEvent).Block 264 if _, err := chain.InsertChain([]*types.Block{block}); err != nil { 265 t.Fatalf("failed to insert new mined block %d: %v", block.NumberU64(), err) 266 } 267 case <-time.After(3 * time.Second): // Worker needs 1s to include new changes. 268 t.Fatalf("timeout") 269 } 270 } 271 } 272 273 func TestEmptyWorkEthash(t *testing.T) { 274 testEmptyWork(t, ethashChainConfig, ethash.NewFaker()) 275 } 276 func TestEmptyWorkClique(t *testing.T) { 277 testEmptyWork(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, rawdb.NewMemoryDatabase())) 278 } 279 280 func testEmptyWork(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) { 281 defer engine.Close() 282 283 w, _ := newTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 0) 284 defer w.close() 285 286 var ( 287 taskIndex int 288 taskCh = make(chan struct{}, 2) 289 ) 290 checkEqual := func(t *testing.T, task *task, index int) { 291 // The first empty work without any txs included 292 receiptLen, balance := 0, big.NewInt(0) 293 if index == 1 { 294 // The second full work with 1 tx included 295 receiptLen, balance = 1, big.NewInt(1000) 296 } 297 if len(task.receipts) != receiptLen { 298 t.Fatalf("receipt number mismatch: have %d, want %d", len(task.receipts), receiptLen) 299 } 300 if task.state.GetBalance(testUserAddress).Cmp(balance) != 0 { 301 t.Fatalf("account balance mismatch: have %d, want %d", task.state.GetBalance(testUserAddress), balance) 302 } 303 } 304 w.newTaskHook = func(task *task) { 305 if task.block.NumberU64() == 1 { 306 checkEqual(t, task, taskIndex) 307 taskIndex += 1 308 taskCh <- struct{}{} 309 } 310 } 311 w.skipSealHook = func(task *task) bool { return true } 312 w.fullTaskHook = func() { 313 time.Sleep(100 * time.Millisecond) 314 } 315 w.start() // Start mining! 316 for i := 0; i < 2; i += 1 { 317 select { 318 case <-taskCh: 319 case <-time.NewTimer(3 * time.Second).C: 320 t.Error("new task timeout") 321 } 322 } 323 } 324 325 func TestStreamUncleBlock(t *testing.T) { 326 ethash := ethash.NewFaker() 327 defer ethash.Close() 328 329 w, b := newTestWorker(t, ethashChainConfig, ethash, rawdb.NewMemoryDatabase(), 1) 330 defer w.close() 331 332 var taskCh = make(chan struct{}) 333 334 taskIndex := 0 335 w.newTaskHook = func(task *task) { 336 if task.block.NumberU64() == 2 { 337 // The first task is an empty task, the second 338 // one has 1 pending tx, the third one has 1 tx 339 // and 1 uncle. 340 if taskIndex == 2 { 341 have := task.block.Header().UncleHash 342 want := types.CalcUncleHash([]*types.Header{b.uncleBlock.Header()}) 343 if have != want { 344 t.Errorf("uncle hash mismatch: have %s, want %s", have.Hex(), want.Hex()) 345 } 346 } 347 taskCh <- struct{}{} 348 taskIndex += 1 349 } 350 } 351 w.skipSealHook = func(task *task) bool { 352 return true 353 } 354 w.fullTaskHook = func() { 355 time.Sleep(100 * time.Millisecond) 356 } 357 w.start() 358 359 for i := 0; i < 2; i += 1 { 360 select { 361 case <-taskCh: 362 case <-time.NewTimer(time.Second).C: 363 t.Error("new task timeout") 364 } 365 } 366 367 w.postSideBlock(core.ChainSideEvent{Block: b.uncleBlock}) 368 369 select { 370 case <-taskCh: 371 case <-time.NewTimer(time.Second).C: 372 t.Error("new task timeout") 373 } 374 } 375 376 func TestRegenerateMiningBlockEthash(t *testing.T) { 377 testRegenerateMiningBlock(t, ethashChainConfig, ethash.NewFaker()) 378 } 379 380 func TestRegenerateMiningBlockClique(t *testing.T) { 381 testRegenerateMiningBlock(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, rawdb.NewMemoryDatabase())) 382 } 383 384 func testRegenerateMiningBlock(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) { 385 defer engine.Close() 386 387 w, b := newTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 0) 388 defer w.close() 389 390 var taskCh = make(chan struct{}, 3) 391 392 taskIndex := 0 393 w.newTaskHook = func(task *task) { 394 if task.block.NumberU64() == 1 { 395 // The first task is an empty task, the second 396 // one has 1 pending tx, the third one has 2 txs 397 if taskIndex == 2 { 398 receiptLen, balance := 2, big.NewInt(2000) 399 if len(task.receipts) != receiptLen { 400 t.Errorf("receipt number mismatch: have %d, want %d", len(task.receipts), receiptLen) 401 } 402 if task.state.GetBalance(testUserAddress).Cmp(balance) != 0 { 403 t.Errorf("account balance mismatch: have %d, want %d", task.state.GetBalance(testUserAddress), balance) 404 } 405 } 406 taskCh <- struct{}{} 407 taskIndex += 1 408 } 409 } 410 w.skipSealHook = func(task *task) bool { 411 return true 412 } 413 w.fullTaskHook = func() { 414 time.Sleep(100 * time.Millisecond) 415 } 416 417 w.start() 418 // Ignore the first two works 419 for i := 0; i < 2; i += 1 { 420 select { 421 case <-taskCh: 422 case <-time.NewTimer(time.Second).C: 423 t.Error("new task timeout") 424 } 425 } 426 b.txPool.AddLocals(newTxs) 427 time.Sleep(time.Second) 428 429 select { 430 case <-taskCh: 431 case <-time.NewTimer(time.Second).C: 432 t.Error("new task timeout") 433 } 434 } 435 436 func TestAdjustIntervalEthash(t *testing.T) { 437 testAdjustInterval(t, ethashChainConfig, ethash.NewFaker()) 438 } 439 440 func TestAdjustIntervalClique(t *testing.T) { 441 testAdjustInterval(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, rawdb.NewMemoryDatabase())) 442 } 443 444 func testAdjustInterval(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) { 445 defer engine.Close() 446 447 w, _ := newTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 0) 448 defer w.close() 449 450 w.skipSealHook = func(task *task) bool { 451 return true 452 } 453 w.fullTaskHook = func() { 454 time.Sleep(100 * time.Millisecond) 455 } 456 var ( 457 progress = make(chan struct{}, 10) 458 result = make([]float64, 0, 10) 459 index = 0 460 start uint32 461 ) 462 w.resubmitHook = func(minInterval time.Duration, recommitInterval time.Duration) { 463 // Short circuit if interval checking hasn't started. 464 if atomic.LoadUint32(&start) == 0 { 465 return 466 } 467 var wantMinInterval, wantRecommitInterval time.Duration 468 469 switch index { 470 case 0: 471 wantMinInterval, wantRecommitInterval = 3*time.Second, 3*time.Second 472 case 1: 473 origin := float64(3 * time.Second.Nanoseconds()) 474 estimate := origin*(1-intervalAdjustRatio) + intervalAdjustRatio*(origin/0.8+intervalAdjustBias) 475 wantMinInterval, wantRecommitInterval = 3*time.Second, time.Duration(estimate)*time.Nanosecond 476 case 2: 477 estimate := result[index-1] 478 min := float64(3 * time.Second.Nanoseconds()) 479 estimate = estimate*(1-intervalAdjustRatio) + intervalAdjustRatio*(min-intervalAdjustBias) 480 wantMinInterval, wantRecommitInterval = 3*time.Second, time.Duration(estimate)*time.Nanosecond 481 case 3: 482 wantMinInterval, wantRecommitInterval = time.Second, time.Second 483 } 484 485 // Check interval 486 if minInterval != wantMinInterval { 487 t.Errorf("resubmit min interval mismatch: have %v, want %v ", minInterval, wantMinInterval) 488 } 489 if recommitInterval != wantRecommitInterval { 490 t.Errorf("resubmit interval mismatch: have %v, want %v", recommitInterval, wantRecommitInterval) 491 } 492 result = append(result, float64(recommitInterval.Nanoseconds())) 493 index += 1 494 progress <- struct{}{} 495 } 496 w.start() 497 498 time.Sleep(time.Second) // Ensure two tasks have been summitted due to start opt 499 atomic.StoreUint32(&start, 1) 500 501 w.setRecommitInterval(3 * time.Second) 502 select { 503 case <-progress: 504 case <-time.NewTimer(time.Second).C: 505 t.Error("interval reset timeout") 506 } 507 508 w.resubmitAdjustCh <- &intervalAdjust{inc: true, ratio: 0.8} 509 select { 510 case <-progress: 511 case <-time.NewTimer(time.Second).C: 512 t.Error("interval reset timeout") 513 } 514 515 w.resubmitAdjustCh <- &intervalAdjust{inc: false} 516 select { 517 case <-progress: 518 case <-time.NewTimer(time.Second).C: 519 t.Error("interval reset timeout") 520 } 521 522 w.setRecommitInterval(500 * time.Millisecond) 523 select { 524 case <-progress: 525 case <-time.NewTimer(time.Second).C: 526 t.Error("interval reset timeout") 527 } 528 } 529 530 func TestGetSealingWorkEthash(t *testing.T) { 531 testGetSealingWork(t, ethashChainConfig, ethash.NewFaker(), false) 532 } 533 534 func TestGetSealingWorkClique(t *testing.T) { 535 testGetSealingWork(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, rawdb.NewMemoryDatabase()), false) 536 } 537 538 func TestGetSealingWorkPostMerge(t *testing.T) { 539 local := new(params.ChainConfig) 540 *local = *ethashChainConfig 541 local.TerminalTotalDifficulty = big.NewInt(0) 542 testGetSealingWork(t, local, ethash.NewFaker(), true) 543 } 544 545 func testGetSealingWork(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, postMerge bool) { 546 defer engine.Close() 547 548 w, b := newTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 0) 549 defer w.close() 550 551 w.setExtra([]byte{0x01, 0x02}) 552 w.postSideBlock(core.ChainSideEvent{Block: b.uncleBlock}) 553 554 w.skipSealHook = func(task *task) bool { 555 return true 556 } 557 w.fullTaskHook = func() { 558 time.Sleep(100 * time.Millisecond) 559 } 560 timestamp := uint64(time.Now().Unix()) 561 assertBlock := func(block *types.Block, number uint64, coinbase common.Address, random common.Hash) { 562 if block.Time() != timestamp { 563 // Sometime the timestamp will be mutated if the timestamp 564 // is even smaller than parent block's. It's OK. 565 t.Logf("Invalid timestamp, want %d, get %d", timestamp, block.Time()) 566 } 567 if len(block.Uncles()) != 0 { 568 t.Error("Unexpected uncle block") 569 } 570 _, isClique := engine.(*clique.Clique) 571 if !isClique { 572 if len(block.Extra()) != 0 { 573 t.Error("Unexpected extra field") 574 } 575 if block.Coinbase() != coinbase { 576 t.Errorf("Unexpected coinbase got %x want %x", block.Coinbase(), coinbase) 577 } 578 } else { 579 if block.Coinbase() != (common.Address{}) { 580 t.Error("Unexpected coinbase") 581 } 582 } 583 if !isClique { 584 if block.MixDigest() != random { 585 t.Error("Unexpected mix digest") 586 } 587 } 588 if block.Nonce() != 0 { 589 t.Error("Unexpected block nonce") 590 } 591 if block.NumberU64() != number { 592 t.Errorf("Mismatched block number, want %d got %d", number, block.NumberU64()) 593 } 594 } 595 var cases = []struct { 596 parent common.Hash 597 coinbase common.Address 598 random common.Hash 599 expectNumber uint64 600 expectErr bool 601 }{ 602 { 603 b.chain.Genesis().Hash(), 604 common.HexToAddress("0xdeadbeef"), 605 common.HexToHash("0xcafebabe"), 606 uint64(1), 607 false, 608 }, 609 { 610 b.chain.CurrentBlock().Hash(), 611 common.HexToAddress("0xdeadbeef"), 612 common.HexToHash("0xcafebabe"), 613 b.chain.CurrentBlock().NumberU64() + 1, 614 false, 615 }, 616 { 617 b.chain.CurrentBlock().Hash(), 618 common.Address{}, 619 common.HexToHash("0xcafebabe"), 620 b.chain.CurrentBlock().NumberU64() + 1, 621 false, 622 }, 623 { 624 b.chain.CurrentBlock().Hash(), 625 common.Address{}, 626 common.Hash{}, 627 b.chain.CurrentBlock().NumberU64() + 1, 628 false, 629 }, 630 { 631 common.HexToHash("0xdeadbeef"), 632 common.HexToAddress("0xdeadbeef"), 633 common.HexToHash("0xcafebabe"), 634 0, 635 true, 636 }, 637 } 638 639 // This API should work even when the automatic sealing is not enabled 640 for _, c := range cases { 641 block, err := w.getSealingBlock(c.parent, timestamp, c.coinbase, c.random) 642 if c.expectErr { 643 if err == nil { 644 t.Error("Expect error but get nil") 645 } 646 } else { 647 if err != nil { 648 t.Errorf("Unexpected error %v", err) 649 } 650 assertBlock(block, c.expectNumber, c.coinbase, c.random) 651 } 652 } 653 654 // This API should work even when the automatic sealing is enabled 655 w.start() 656 for _, c := range cases { 657 block, err := w.getSealingBlock(c.parent, timestamp, c.coinbase, c.random) 658 if c.expectErr { 659 if err == nil { 660 t.Error("Expect error but get nil") 661 } 662 } else { 663 if err != nil { 664 t.Errorf("Unexpected error %v", err) 665 } 666 assertBlock(block, c.expectNumber, c.coinbase, c.random) 667 } 668 } 669 }