| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | // Copyright 2018 The go-ethereum Authors | 
					
						
							|  |  |  | // This file is part of the go-ethereum library. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  | // it under the terms of the GNU Lesser General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							|  |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							|  |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package miner | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"math/big" | 
					
						
							|  |  |  | 	"testing" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/common" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/consensus" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/consensus/clique" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/consensus/ethash" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/core" | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 	"github.com/ethereum/go-ethereum/core/rawdb" | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	"github.com/ethereum/go-ethereum/core/types" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/core/vm" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/crypto" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/ethdb" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/event" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/params" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var ( | 
					
						
							|  |  |  | 	// Test chain configurations | 
					
						
							|  |  |  | 	testTxPoolConfig  core.TxPoolConfig | 
					
						
							|  |  |  | 	ethashChainConfig *params.ChainConfig | 
					
						
							|  |  |  | 	cliqueChainConfig *params.ChainConfig | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Test accounts | 
					
						
							|  |  |  | 	testBankKey, _  = crypto.GenerateKey() | 
					
						
							|  |  |  | 	testBankAddress = crypto.PubkeyToAddress(testBankKey.PublicKey) | 
					
						
							|  |  |  | 	testBankFunds   = big.NewInt(1000000000000000000) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-28 16:48:20 +03:00
										 |  |  | 	testUserKey, _  = crypto.GenerateKey() | 
					
						
							|  |  |  | 	testUserAddress = crypto.PubkeyToAddress(testUserKey.PublicKey) | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Test transactions | 
					
						
							|  |  |  | 	pendingTxs []*types.Transaction | 
					
						
							|  |  |  | 	newTxs     []*types.Transaction | 
					
						
							| 
									
										
										
										
											2019-04-23 15:08:51 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	testConfig = &Config{ | 
					
						
							|  |  |  | 		Recommit: time.Second, | 
					
						
							|  |  |  | 		GasFloor: params.GenesisGasLimit, | 
					
						
							|  |  |  | 		GasCeil:  params.GenesisGasLimit, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func init() { | 
					
						
							|  |  |  | 	testTxPoolConfig = core.DefaultTxPoolConfig | 
					
						
							|  |  |  | 	testTxPoolConfig.Journal = "" | 
					
						
							|  |  |  | 	ethashChainConfig = params.TestChainConfig | 
					
						
							|  |  |  | 	cliqueChainConfig = params.TestChainConfig | 
					
						
							|  |  |  | 	cliqueChainConfig.Clique = ¶ms.CliqueConfig{ | 
					
						
							| 
									
										
										
										
											2018-08-15 19:09:17 +08:00
										 |  |  | 		Period: 10, | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 		Epoch:  30000, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-08-28 16:48:20 +03:00
										 |  |  | 	tx1, _ := types.SignTx(types.NewTransaction(0, testUserAddress, big.NewInt(1000), params.TxGas, nil, nil), types.HomesteadSigner{}, testBankKey) | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	pendingTxs = append(pendingTxs, tx1) | 
					
						
							| 
									
										
										
										
											2018-08-28 16:48:20 +03:00
										 |  |  | 	tx2, _ := types.SignTx(types.NewTransaction(1, testUserAddress, big.NewInt(1000), params.TxGas, nil, nil), types.HomesteadSigner{}, testBankKey) | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	newTxs = append(newTxs, tx2) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // testWorkerBackend implements worker.Backend interfaces and wraps all information needed during the testing. | 
					
						
							|  |  |  | type testWorkerBackend struct { | 
					
						
							|  |  |  | 	db         ethdb.Database | 
					
						
							|  |  |  | 	txPool     *core.TxPool | 
					
						
							|  |  |  | 	chain      *core.BlockChain | 
					
						
							|  |  |  | 	testTxFeed event.Feed | 
					
						
							| 
									
										
										
										
											2018-08-15 19:09:17 +08:00
										 |  |  | 	uncleBlock *types.Block | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-28 16:48:20 +03:00
										 |  |  | func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, n int) *testWorkerBackend { | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	var ( | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 		db    = rawdb.NewMemoryDatabase() | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 		gspec = core.Genesis{ | 
					
						
							|  |  |  | 			Config: chainConfig, | 
					
						
							|  |  |  | 			Alloc:  core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch engine.(type) { | 
					
						
							|  |  |  | 	case *clique.Clique: | 
					
						
							|  |  |  | 		gspec.ExtraData = make([]byte, 32+common.AddressLength+65) | 
					
						
							|  |  |  | 		copy(gspec.ExtraData[32:], testBankAddress[:]) | 
					
						
							|  |  |  | 	case *ethash.Ethash: | 
					
						
							|  |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2018-08-28 16:48:20 +03:00
										 |  |  | 		t.Fatalf("unexpected consensus engine type: %T", engine) | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-08-15 19:09:17 +08:00
										 |  |  | 	genesis := gspec.MustCommit(db) | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-20 20:09:30 +08:00
										 |  |  | 	chain, _ := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil) | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	txpool := core.NewTxPool(testTxPoolConfig, chainConfig, chain) | 
					
						
							| 
									
										
										
										
											2018-08-28 16:48:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Generate a small n-block chain and an uncle block for it | 
					
						
							|  |  |  | 	if n > 0 { | 
					
						
							|  |  |  | 		blocks, _ := core.GenerateChain(chainConfig, genesis, engine, db, n, func(i int, gen *core.BlockGen) { | 
					
						
							|  |  |  | 			gen.SetCoinbase(testBankAddress) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		if _, err := chain.InsertChain(blocks); err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("failed to insert origin chain: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	parent := genesis | 
					
						
							|  |  |  | 	if n > 0 { | 
					
						
							|  |  |  | 		parent = chain.GetBlockByHash(chain.CurrentBlock().ParentHash()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	blocks, _ := core.GenerateChain(chainConfig, parent, engine, db, 1, func(i int, gen *core.BlockGen) { | 
					
						
							|  |  |  | 		gen.SetCoinbase(testUserAddress) | 
					
						
							| 
									
										
										
										
											2018-08-15 19:09:17 +08:00
										 |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return &testWorkerBackend{ | 
					
						
							| 
									
										
										
										
											2018-08-15 19:09:17 +08:00
										 |  |  | 		db:         db, | 
					
						
							|  |  |  | 		chain:      chain, | 
					
						
							|  |  |  | 		txPool:     txpool, | 
					
						
							|  |  |  | 		uncleBlock: blocks[0], | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (b *testWorkerBackend) BlockChain() *core.BlockChain { return b.chain } | 
					
						
							|  |  |  | func (b *testWorkerBackend) TxPool() *core.TxPool         { return b.txPool } | 
					
						
							|  |  |  | func (b *testWorkerBackend) PostChainEvents(events []interface{}) { | 
					
						
							|  |  |  | 	b.chain.PostChainEvents(events, nil) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-28 16:48:20 +03:00
										 |  |  | func newTestWorker(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, blocks int) (*worker, *testWorkerBackend) { | 
					
						
							|  |  |  | 	backend := newTestWorkerBackend(t, chainConfig, engine, blocks) | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	backend.txPool.AddLocals(pendingTxs) | 
					
						
							| 
									
										
										
										
											2019-04-23 15:08:51 +08:00
										 |  |  | 	w := newWorker(testConfig, chainConfig, engine, backend, new(event.TypeMux), nil) | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	w.setEtherbase(testBankAddress) | 
					
						
							|  |  |  | 	return w, backend | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestPendingStateAndBlockEthash(t *testing.T) { | 
					
						
							|  |  |  | 	testPendingStateAndBlock(t, ethashChainConfig, ethash.NewFaker()) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | func TestPendingStateAndBlockClique(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 	testPendingStateAndBlock(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, rawdb.NewMemoryDatabase())) | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testPendingStateAndBlock(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) { | 
					
						
							|  |  |  | 	defer engine.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-28 16:48:20 +03:00
										 |  |  | 	w, b := newTestWorker(t, chainConfig, engine, 0) | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	defer w.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Ensure snapshot has been updated. | 
					
						
							|  |  |  | 	time.Sleep(100 * time.Millisecond) | 
					
						
							|  |  |  | 	block, state := w.pending() | 
					
						
							|  |  |  | 	if block.NumberU64() != 1 { | 
					
						
							| 
									
										
										
										
											2018-08-28 16:48:20 +03:00
										 |  |  | 		t.Errorf("block number mismatch: have %d, want %d", block.NumberU64(), 1) | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-08-28 16:48:20 +03:00
										 |  |  | 	if balance := state.GetBalance(testUserAddress); balance.Cmp(big.NewInt(1000)) != 0 { | 
					
						
							|  |  |  | 		t.Errorf("account balance mismatch: have %d, want %d", balance, 1000) | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	b.txPool.AddLocals(newTxs) | 
					
						
							| 
									
										
										
										
											2018-09-10 17:12:39 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	// Ensure the new tx events has been processed | 
					
						
							|  |  |  | 	time.Sleep(100 * time.Millisecond) | 
					
						
							|  |  |  | 	block, state = w.pending() | 
					
						
							| 
									
										
										
										
											2018-08-28 16:48:20 +03:00
										 |  |  | 	if balance := state.GetBalance(testUserAddress); balance.Cmp(big.NewInt(2000)) != 0 { | 
					
						
							|  |  |  | 		t.Errorf("account balance mismatch: have %d, want %d", balance, 2000) | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestEmptyWorkEthash(t *testing.T) { | 
					
						
							|  |  |  | 	testEmptyWork(t, ethashChainConfig, ethash.NewFaker()) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | func TestEmptyWorkClique(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 	testEmptyWork(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, rawdb.NewMemoryDatabase())) | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testEmptyWork(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) { | 
					
						
							|  |  |  | 	defer engine.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-28 16:48:20 +03:00
										 |  |  | 	w, _ := newTestWorker(t, chainConfig, engine, 0) | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	defer w.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		taskCh    = make(chan struct{}, 2) | 
					
						
							|  |  |  | 		taskIndex int | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	checkEqual := func(t *testing.T, task *task, index int) { | 
					
						
							|  |  |  | 		receiptLen, balance := 0, big.NewInt(0) | 
					
						
							|  |  |  | 		if index == 1 { | 
					
						
							|  |  |  | 			receiptLen, balance = 1, big.NewInt(1000) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if len(task.receipts) != receiptLen { | 
					
						
							| 
									
										
										
										
											2018-08-28 16:48:20 +03:00
										 |  |  | 			t.Errorf("receipt number mismatch: have %d, want %d", len(task.receipts), receiptLen) | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-08-28 16:48:20 +03:00
										 |  |  | 		if task.state.GetBalance(testUserAddress).Cmp(balance) != 0 { | 
					
						
							|  |  |  | 			t.Errorf("account balance mismatch: have %d, want %d", task.state.GetBalance(testUserAddress), balance) | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	w.newTaskHook = func(task *task) { | 
					
						
							|  |  |  | 		if task.block.NumberU64() == 1 { | 
					
						
							|  |  |  | 			checkEqual(t, task, taskIndex) | 
					
						
							|  |  |  | 			taskIndex += 1 | 
					
						
							|  |  |  | 			taskCh <- struct{}{} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-08-15 19:09:17 +08:00
										 |  |  | 	w.fullTaskHook = func() { | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 		time.Sleep(100 * time.Millisecond) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Ensure worker has finished initialization | 
					
						
							|  |  |  | 	for { | 
					
						
							|  |  |  | 		b := w.pendingBlock() | 
					
						
							|  |  |  | 		if b != nil && b.NumberU64() == 1 { | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	w.start() | 
					
						
							|  |  |  | 	for i := 0; i < 2; i += 1 { | 
					
						
							|  |  |  | 		select { | 
					
						
							|  |  |  | 		case <-taskCh: | 
					
						
							| 
									
										
										
										
											2019-01-23 16:09:29 +01:00
										 |  |  | 		case <-time.NewTimer(2 * time.Second).C: | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 			t.Error("new task timeout") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-08-15 19:09:17 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestStreamUncleBlock(t *testing.T) { | 
					
						
							|  |  |  | 	ethash := ethash.NewFaker() | 
					
						
							|  |  |  | 	defer ethash.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-28 16:48:20 +03:00
										 |  |  | 	w, b := newTestWorker(t, ethashChainConfig, ethash, 1) | 
					
						
							| 
									
										
										
										
											2018-08-15 19:09:17 +08:00
										 |  |  | 	defer w.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var taskCh = make(chan struct{}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	taskIndex := 0 | 
					
						
							|  |  |  | 	w.newTaskHook = func(task *task) { | 
					
						
							| 
									
										
										
										
											2018-08-28 16:48:20 +03:00
										 |  |  | 		if task.block.NumberU64() == 2 { | 
					
						
							| 
									
										
										
										
											2018-08-15 19:09:17 +08:00
										 |  |  | 			if taskIndex == 2 { | 
					
						
							| 
									
										
										
										
											2018-08-28 16:48:20 +03:00
										 |  |  | 				have := task.block.Header().UncleHash | 
					
						
							| 
									
										
										
										
											2018-08-15 19:09:17 +08:00
										 |  |  | 				want := types.CalcUncleHash([]*types.Header{b.uncleBlock.Header()}) | 
					
						
							| 
									
										
										
										
											2018-08-28 16:48:20 +03:00
										 |  |  | 				if have != want { | 
					
						
							|  |  |  | 					t.Errorf("uncle hash mismatch: have %s, want %s", have.Hex(), want.Hex()) | 
					
						
							| 
									
										
										
										
											2018-08-15 19:09:17 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			taskCh <- struct{}{} | 
					
						
							|  |  |  | 			taskIndex += 1 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	w.skipSealHook = func(task *task) bool { | 
					
						
							|  |  |  | 		return true | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	w.fullTaskHook = func() { | 
					
						
							|  |  |  | 		time.Sleep(100 * time.Millisecond) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Ensure worker has finished initialization | 
					
						
							|  |  |  | 	for { | 
					
						
							|  |  |  | 		b := w.pendingBlock() | 
					
						
							| 
									
										
										
										
											2018-08-28 16:48:20 +03:00
										 |  |  | 		if b != nil && b.NumberU64() == 2 { | 
					
						
							| 
									
										
										
										
											2018-08-15 19:09:17 +08:00
										 |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	w.start() | 
					
						
							| 
									
										
										
										
											2018-08-28 16:48:20 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-15 19:09:17 +08:00
										 |  |  | 	// Ignore the first two works | 
					
						
							|  |  |  | 	for i := 0; i < 2; i += 1 { | 
					
						
							|  |  |  | 		select { | 
					
						
							|  |  |  | 		case <-taskCh: | 
					
						
							|  |  |  | 		case <-time.NewTimer(time.Second).C: | 
					
						
							|  |  |  | 			t.Error("new task timeout") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	b.PostChainEvents([]interface{}{core.ChainSideEvent{Block: b.uncleBlock}}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	select { | 
					
						
							|  |  |  | 	case <-taskCh: | 
					
						
							|  |  |  | 	case <-time.NewTimer(time.Second).C: | 
					
						
							|  |  |  | 		t.Error("new task timeout") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestRegenerateMiningBlockEthash(t *testing.T) { | 
					
						
							|  |  |  | 	testRegenerateMiningBlock(t, ethashChainConfig, ethash.NewFaker()) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestRegenerateMiningBlockClique(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 	testRegenerateMiningBlock(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, rawdb.NewMemoryDatabase())) | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testRegenerateMiningBlock(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) { | 
					
						
							|  |  |  | 	defer engine.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-28 16:48:20 +03:00
										 |  |  | 	w, b := newTestWorker(t, chainConfig, engine, 0) | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | 	defer w.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var taskCh = make(chan struct{}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	taskIndex := 0 | 
					
						
							|  |  |  | 	w.newTaskHook = func(task *task) { | 
					
						
							|  |  |  | 		if task.block.NumberU64() == 1 { | 
					
						
							|  |  |  | 			if taskIndex == 2 { | 
					
						
							|  |  |  | 				receiptLen, balance := 2, big.NewInt(2000) | 
					
						
							|  |  |  | 				if len(task.receipts) != receiptLen { | 
					
						
							| 
									
										
										
										
											2018-08-28 16:48:20 +03:00
										 |  |  | 					t.Errorf("receipt number mismatch: have %d, want %d", len(task.receipts), receiptLen) | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-08-28 16:48:20 +03:00
										 |  |  | 				if task.state.GetBalance(testUserAddress).Cmp(balance) != 0 { | 
					
						
							|  |  |  | 					t.Errorf("account balance mismatch: have %d, want %d", task.state.GetBalance(testUserAddress), balance) | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			taskCh <- struct{}{} | 
					
						
							|  |  |  | 			taskIndex += 1 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	w.skipSealHook = func(task *task) bool { | 
					
						
							|  |  |  | 		return true | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	w.fullTaskHook = func() { | 
					
						
							|  |  |  | 		time.Sleep(100 * time.Millisecond) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Ensure worker has finished initialization | 
					
						
							|  |  |  | 	for { | 
					
						
							|  |  |  | 		b := w.pendingBlock() | 
					
						
							|  |  |  | 		if b != nil && b.NumberU64() == 1 { | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	w.start() | 
					
						
							|  |  |  | 	// Ignore the first two works | 
					
						
							|  |  |  | 	for i := 0; i < 2; i += 1 { | 
					
						
							|  |  |  | 		select { | 
					
						
							|  |  |  | 		case <-taskCh: | 
					
						
							|  |  |  | 		case <-time.NewTimer(time.Second).C: | 
					
						
							|  |  |  | 			t.Error("new task timeout") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	b.txPool.AddLocals(newTxs) | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | 	time.Sleep(time.Second) | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	select { | 
					
						
							|  |  |  | 	case <-taskCh: | 
					
						
							|  |  |  | 	case <-time.NewTimer(time.Second).C: | 
					
						
							|  |  |  | 		t.Error("new task timeout") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestAdjustIntervalEthash(t *testing.T) { | 
					
						
							|  |  |  | 	testAdjustInterval(t, ethashChainConfig, ethash.NewFaker()) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestAdjustIntervalClique(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 	testAdjustInterval(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, rawdb.NewMemoryDatabase())) | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testAdjustInterval(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) { | 
					
						
							|  |  |  | 	defer engine.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-28 16:48:20 +03:00
										 |  |  | 	w, _ := newTestWorker(t, chainConfig, engine, 0) | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | 	defer w.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	w.skipSealHook = func(task *task) bool { | 
					
						
							|  |  |  | 		return true | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	w.fullTaskHook = func() { | 
					
						
							|  |  |  | 		time.Sleep(100 * time.Millisecond) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		progress = make(chan struct{}, 10) | 
					
						
							|  |  |  | 		result   = make([]float64, 0, 10) | 
					
						
							|  |  |  | 		index    = 0 | 
					
						
							|  |  |  | 		start    = false | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	w.resubmitHook = func(minInterval time.Duration, recommitInterval time.Duration) { | 
					
						
							|  |  |  | 		// Short circuit if interval checking hasn't started. | 
					
						
							|  |  |  | 		if !start { | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		var wantMinInterval, wantRecommitInterval time.Duration | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		switch index { | 
					
						
							|  |  |  | 		case 0: | 
					
						
							|  |  |  | 			wantMinInterval, wantRecommitInterval = 3*time.Second, 3*time.Second | 
					
						
							|  |  |  | 		case 1: | 
					
						
							|  |  |  | 			origin := float64(3 * time.Second.Nanoseconds()) | 
					
						
							|  |  |  | 			estimate := origin*(1-intervalAdjustRatio) + intervalAdjustRatio*(origin/0.8+intervalAdjustBias) | 
					
						
							| 
									
										
										
										
											2018-10-08 16:30:00 +02:00
										 |  |  | 			wantMinInterval, wantRecommitInterval = 3*time.Second, time.Duration(estimate)*time.Nanosecond | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | 		case 2: | 
					
						
							|  |  |  | 			estimate := result[index-1] | 
					
						
							|  |  |  | 			min := float64(3 * time.Second.Nanoseconds()) | 
					
						
							|  |  |  | 			estimate = estimate*(1-intervalAdjustRatio) + intervalAdjustRatio*(min-intervalAdjustBias) | 
					
						
							| 
									
										
										
										
											2018-10-08 16:30:00 +02:00
										 |  |  | 			wantMinInterval, wantRecommitInterval = 3*time.Second, time.Duration(estimate)*time.Nanosecond | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | 		case 3: | 
					
						
							|  |  |  | 			wantMinInterval, wantRecommitInterval = time.Second, time.Second | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Check interval | 
					
						
							|  |  |  | 		if minInterval != wantMinInterval { | 
					
						
							| 
									
										
										
										
											2018-08-28 16:48:20 +03:00
										 |  |  | 			t.Errorf("resubmit min interval mismatch: have %v, want %v ", minInterval, wantMinInterval) | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if recommitInterval != wantRecommitInterval { | 
					
						
							| 
									
										
										
										
											2018-08-28 16:48:20 +03:00
										 |  |  | 			t.Errorf("resubmit interval mismatch: have %v, want %v", recommitInterval, wantRecommitInterval) | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		result = append(result, float64(recommitInterval.Nanoseconds())) | 
					
						
							|  |  |  | 		index += 1 | 
					
						
							|  |  |  | 		progress <- struct{}{} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Ensure worker has finished initialization | 
					
						
							|  |  |  | 	for { | 
					
						
							|  |  |  | 		b := w.pendingBlock() | 
					
						
							|  |  |  | 		if b != nil && b.NumberU64() == 1 { | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	w.start() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	time.Sleep(time.Second) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	start = true | 
					
						
							|  |  |  | 	w.setRecommitInterval(3 * time.Second) | 
					
						
							|  |  |  | 	select { | 
					
						
							|  |  |  | 	case <-progress: | 
					
						
							|  |  |  | 	case <-time.NewTimer(time.Second).C: | 
					
						
							|  |  |  | 		t.Error("interval reset timeout") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	w.resubmitAdjustCh <- &intervalAdjust{inc: true, ratio: 0.8} | 
					
						
							|  |  |  | 	select { | 
					
						
							|  |  |  | 	case <-progress: | 
					
						
							|  |  |  | 	case <-time.NewTimer(time.Second).C: | 
					
						
							|  |  |  | 		t.Error("interval reset timeout") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	w.resubmitAdjustCh <- &intervalAdjust{inc: false} | 
					
						
							|  |  |  | 	select { | 
					
						
							|  |  |  | 	case <-progress: | 
					
						
							|  |  |  | 	case <-time.NewTimer(time.Second).C: | 
					
						
							|  |  |  | 		t.Error("interval reset timeout") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	w.setRecommitInterval(500 * time.Millisecond) | 
					
						
							|  |  |  | 	select { | 
					
						
							|  |  |  | 	case <-progress: | 
					
						
							|  |  |  | 	case <-time.NewTimer(time.Second).C: | 
					
						
							|  |  |  | 		t.Error("interval reset timeout") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |