github.com/core-coin/go-core/v2@v2.1.9/miner/miner_test.go (about) 1 // Copyright 2020 by the Authors 2 // This file is part of the go-core library. 3 // 4 // The go-core 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-core 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-core library. If not, see <http://www.gnu.org/licenses/>. 16 17 // Package miner implements Core block creation and mining. 18 package miner 19 20 import ( 21 "testing" 22 "time" 23 24 "github.com/core-coin/go-core/v2/xcbdb/memorydb" 25 26 "github.com/core-coin/go-core/v2/common" 27 "github.com/core-coin/go-core/v2/consensus/clique" 28 "github.com/core-coin/go-core/v2/core" 29 "github.com/core-coin/go-core/v2/core/rawdb" 30 "github.com/core-coin/go-core/v2/core/state" 31 "github.com/core-coin/go-core/v2/core/types" 32 "github.com/core-coin/go-core/v2/core/vm" 33 "github.com/core-coin/go-core/v2/event" 34 "github.com/core-coin/go-core/v2/trie" 35 "github.com/core-coin/go-core/v2/xcb/downloader" 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 energyLimit uint64 61 chainHeadFeed *event.Feed 62 } 63 64 func (bc *testBlockChain) CurrentBlock() *types.Block { 65 return types.NewBlock(&types.Header{ 66 EnergyLimit: bc.energyLimit, 67 }, nil, nil, nil, new(trie.Trie)) 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 := createMiner(t) 84 addr, err := common.HexToAddress("cb375a538daf54f2e568bb4237357b1cee1aa3cb7eba") 85 if err != nil { 86 t.Error(err) 87 } 88 miner.Start(addr) 89 waitForMiningState(t, miner, true) 90 // Start the downloader 91 mux.Post(downloader.StartEvent{}) 92 waitForMiningState(t, miner, false) 93 // Stop the downloader and wait for the update loop to run 94 mux.Post(downloader.DoneEvent{}) 95 waitForMiningState(t, miner, true) 96 97 // Subsequent downloader events after a successful DoneEvent should not cause the 98 // miner to start or stop. This prevents a security vulnerability 99 // that would allow entities to present fake high blocks that would 100 // stop mining operations by causing a downloader sync 101 // until it was discovered they were invalid, whereon mining would resume. 102 mux.Post(downloader.StartEvent{}) 103 waitForMiningState(t, miner, true) 104 105 mux.Post(downloader.FailedEvent{}) 106 waitForMiningState(t, miner, true) 107 } 108 109 // TestMinerDownloaderFirstFails tests that mining is only 110 // permitted to run indefinitely once the downloader sees a DoneEvent (success). 111 // An initial FailedEvent should allow mining to stop on a subsequent 112 // downloader StartEvent. 113 func TestMinerDownloaderFirstFails(t *testing.T) { 114 addr, err := common.HexToAddress("cb375a538daf54f2e568bb4237357b1cee1aa3cb7eba") 115 if err != nil { 116 t.Error(err) 117 } 118 miner, mux := createMiner(t) 119 miner.Start(addr) 120 waitForMiningState(t, miner, true) 121 // Start the downloader 122 mux.Post(downloader.StartEvent{}) 123 waitForMiningState(t, miner, false) 124 125 // Stop the downloader and wait for the update loop to run 126 mux.Post(downloader.FailedEvent{}) 127 waitForMiningState(t, miner, true) 128 129 // Since the downloader hasn't yet emitted a successful DoneEvent, 130 // we expect the miner to stop on next StartEvent. 131 mux.Post(downloader.StartEvent{}) 132 waitForMiningState(t, miner, false) 133 134 // Downloader finally succeeds. 135 mux.Post(downloader.DoneEvent{}) 136 waitForMiningState(t, miner, true) 137 138 // Downloader starts again. 139 // Since it has achieved a DoneEvent once, we expect miner 140 // state to be unchanged. 141 mux.Post(downloader.StartEvent{}) 142 waitForMiningState(t, miner, true) 143 144 mux.Post(downloader.FailedEvent{}) 145 waitForMiningState(t, miner, true) 146 } 147 148 func TestMinerStartStopAfterDownloaderEvents(t *testing.T) { 149 addr, err := common.HexToAddress("cb375a538daf54f2e568bb4237357b1cee1aa3cb7eba") 150 if err != nil { 151 t.Error(err) 152 } 153 addr2, err := common.HexToAddress("cb76a631db606f1452ddc2432931d611f1d5b126f848") 154 if err != nil { 155 t.Error(err) 156 } 157 158 miner, mux := createMiner(t) 159 160 miner.Start(addr) 161 waitForMiningState(t, miner, true) 162 // Start the downloader 163 mux.Post(downloader.StartEvent{}) 164 waitForMiningState(t, miner, false) 165 166 // Downloader finally succeeds. 167 mux.Post(downloader.DoneEvent{}) 168 waitForMiningState(t, miner, true) 169 170 miner.Stop() 171 waitForMiningState(t, miner, false) 172 173 miner.Start(addr2) 174 waitForMiningState(t, miner, true) 175 176 miner.Stop() 177 waitForMiningState(t, miner, false) 178 } 179 180 func TestStartWhileDownload(t *testing.T) { 181 miner, mux := createMiner(t) 182 addr, err := common.HexToAddress("cb375a538daf54f2e568bb4237357b1cee1aa3cb7eba") 183 if err != nil { 184 t.Error(err) 185 } 186 waitForMiningState(t, miner, false) 187 miner.Start(addr) 188 waitForMiningState(t, miner, true) 189 // Stop the downloader and wait for the update loop to run 190 mux.Post(downloader.StartEvent{}) 191 waitForMiningState(t, miner, false) 192 // Starting the miner after the downloader should not work 193 miner.Start(addr) 194 waitForMiningState(t, miner, false) 195 } 196 197 func TestStartStopMiner(t *testing.T) { 198 miner, _ := createMiner(t) 199 addr, err := common.HexToAddress("cb375a538daf54f2e568bb4237357b1cee1aa3cb7eba") 200 if err != nil { 201 t.Error(err) 202 } 203 waitForMiningState(t, miner, false) 204 miner.Start(addr) 205 waitForMiningState(t, miner, true) 206 miner.Stop() 207 waitForMiningState(t, miner, false) 208 } 209 210 func TestCloseMiner(t *testing.T) { 211 miner, _ := createMiner(t) 212 addr, err := common.HexToAddress("cb375a538daf54f2e568bb4237357b1cee1aa3cb7eba") 213 if err != nil { 214 t.Error(err) 215 } 216 waitForMiningState(t, miner, false) 217 miner.Start(addr) 218 waitForMiningState(t, miner, true) 219 // Terminate the miner and wait for the update loop to run 220 miner.Close() 221 waitForMiningState(t, miner, false) 222 } 223 224 // TestMinerSetCorebase checks that corebase becomes set even if mining isn't 225 // possible at the moment 226 func TestMinerSetCorebase(t *testing.T) { 227 miner, mux := createMiner(t) 228 addr, err := common.HexToAddress("cb375a538daf54f2e568bb4237357b1cee1aa3cb7eba") 229 if err != nil { 230 t.Error(err) 231 } 232 addr2, err := common.HexToAddress("cb27de521e43741cf785cbad450d5649187b9612018f") 233 if err != nil { 234 t.Error(err) 235 } 236 // Start with a 'bad' mining address 237 miner.Start(addr2) 238 waitForMiningState(t, miner, true) 239 // Start the downloader 240 mux.Post(downloader.StartEvent{}) 241 waitForMiningState(t, miner, false) 242 // Now user tries to configure proper mining address 243 miner.Start(addr) 244 // Stop the downloader and wait for the update loop to run 245 mux.Post(downloader.DoneEvent{}) 246 247 waitForMiningState(t, miner, true) 248 // The miner should now be using the good address 249 if got, exp := miner.coinbase, addr; got != exp { 250 t.Fatalf("Wrong coinbase, got %x expected %x", got, exp) 251 } 252 } 253 254 // waitForMiningState waits until either 255 // * the desired mining state was reached 256 // * a timeout was reached which fails the test 257 func waitForMiningState(t *testing.T, m *Miner, mining bool) { 258 t.Helper() 259 260 var state bool 261 for i := 0; i < 100; i++ { 262 time.Sleep(10 * time.Millisecond) 263 if state = m.Mining(); state == mining { 264 return 265 } 266 } 267 t.Fatalf("Mining() == %t, want %t", state, mining) 268 } 269 270 func createMiner(t *testing.T) (*Miner, *event.TypeMux) { 271 // Create Cryptore config 272 addr, err := common.HexToAddress("cb375a538daf54f2e568bb4237357b1cee1aa3cb7eba") 273 if err != nil { 274 t.Error(err) 275 } 276 addr2, err := common.HexToAddress("cb270000000000000000000000000000000000000001") 277 if err != nil { 278 t.Error(err) 279 } 280 config := Config{ 281 Corebase: addr2, 282 } 283 // Create chainConfig 284 memdb := memorydb.New() 285 chainDB := rawdb.NewDatabase(memdb) 286 genesis := core.DeveloperGenesisBlock(15, addr) 287 chainConfig, _, err := core.SetupGenesisBlock(chainDB, genesis) 288 if err != nil { 289 t.Fatalf("can't create new chain config: %v", err) 290 } 291 // Create consensus engine 292 engine := clique.New(chainConfig.Clique, chainDB) 293 // Create Core backend 294 bc, err := core.NewBlockChain(chainDB, nil, chainConfig, engine, vm.Config{}, nil, nil) 295 if err != nil { 296 t.Fatalf("can't create new chain %v", err) 297 } 298 statedb, _ := state.New(common.Hash{}, state.NewDatabase(chainDB), nil) 299 blockchain := &testBlockChain{statedb, 10000000, new(event.Feed)} 300 301 pool := core.NewTxPool(testTxPoolConfig, chainConfig, blockchain) 302 backend := NewMockBackend(bc, pool) 303 // Create event Mux 304 mux := new(event.TypeMux) 305 // Create Miner 306 return New(backend, &config, chainConfig, mux, engine, nil), mux 307 }