github.com/theQRL/go-zond@v0.1.1/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 "math/big" 23 "testing" 24 "time" 25 26 "github.com/theQRL/go-zond/common" 27 "github.com/theQRL/go-zond/consensus/clique" 28 "github.com/theQRL/go-zond/core" 29 "github.com/theQRL/go-zond/core/rawdb" 30 "github.com/theQRL/go-zond/core/state" 31 "github.com/theQRL/go-zond/core/txpool" 32 "github.com/theQRL/go-zond/core/txpool/legacypool" 33 "github.com/theQRL/go-zond/core/types" 34 "github.com/theQRL/go-zond/core/vm" 35 "github.com/theQRL/go-zond/crypto" 36 "github.com/theQRL/go-zond/event" 37 "github.com/theQRL/go-zond/params" 38 "github.com/theQRL/go-zond/trie" 39 "github.com/theQRL/go-zond/zond/downloader" 40 ) 41 42 type mockBackend struct { 43 bc *core.BlockChain 44 txPool *txpool.TxPool 45 } 46 47 func NewMockBackend(bc *core.BlockChain, txPool *txpool.TxPool) *mockBackend { 48 return &mockBackend{ 49 bc: bc, 50 txPool: txPool, 51 } 52 } 53 54 func (m *mockBackend) BlockChain() *core.BlockChain { 55 return m.bc 56 } 57 58 func (m *mockBackend) TxPool() *txpool.TxPool { 59 return m.txPool 60 } 61 62 func (m *mockBackend) StateAtBlock(block *types.Block, reexec uint64, base *state.StateDB, checkLive bool, preferDisk bool) (statedb *state.StateDB, err error) { 63 return nil, errors.New("not supported") 64 } 65 66 type testBlockChain struct { 67 config *params.ChainConfig 68 statedb *state.StateDB 69 gasLimit uint64 70 chainHeadFeed *event.Feed 71 } 72 73 func (bc *testBlockChain) Config() *params.ChainConfig { 74 return bc.config 75 } 76 77 func (bc *testBlockChain) CurrentBlock() *types.Header { 78 return &types.Header{ 79 Number: new(big.Int), 80 GasLimit: bc.gasLimit, 81 } 82 } 83 84 func (bc *testBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block { 85 return types.NewBlock(bc.CurrentBlock(), nil, nil, nil, trie.NewStackTrie(nil)) 86 } 87 88 func (bc *testBlockChain) StateAt(common.Hash) (*state.StateDB, error) { 89 return bc.statedb, nil 90 } 91 92 func (bc *testBlockChain) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription { 93 return bc.chainHeadFeed.Subscribe(ch) 94 } 95 96 func TestMiner(t *testing.T) { 97 miner, mux, cleanup := createMiner(t) 98 defer cleanup(false) 99 100 miner.Start() 101 waitForMiningState(t, miner, true) 102 // Start the downloader 103 mux.Post(downloader.StartEvent{}) 104 waitForMiningState(t, miner, false) 105 // Stop the downloader and wait for the update loop to run 106 mux.Post(downloader.DoneEvent{}) 107 waitForMiningState(t, miner, true) 108 109 // Subsequent downloader events after a successful DoneEvent should not cause the 110 // miner to start or stop. This prevents a security vulnerability 111 // that would allow entities to present fake high blocks that would 112 // stop mining operations by causing a downloader sync 113 // until it was discovered they were invalid, whereon mining would resume. 114 mux.Post(downloader.StartEvent{}) 115 waitForMiningState(t, miner, true) 116 117 mux.Post(downloader.FailedEvent{}) 118 waitForMiningState(t, miner, true) 119 } 120 121 // TestMinerDownloaderFirstFails tests that mining is only 122 // permitted to run indefinitely once the downloader sees a DoneEvent (success). 123 // An initial FailedEvent should allow mining to stop on a subsequent 124 // downloader StartEvent. 125 func TestMinerDownloaderFirstFails(t *testing.T) { 126 miner, mux, cleanup := createMiner(t) 127 defer cleanup(false) 128 129 miner.Start() 130 waitForMiningState(t, miner, true) 131 // Start the downloader 132 mux.Post(downloader.StartEvent{}) 133 waitForMiningState(t, miner, false) 134 135 // Stop the downloader and wait for the update loop to run 136 mux.Post(downloader.FailedEvent{}) 137 waitForMiningState(t, miner, true) 138 139 // Since the downloader hasn't yet emitted a successful DoneEvent, 140 // we expect the miner to stop on next StartEvent. 141 mux.Post(downloader.StartEvent{}) 142 waitForMiningState(t, miner, false) 143 144 // Downloader finally succeeds. 145 mux.Post(downloader.DoneEvent{}) 146 waitForMiningState(t, miner, true) 147 148 // Downloader starts again. 149 // Since it has achieved a DoneEvent once, we expect miner 150 // state to be unchanged. 151 mux.Post(downloader.StartEvent{}) 152 waitForMiningState(t, miner, true) 153 154 mux.Post(downloader.FailedEvent{}) 155 waitForMiningState(t, miner, true) 156 } 157 158 func TestMinerStartStopAfterDownloaderEvents(t *testing.T) { 159 miner, mux, cleanup := createMiner(t) 160 defer cleanup(false) 161 162 miner.Start() 163 waitForMiningState(t, miner, true) 164 // Start the downloader 165 mux.Post(downloader.StartEvent{}) 166 waitForMiningState(t, miner, false) 167 168 // Downloader finally succeeds. 169 mux.Post(downloader.DoneEvent{}) 170 waitForMiningState(t, miner, true) 171 172 miner.Stop() 173 waitForMiningState(t, miner, false) 174 175 miner.Start() 176 waitForMiningState(t, miner, true) 177 178 miner.Stop() 179 waitForMiningState(t, miner, false) 180 } 181 182 func TestStartWhileDownload(t *testing.T) { 183 miner, mux, cleanup := createMiner(t) 184 defer cleanup(false) 185 waitForMiningState(t, miner, false) 186 miner.Start() 187 waitForMiningState(t, miner, true) 188 // Stop the downloader and wait for the update loop to run 189 mux.Post(downloader.StartEvent{}) 190 waitForMiningState(t, miner, false) 191 // Starting the miner after the downloader should not work 192 miner.Start() 193 waitForMiningState(t, miner, false) 194 } 195 196 func TestStartStopMiner(t *testing.T) { 197 miner, _, cleanup := createMiner(t) 198 defer cleanup(false) 199 waitForMiningState(t, miner, false) 200 miner.Start() 201 waitForMiningState(t, miner, true) 202 miner.Stop() 203 waitForMiningState(t, miner, false) 204 } 205 206 func TestCloseMiner(t *testing.T) { 207 miner, _, cleanup := createMiner(t) 208 defer cleanup(true) 209 waitForMiningState(t, miner, false) 210 miner.Start() 211 waitForMiningState(t, miner, true) 212 // Terminate the miner and wait for the update loop to run 213 miner.Close() 214 waitForMiningState(t, miner, false) 215 } 216 217 // TestMinerSetEtherbase checks that etherbase becomes set even if mining isn't 218 // possible at the moment 219 func TestMinerSetEtherbase(t *testing.T) { 220 miner, mux, cleanup := createMiner(t) 221 defer cleanup(false) 222 miner.Start() 223 waitForMiningState(t, miner, true) 224 // Start the downloader 225 mux.Post(downloader.StartEvent{}) 226 waitForMiningState(t, miner, false) 227 // Now user tries to configure proper mining address 228 miner.Start() 229 // Stop the downloader and wait for the update loop to run 230 mux.Post(downloader.DoneEvent{}) 231 waitForMiningState(t, miner, true) 232 233 coinbase := common.HexToAddress("0xdeedbeef") 234 miner.SetEtherbase(coinbase) 235 if addr := miner.worker.etherbase(); addr != coinbase { 236 t.Fatalf("Unexpected etherbase want %x got %x", coinbase, addr) 237 } 238 } 239 240 // waitForMiningState waits until either 241 // * the desired mining state was reached 242 // * a timeout was reached which fails the test 243 func waitForMiningState(t *testing.T, m *Miner, mining bool) { 244 t.Helper() 245 246 var state bool 247 for i := 0; i < 100; i++ { 248 time.Sleep(10 * time.Millisecond) 249 if state = m.Mining(); state == mining { 250 return 251 } 252 } 253 t.Fatalf("Mining() == %t, want %t", state, mining) 254 } 255 256 func minerTestGenesisBlock(period uint64, gasLimit uint64, faucet common.Address) *core.Genesis { 257 config := *params.AllCliqueProtocolChanges 258 config.Clique = ¶ms.CliqueConfig{ 259 Period: period, 260 Epoch: config.Clique.Epoch, 261 } 262 263 // Assemble and return the genesis with the precompiles and faucet pre-funded 264 return &core.Genesis{ 265 Config: &config, 266 ExtraData: append(append(make([]byte, 32), faucet[:]...), make([]byte, crypto.SignatureLength)...), 267 GasLimit: gasLimit, 268 BaseFee: big.NewInt(params.InitialBaseFee), 269 Difficulty: big.NewInt(1), 270 Alloc: map[common.Address]core.GenesisAccount{ 271 common.BytesToAddress([]byte{1}): {Balance: big.NewInt(1)}, // ECRecover 272 common.BytesToAddress([]byte{2}): {Balance: big.NewInt(1)}, // SHA256 273 common.BytesToAddress([]byte{3}): {Balance: big.NewInt(1)}, // RIPEMD 274 common.BytesToAddress([]byte{4}): {Balance: big.NewInt(1)}, // Identity 275 common.BytesToAddress([]byte{5}): {Balance: big.NewInt(1)}, // ModExp 276 common.BytesToAddress([]byte{6}): {Balance: big.NewInt(1)}, // ECAdd 277 common.BytesToAddress([]byte{7}): {Balance: big.NewInt(1)}, // ECScalarMul 278 common.BytesToAddress([]byte{8}): {Balance: big.NewInt(1)}, // ECPairing 279 common.BytesToAddress([]byte{9}): {Balance: big.NewInt(1)}, // BLAKE2b 280 faucet: {Balance: new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(9))}, 281 }, 282 } 283 } 284 func createMiner(t *testing.T) (*Miner, *event.TypeMux, func(skipMiner bool)) { 285 // Create Ethash config 286 config := Config{ 287 Etherbase: common.HexToAddress("123456789"), 288 } 289 // Create chainConfig 290 chainDB := rawdb.NewMemoryDatabase() 291 triedb := trie.NewDatabase(chainDB, nil) 292 genesis := minerTestGenesisBlock(15, 11_500_000, common.HexToAddress("12345")) 293 chainConfig, _, err := core.SetupGenesisBlock(chainDB, triedb, genesis) 294 if err != nil { 295 t.Fatalf("can't create new chain config: %v", err) 296 } 297 // Create consensus engine 298 engine := clique.New(chainConfig.Clique, chainDB) 299 // Create Ethereum backend 300 bc, err := core.NewBlockChain(chainDB, nil, genesis, nil, engine, vm.Config{}, nil, nil) 301 if err != nil { 302 t.Fatalf("can't create new chain %v", err) 303 } 304 statedb, _ := state.New(bc.Genesis().Root(), bc.StateCache(), nil) 305 blockchain := &testBlockChain{chainConfig, statedb, 10000000, new(event.Feed)} 306 307 pool := legacypool.New(testTxPoolConfig, blockchain) 308 txpool, _ := txpool.New(new(big.Int).SetUint64(testTxPoolConfig.PriceLimit), blockchain, []txpool.SubPool{pool}) 309 310 backend := NewMockBackend(bc, txpool) 311 // Create event Mux 312 mux := new(event.TypeMux) 313 // Create Miner 314 miner := New(backend, &config, chainConfig, mux, engine, nil) 315 cleanup := func(skipMiner bool) { 316 bc.Stop() 317 engine.Close() 318 txpool.Close() 319 if !skipMiner { 320 miner.Close() 321 } 322 } 323 return miner, mux, cleanup 324 }