| 
									
										
										
										
											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" | 
					
						
							| 
									
										
										
										
											2019-10-20 19:36:40 +09:00
										 |  |  | 	"math/rand" | 
					
						
							| 
									
										
										
										
											2019-11-20 18:36:41 +08:00
										 |  |  | 	"sync/atomic" | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	"testing" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-20 19:36:40 +09:00
										 |  |  | 	"github.com/ethereum/go-ethereum/accounts" | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	"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" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-20 19:36:40 +09:00
										 |  |  | const ( | 
					
						
							|  |  |  | 	// testCode is the testing contract binary code which will initialises some | 
					
						
							|  |  |  | 	// variables in constructor | 
					
						
							|  |  |  | 	testCode = "0x60806040527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0060005534801561003457600080fd5b5060fc806100436000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c80630c4dae8814603757806398a213cf146053575b600080fd5b603d607e565b6040518082815260200191505060405180910390f35b607c60048036036020811015606757600080fd5b81019080803590602001909291905050506084565b005b60005481565b806000819055507fe9e44f9f7da8c559de847a3232b57364adc0354f15a2cd8dc636d54396f9587a6000546040518082815260200191505060405180910390a15056fea265627a7a723058208ae31d9424f2d0bc2a3da1a5dd659db2d71ec322a17db8f87e19e209e3a1ff4a64736f6c634300050a0032" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// testGas is the gas required for contract deployment. | 
					
						
							|  |  |  | 	testGas = 144109 | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 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, | 
					
						
							|  |  |  | 		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, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	signer := types.LatestSigner(params.TestChainConfig) | 
					
						
							|  |  |  | 	tx1 := types.MustSignNewTx(testBankKey, signer, &types.AccessListTx{ | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 		ChainID:  params.TestChainConfig.ChainID, | 
					
						
							|  |  |  | 		Nonce:    0, | 
					
						
							|  |  |  | 		To:       &testUserAddress, | 
					
						
							|  |  |  | 		Value:    big.NewInt(1000), | 
					
						
							|  |  |  | 		Gas:      params.TxGas, | 
					
						
							|  |  |  | 		GasPrice: big.NewInt(params.InitialBaseFee), | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	pendingTxs = append(pendingTxs, tx1) | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	tx2 := types.MustSignNewTx(testBankKey, signer, &types.LegacyTx{ | 
					
						
							| 
									
										
										
										
											2021-06-15 13:56:14 +03:00
										 |  |  | 		Nonce:    1, | 
					
						
							|  |  |  | 		To:       &testUserAddress, | 
					
						
							|  |  |  | 		Value:    big.NewInt(1000), | 
					
						
							|  |  |  | 		Gas:      params.TxGas, | 
					
						
							|  |  |  | 		GasPrice: big.NewInt(params.InitialBaseFee), | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	newTxs = append(newTxs, tx2) | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-30 19:07:30 +08:00
										 |  |  | 	rand.Seed(time.Now().UnixNano()) | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 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 | 
					
						
							| 
									
										
										
										
											2019-10-20 19:36:40 +09:00
										 |  |  | 	genesis    *core.Genesis | 
					
						
							| 
									
										
										
										
											2018-08-15 19:09:17 +08:00
										 |  |  | 	uncleBlock *types.Block | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-20 19:36:40 +09:00
										 |  |  | func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, db ethdb.Database, n int) *testWorkerBackend { | 
					
						
							|  |  |  | 	var gspec = core.Genesis{ | 
					
						
							|  |  |  | 		Config: chainConfig, | 
					
						
							|  |  |  | 		Alloc:  core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-20 19:36:40 +09:00
										 |  |  | 	switch e := engine.(type) { | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	case *clique.Clique: | 
					
						
							| 
									
										
										
										
											2019-08-22 15:14:06 +02:00
										 |  |  | 		gspec.ExtraData = make([]byte, 32+common.AddressLength+crypto.SignatureLength) | 
					
						
							| 
									
										
										
										
											2019-10-20 19:36:40 +09:00
										 |  |  | 		copy(gspec.ExtraData[32:32+common.AddressLength], testBankAddress.Bytes()) | 
					
						
							|  |  |  | 		e.Authorize(testBankAddress, func(account accounts.Account, s string, data []byte) ([]byte, error) { | 
					
						
							|  |  |  | 			return crypto.Sign(crypto.Keccak256(data), testBankKey) | 
					
						
							|  |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 	chain, _ := core.NewBlockChain(db, &core.CacheConfig{TrieDirtyDisabled: true}, gspec.Config, engine, vm.Config{}, nil, 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, | 
					
						
							| 
									
										
										
										
											2019-10-20 19:36:40 +09:00
										 |  |  | 		genesis:    &gspec, | 
					
						
							| 
									
										
										
										
											2018-08-15 19:09:17 +08:00
										 |  |  | 		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 } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-20 19:36:40 +09:00
										 |  |  | func (b *testWorkerBackend) newRandomUncle() *types.Block { | 
					
						
							|  |  |  | 	var parent *types.Block | 
					
						
							|  |  |  | 	cur := b.chain.CurrentBlock() | 
					
						
							|  |  |  | 	if cur.NumberU64() == 0 { | 
					
						
							|  |  |  | 		parent = b.chain.Genesis() | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		parent = b.chain.GetBlockByHash(b.chain.CurrentBlock().ParentHash()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	blocks, _ := core.GenerateChain(b.chain.Config(), parent, b.chain.Engine(), b.db, 1, func(i int, gen *core.BlockGen) { | 
					
						
							| 
									
										
										
										
											2019-10-30 19:07:30 +08:00
										 |  |  | 		var addr = make([]byte, common.AddressLength) | 
					
						
							|  |  |  | 		rand.Read(addr) | 
					
						
							|  |  |  | 		gen.SetCoinbase(common.BytesToAddress(addr)) | 
					
						
							| 
									
										
										
										
											2019-10-20 19:36:40 +09:00
										 |  |  | 	}) | 
					
						
							|  |  |  | 	return blocks[0] | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (b *testWorkerBackend) newRandomTx(creation bool) *types.Transaction { | 
					
						
							|  |  |  | 	var tx *types.Transaction | 
					
						
							| 
									
										
										
										
											2021-05-21 09:59:26 +02:00
										 |  |  | 	gasPrice := big.NewInt(10 * params.InitialBaseFee) | 
					
						
							| 
									
										
										
										
											2019-10-20 19:36:40 +09:00
										 |  |  | 	if creation { | 
					
						
							| 
									
										
										
										
											2021-05-21 09:59:26 +02:00
										 |  |  | 		tx, _ = types.SignTx(types.NewContractCreation(b.txPool.Nonce(testBankAddress), big.NewInt(0), testGas, gasPrice, common.FromHex(testCode)), types.HomesteadSigner{}, testBankKey) | 
					
						
							| 
									
										
										
										
											2019-10-20 19:36:40 +09:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2021-05-21 09:59:26 +02:00
										 |  |  | 		tx, _ = types.SignTx(types.NewTransaction(b.txPool.Nonce(testBankAddress), testUserAddress, big.NewInt(1000), params.TxGas, gasPrice, nil), types.HomesteadSigner{}, testBankKey) | 
					
						
							| 
									
										
										
										
											2019-10-20 19:36:40 +09:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return tx | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func newTestWorker(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, db ethdb.Database, blocks int) (*worker, *testWorkerBackend) { | 
					
						
							|  |  |  | 	backend := newTestWorkerBackend(t, chainConfig, engine, db, blocks) | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	backend.txPool.AddLocals(pendingTxs) | 
					
						
							| 
									
										
										
										
											2019-11-20 18:36:41 +08:00
										 |  |  | 	w := newWorker(testConfig, chainConfig, engine, backend, new(event.TypeMux), nil, false) | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	w.setEtherbase(testBankAddress) | 
					
						
							|  |  |  | 	return w, backend | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-20 19:36:40 +09:00
										 |  |  | func TestGenerateBlockAndImportEthash(t *testing.T) { | 
					
						
							|  |  |  | 	testGenerateBlockAndImport(t, false) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestGenerateBlockAndImportClique(t *testing.T) { | 
					
						
							|  |  |  | 	testGenerateBlockAndImport(t, true) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testGenerateBlockAndImport(t *testing.T, isClique bool) { | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		engine      consensus.Engine | 
					
						
							|  |  |  | 		chainConfig *params.ChainConfig | 
					
						
							|  |  |  | 		db          = rawdb.NewMemoryDatabase() | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	if isClique { | 
					
						
							|  |  |  | 		chainConfig = params.AllCliqueProtocolChanges | 
					
						
							| 
									
										
										
										
											2019-10-30 19:07:30 +08:00
										 |  |  | 		chainConfig.Clique = ¶ms.CliqueConfig{Period: 1, Epoch: 30000} | 
					
						
							| 
									
										
										
										
											2019-10-20 19:36:40 +09:00
										 |  |  | 		engine = clique.New(chainConfig.Clique, db) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		chainConfig = params.AllEthashProtocolChanges | 
					
						
							|  |  |  | 		engine = ethash.NewFaker() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-21 09:59:26 +02:00
										 |  |  | 	chainConfig.LondonBlock = big.NewInt(0) | 
					
						
							| 
									
										
										
										
											2019-10-20 19:36:40 +09:00
										 |  |  | 	w, b := newTestWorker(t, chainConfig, engine, db, 0) | 
					
						
							|  |  |  | 	defer w.close() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 02:07:22 +08:00
										 |  |  | 	// This test chain imports the mined blocks. | 
					
						
							| 
									
										
										
										
											2019-10-20 19:36:40 +09:00
										 |  |  | 	db2 := rawdb.NewMemoryDatabase() | 
					
						
							|  |  |  | 	b.genesis.MustCommit(db2) | 
					
						
							| 
									
										
										
										
											2020-05-11 17:58:43 +02:00
										 |  |  | 	chain, _ := core.NewBlockChain(db2, nil, b.chain.Config(), engine, vm.Config{}, nil, nil) | 
					
						
							| 
									
										
										
										
											2019-10-20 19:36:40 +09:00
										 |  |  | 	defer chain.Stop() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 02:07:22 +08:00
										 |  |  | 	// Ignore empty commit here for less noise. | 
					
						
							| 
									
										
										
										
											2019-10-20 19:36:40 +09:00
										 |  |  | 	w.skipSealHook = func(task *task) bool { | 
					
						
							|  |  |  | 		return len(task.receipts) == 0 | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-11-20 18:36:41 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 02:07:22 +08:00
										 |  |  | 	// Wait for mined blocks. | 
					
						
							|  |  |  | 	sub := w.mux.Subscribe(core.NewMinedBlockEvent{}) | 
					
						
							|  |  |  | 	defer sub.Unsubscribe() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Start mining! | 
					
						
							|  |  |  | 	w.start() | 
					
						
							| 
									
										
										
										
											2020-02-20 20:05:54 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-30 19:07:30 +08:00
										 |  |  | 	for i := 0; i < 5; i++ { | 
					
						
							| 
									
										
										
										
											2019-10-20 19:36:40 +09:00
										 |  |  | 		b.txPool.AddLocal(b.newRandomTx(true)) | 
					
						
							|  |  |  | 		b.txPool.AddLocal(b.newRandomTx(false)) | 
					
						
							| 
									
										
										
										
											2019-11-29 21:22:08 +08:00
										 |  |  | 		w.postSideBlock(core.ChainSideEvent{Block: b.newRandomUncle()}) | 
					
						
							|  |  |  | 		w.postSideBlock(core.ChainSideEvent{Block: b.newRandomUncle()}) | 
					
						
							| 
									
										
										
										
											2020-04-04 02:07:22 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-20 19:36:40 +09:00
										 |  |  | 		select { | 
					
						
							| 
									
										
										
										
											2020-04-04 02:07:22 +08:00
										 |  |  | 		case ev := <-sub.Chan(): | 
					
						
							|  |  |  | 			block := ev.Data.(core.NewMinedBlockEvent).Block | 
					
						
							|  |  |  | 			if _, err := chain.InsertChain([]*types.Block{block}); err != nil { | 
					
						
							|  |  |  | 				t.Fatalf("failed to insert new mined block %d: %v", block.NumberU64(), err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		case <-time.After(3 * time.Second): // Worker needs 1s to include new changes. | 
					
						
							| 
									
										
										
										
											2019-10-20 19:36:40 +09:00
										 |  |  | 			t.Fatalf("timeout") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-20 19:36:40 +09:00
										 |  |  | 	w, _ := newTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 0) | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	defer w.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		taskIndex int | 
					
						
							| 
									
										
										
										
											2019-11-20 18:36:41 +08:00
										 |  |  | 		taskCh    = make(chan struct{}, 2) | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	) | 
					
						
							|  |  |  | 	checkEqual := func(t *testing.T, task *task, index int) { | 
					
						
							| 
									
										
										
										
											2019-11-20 18:36:41 +08:00
										 |  |  | 		// The first empty work without any txs included | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 		receiptLen, balance := 0, big.NewInt(0) | 
					
						
							|  |  |  | 		if index == 1 { | 
					
						
							| 
									
										
										
										
											2019-11-20 18:36:41 +08:00
										 |  |  | 			// The second full work with 1 tx included | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 			receiptLen, balance = 1, big.NewInt(1000) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if len(task.receipts) != receiptLen { | 
					
						
							| 
									
										
										
										
											2019-11-20 18:36:41 +08:00
										 |  |  | 			t.Fatalf("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 { | 
					
						
							| 
									
										
										
										
											2019-11-20 18:36:41 +08:00
										 |  |  | 			t.Fatalf("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{}{} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-11-20 18:36:41 +08:00
										 |  |  | 	w.skipSealHook = func(task *task) bool { return true } | 
					
						
							| 
									
										
										
										
											2018-08-15 19:09:17 +08:00
										 |  |  | 	w.fullTaskHook = func() { | 
					
						
							| 
									
										
										
										
											2020-06-09 11:39:19 +02:00
										 |  |  | 		time.Sleep(100 * time.Millisecond) | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-11-20 18:36:41 +08:00
										 |  |  | 	w.start() // Start mining! | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	for i := 0; i < 2; i += 1 { | 
					
						
							|  |  |  | 		select { | 
					
						
							|  |  |  | 		case <-taskCh: | 
					
						
							| 
									
										
										
										
											2019-11-20 18:36:41 +08:00
										 |  |  | 		case <-time.NewTimer(3 * 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() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-20 19:36:40 +09:00
										 |  |  | 	w, b := newTestWorker(t, ethashChainConfig, ethash, rawdb.NewMemoryDatabase(), 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 { | 
					
						
							| 
									
										
										
										
											2019-11-20 18:36:41 +08:00
										 |  |  | 			// The first task is an empty task, the second | 
					
						
							|  |  |  | 			// one has 1 pending tx, the third one has 1 tx | 
					
						
							|  |  |  | 			// and 1 uncle. | 
					
						
							| 
									
										
										
										
											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) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	w.start() | 
					
						
							| 
									
										
										
										
											2018-08-28 16:48:20 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-15 19:09:17 +08:00
										 |  |  | 	for i := 0; i < 2; i += 1 { | 
					
						
							|  |  |  | 		select { | 
					
						
							|  |  |  | 		case <-taskCh: | 
					
						
							|  |  |  | 		case <-time.NewTimer(time.Second).C: | 
					
						
							|  |  |  | 			t.Error("new task timeout") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-29 21:22:08 +08:00
										 |  |  | 	w.postSideBlock(core.ChainSideEvent{Block: b.uncleBlock}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-15 19:09:17 +08:00
										 |  |  | 	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() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-20 19:36:40 +09:00
										 |  |  | 	w, b := newTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 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 { | 
					
						
							| 
									
										
										
										
											2019-11-20 18:36:41 +08:00
										 |  |  | 			// The first task is an empty task, the second | 
					
						
							|  |  |  | 			// one has 1 pending tx, the third one has 2 txs | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | 			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) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	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() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-20 19:36:40 +09:00
										 |  |  | 	w, _ := newTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 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 | 
					
						
							| 
									
										
										
										
											2019-11-20 18:36:41 +08:00
										 |  |  | 		start    uint32 | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | 	) | 
					
						
							|  |  |  | 	w.resubmitHook = func(minInterval time.Duration, recommitInterval time.Duration) { | 
					
						
							|  |  |  | 		// Short circuit if interval checking hasn't started. | 
					
						
							| 
									
										
										
										
											2019-11-20 18:36:41 +08:00
										 |  |  | 		if atomic.LoadUint32(&start) == 0 { | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | 			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{}{} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	w.start() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-20 18:36:41 +08:00
										 |  |  | 	time.Sleep(time.Second) // Ensure two tasks have been summitted due to start opt | 
					
						
							|  |  |  | 	atomic.StoreUint32(&start, 1) | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	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") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |