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