github.com/EgonCoin/EgonChain@v1.10.16/miner/miner_test.go (about) 1 // Copyright 2020 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 implements Ethereum block creation and mining. 18 package miner 19 20 import ( 21 "errors" 22 "testing" 23 "time" 24 25 "github.com/EgonCoin/EgonChain/common" 26 "github.com/EgonCoin/EgonChain/consensus/clique" 27 "github.com/EgonCoin/EgonChain/core" 28 "github.com/EgonCoin/EgonChain/core/rawdb" 29 "github.com/EgonCoin/EgonChain/core/state" 30 "github.com/EgonCoin/EgonChain/core/types" 31 "github.com/EgonCoin/EgonChain/core/vm" 32 "github.com/EgonCoin/EgonChain/eth/downloader" 33 "github.com/EgonCoin/EgonChain/ethdb/memorydb" 34 "github.com/EgonCoin/EgonChain/event" 35 "github.com/EgonCoin/EgonChain/trie" 36 ) 37 38 type mockBackend struct { 39 bc *core.BlockChain 40 txPool *core.TxPool 41 } 42 43 func NewMockBackend(bc *core.BlockChain, txPool *core.TxPool) *mockBackend { 44 return &mockBackend{ 45 bc: bc, 46 txPool: txPool, 47 } 48 } 49 50 func (m *mockBackend) BlockChain() *core.BlockChain { 51 return m.bc 52 } 53 54 func (m *mockBackend) TxPool() *core.TxPool { 55 return m.txPool 56 } 57 58 func (m *mockBackend) StateAtBlock(block *types.Block, reexec uint64, base *state.StateDB, checkLive bool, preferDisk bool) (statedb *state.StateDB, err error) { 59 return nil, errors.New("not supported") 60 } 61 62 type testBlockChain struct { 63 statedb *state.StateDB 64 gasLimit uint64 65 chainHeadFeed *event.Feed 66 } 67 68 func (bc *testBlockChain) CurrentBlock() *types.Block { 69 return types.NewBlock(&types.Header{ 70 GasLimit: bc.gasLimit, 71 }, nil, nil, nil, trie.NewStackTrie(nil)) 72 } 73 74 func (bc *testBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block { 75 return bc.CurrentBlock() 76 } 77 78 func (bc *testBlockChain) StateAt(common.Hash) (*state.StateDB, error) { 79 return bc.statedb, nil 80 } 81 82 func (bc *testBlockChain) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription { 83 return bc.chainHeadFeed.Subscribe(ch) 84 } 85 86 func TestMiner(t *testing.T) { 87 miner, mux, cleanup := createMiner(t) 88 defer cleanup(false) 89 miner.Start(common.HexToAddress("0x12345")) 90 waitForMiningState(t, miner, true) 91 // Start the downloader 92 mux.Post(downloader.StartEvent{}) 93 waitForMiningState(t, miner, false) 94 // Stop the downloader and wait for the update loop to run 95 mux.Post(downloader.DoneEvent{}) 96 waitForMiningState(t, miner, true) 97 98 // Subsequent downloader events after a successful DoneEvent should not cause the 99 // miner to start or stop. This prevents a security vulnerability 100 // that would allow entities to present fake high blocks that would 101 // stop mining operations by causing a downloader sync 102 // until it was discovered they were invalid, whereon mining would resume. 103 mux.Post(downloader.StartEvent{}) 104 waitForMiningState(t, miner, true) 105 106 mux.Post(downloader.FailedEvent{}) 107 waitForMiningState(t, miner, true) 108 } 109 110 // TestMinerDownloaderFirstFails tests that mining is only 111 // permitted to run indefinitely once the downloader sees a DoneEvent (success). 112 // An initial FailedEvent should allow mining to stop on a subsequent 113 // downloader StartEvent. 114 func TestMinerDownloaderFirstFails(t *testing.T) { 115 miner, mux, cleanup := createMiner(t) 116 defer cleanup(false) 117 miner.Start(common.HexToAddress("0x12345")) 118 waitForMiningState(t, miner, true) 119 // Start the downloader 120 mux.Post(downloader.StartEvent{}) 121 waitForMiningState(t, miner, false) 122 123 // Stop the downloader and wait for the update loop to run 124 mux.Post(downloader.FailedEvent{}) 125 waitForMiningState(t, miner, true) 126 127 // Since the downloader hasn't yet emitted a successful DoneEvent, 128 // we expect the miner to stop on next StartEvent. 129 mux.Post(downloader.StartEvent{}) 130 waitForMiningState(t, miner, false) 131 132 // Downloader finally succeeds. 133 mux.Post(downloader.DoneEvent{}) 134 waitForMiningState(t, miner, true) 135 136 // Downloader starts again. 137 // Since it has achieved a DoneEvent once, we expect miner 138 // state to be unchanged. 139 mux.Post(downloader.StartEvent{}) 140 waitForMiningState(t, miner, true) 141 142 mux.Post(downloader.FailedEvent{}) 143 waitForMiningState(t, miner, true) 144 } 145 146 func TestMinerStartStopAfterDownloaderEvents(t *testing.T) { 147 miner, mux, cleanup := createMiner(t) 148 defer cleanup(false) 149 miner.Start(common.HexToAddress("0x12345")) 150 waitForMiningState(t, miner, true) 151 // Start the downloader 152 mux.Post(downloader.StartEvent{}) 153 waitForMiningState(t, miner, false) 154 155 // Downloader finally succeeds. 156 mux.Post(downloader.DoneEvent{}) 157 waitForMiningState(t, miner, true) 158 159 miner.Stop() 160 waitForMiningState(t, miner, false) 161 162 miner.Start(common.HexToAddress("0x678910")) 163 waitForMiningState(t, miner, true) 164 165 miner.Stop() 166 waitForMiningState(t, miner, false) 167 } 168 169 func TestStartWhileDownload(t *testing.T) { 170 miner, mux, cleanup := createMiner(t) 171 defer cleanup(false) 172 waitForMiningState(t, miner, false) 173 miner.Start(common.HexToAddress("0x12345")) 174 waitForMiningState(t, miner, true) 175 // Stop the downloader and wait for the update loop to run 176 mux.Post(downloader.StartEvent{}) 177 waitForMiningState(t, miner, false) 178 // Starting the miner after the downloader should not work 179 miner.Start(common.HexToAddress("0x12345")) 180 waitForMiningState(t, miner, false) 181 } 182 183 func TestStartStopMiner(t *testing.T) { 184 miner, _, cleanup := createMiner(t) 185 defer cleanup(false) 186 waitForMiningState(t, miner, false) 187 miner.Start(common.HexToAddress("0x12345")) 188 waitForMiningState(t, miner, true) 189 miner.Stop() 190 waitForMiningState(t, miner, false) 191 192 } 193 194 func TestCloseMiner(t *testing.T) { 195 miner, _, cleanup := createMiner(t) 196 defer cleanup(true) 197 waitForMiningState(t, miner, false) 198 miner.Start(common.HexToAddress("0x12345")) 199 waitForMiningState(t, miner, true) 200 // Terminate the miner and wait for the update loop to run 201 miner.Close() 202 waitForMiningState(t, miner, false) 203 } 204 205 // TestMinerSetEtherbase checks that etherbase becomes set even if mining isn't 206 // possible at the moment 207 func TestMinerSetEtherbase(t *testing.T) { 208 miner, mux, cleanup := createMiner(t) 209 defer cleanup(false) 210 // Start with a 'bad' mining address 211 miner.Start(common.HexToAddress("0xdead")) 212 waitForMiningState(t, miner, true) 213 // Start the downloader 214 mux.Post(downloader.StartEvent{}) 215 waitForMiningState(t, miner, false) 216 // Now user tries to configure proper mining address 217 miner.Start(common.HexToAddress("0x1337")) 218 // Stop the downloader and wait for the update loop to run 219 mux.Post(downloader.DoneEvent{}) 220 221 waitForMiningState(t, miner, true) 222 // The miner should now be using the good address 223 if got, exp := miner.coinbase, common.HexToAddress("0x1337"); got != exp { 224 t.Fatalf("Wrong coinbase, got %x expected %x", got, exp) 225 } 226 } 227 228 // waitForMiningState waits until either 229 // * the desired mining state was reached 230 // * a timeout was reached which fails the test 231 func waitForMiningState(t *testing.T, m *Miner, mining bool) { 232 t.Helper() 233 234 var state bool 235 for i := 0; i < 100; i++ { 236 time.Sleep(10 * time.Millisecond) 237 if state = m.Mining(); state == mining { 238 return 239 } 240 } 241 t.Fatalf("Mining() == %t, want %t", state, mining) 242 } 243 244 func createMiner(t *testing.T) (*Miner, *event.TypeMux, func(skipMiner bool)) { 245 // Create Ethash config 246 config := Config{ 247 Etherbase: common.HexToAddress("123456789"), 248 } 249 // Create chainConfig 250 memdb := memorydb.New() 251 chainDB := rawdb.NewDatabase(memdb) 252 genesis := core.DeveloperGenesisBlock(15, 11_500_000, common.HexToAddress("12345")) 253 chainConfig, _, err := core.SetupGenesisBlock(chainDB, genesis) 254 if err != nil { 255 t.Fatalf("can't create new chain config: %v", err) 256 } 257 // Create consensus engine 258 engine := clique.New(chainConfig.Clique, chainDB) 259 // Create Ethereum backend 260 bc, err := core.NewBlockChain(chainDB, nil, chainConfig, engine, vm.Config{}, nil, nil) 261 if err != nil { 262 t.Fatalf("can't create new chain %v", err) 263 } 264 statedb, _ := state.New(common.Hash{}, state.NewDatabase(chainDB), nil) 265 blockchain := &testBlockChain{statedb, 10000000, new(event.Feed)} 266 267 pool := core.NewTxPool(testTxPoolConfig, chainConfig, blockchain) 268 backend := NewMockBackend(bc, pool) 269 // Create event Mux 270 mux := new(event.TypeMux) 271 // Create Miner 272 miner := New(backend, &config, chainConfig, mux, engine, nil) 273 cleanup := func(skipMiner bool) { 274 bc.Stop() 275 engine.Close() 276 pool.Stop() 277 if !skipMiner { 278 miner.Close() 279 } 280 } 281 return miner, mux, cleanup 282 }