github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/miner/miner.go (about) 1 // Copyright 2014 The Spectrum Authors 2 // This file is part of the Spectrum library. 3 // 4 // The Spectrum 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 Spectrum 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 Spectrum 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 "fmt" 22 "sync" 23 "sync/atomic" 24 25 "time" 26 27 "github.com/SmartMeshFoundation/Spectrum/accounts" 28 "github.com/SmartMeshFoundation/Spectrum/common" 29 "github.com/SmartMeshFoundation/Spectrum/consensus" 30 "github.com/SmartMeshFoundation/Spectrum/consensus/tribe" 31 "github.com/SmartMeshFoundation/Spectrum/core" 32 "github.com/SmartMeshFoundation/Spectrum/core/state" 33 "github.com/SmartMeshFoundation/Spectrum/core/types" 34 "github.com/SmartMeshFoundation/Spectrum/eth/downloader" 35 "github.com/SmartMeshFoundation/Spectrum/ethdb" 36 "github.com/SmartMeshFoundation/Spectrum/event" 37 "github.com/SmartMeshFoundation/Spectrum/log" 38 "github.com/SmartMeshFoundation/Spectrum/params" 39 ) 40 41 // Backend wraps all methods required for mining. 42 type Backend interface { 43 AccountManager() *accounts.Manager 44 BlockChain() *core.BlockChain 45 TxPool() *core.TxPool 46 ChainDb() ethdb.Database 47 } 48 49 // Miner creates blocks and searches for proof-of-work values. 50 type Miner struct { 51 stop *sync.Map 52 mux *event.TypeMux 53 54 worker *worker 55 56 coinbase common.Address 57 mining int32 58 eth Backend 59 engine consensus.Engine 60 61 canStart int32 // can start indicates whether we can start the mining operation 62 shouldStart int32 // should start indicates whether we should start after sync 63 } 64 65 func New(eth Backend, config *params.ChainConfig, mux *event.TypeMux, engine consensus.Engine) *Miner { 66 miner := &Miner{ 67 eth: eth, 68 mux: mux, 69 engine: engine, 70 worker: newWorker(config, engine, common.Address{}, eth, mux), 71 canStart: 1, 72 stop: new(sync.Map), 73 } 74 miner.Register(NewCpuAgent(eth.BlockChain(), engine)) 75 go miner.update() 76 if tribe, ok := miner.engine.(*tribe.Tribe); ok { 77 close(params.TribeReadyForAcceptTxs) 78 go func() { 79 log.Info("miner wait miner address") 80 rtn := make(chan common.Address) 81 tribe.Status.GetMinerAddressByChan(rtn) 82 tma := <-rtn 83 log.Info("miner get miner address") 84 go miner.Start(tma) 85 log.Info("👷 Tribe and miner is started .") 86 }() 87 } 88 return miner 89 } 90 91 // update keeps track of the downloader events. Please be aware that this is a one shot type of update loop. 92 // It's entered once and as soon as `Done` or `Failed` has been broadcasted the events are unregistered and 93 // the loop is exited. This to prevent a major security vuln where external parties can DOS you with blocks 94 // and halt your mining operation for as long as the DOS continues. 95 func (self *Miner) update() { 96 events := self.mux.Subscribe(downloader.StartEvent{}, downloader.DoneEvent{}, downloader.FailedEvent{}) 97 out: 98 for ev := range events.Chan() { 99 switch ev.Data.(type) { 100 case downloader.StartEvent: 101 atomic.StoreInt32(&self.canStart, 0) 102 if self.Mining() { 103 self.Stop() 104 atomic.StoreInt32(&self.shouldStart, 1) 105 log.Info("Mining aborted due to sync") 106 } 107 case downloader.DoneEvent, downloader.FailedEvent: 108 shouldStart := atomic.LoadInt32(&self.shouldStart) == 1 109 110 atomic.StoreInt32(&self.canStart, 1) 111 atomic.StoreInt32(&self.shouldStart, 0) 112 if shouldStart { 113 log.Info("miner start after sync complete") 114 go self.Start(self.coinbase) 115 } 116 // unsubscribe. we're only interested in this event once 117 events.Unsubscribe() 118 // stop immediately and ignore all further pending events 119 break out 120 } 121 } 122 } 123 124 // liangc : The caller will prevents multiple execution. 125 // async run 126 var xx int32 = 0 127 128 func (self *Miner) Start(coinbase common.Address) { 129 stop := make(chan struct{}) 130 self.stop.Store(stop, struct{}{}) 131 atomic.AddInt32(&xx, 1) 132 atomic.StoreInt32(&self.shouldStart, 1) 133 134 self.worker.setEtherbase(coinbase) 135 self.coinbase = coinbase 136 if atomic.LoadInt32(&self.canStart) == 0 { 137 log.Info("Network syncing, will start miner afterwards") 138 return 139 } 140 atomic.StoreInt32(&self.mining, 1) 141 log.Info("Starting mining operation") 142 143 if tribe, ok := self.engine.(*tribe.Tribe); ok && self.eth.BlockChain().CurrentBlock().NumberU64() > 3 { 144 i := 0 145 for { 146 log.Debug("<<MinerStart>> loop_start", "i", i, "num", self.eth.BlockChain().CurrentBlock().Number()) 147 m := tribe.Status.GetMinerAddress() 148 s, err := self.worker.chain.State() 149 if err != nil { 150 log.Error("miner start fail", err) 151 } 152 cn := self.eth.BlockChain().CurrentBlock().Number() 153 // SIP100 skip this verfiy 154 if params.IsSIP100Block(cn) { 155 break 156 } 157 if params.IsReadyMeshbox(cn) { 158 if params.MeshboxExistAddress(m) { 159 break 160 } 161 } 162 if s.GetBalance(m).Cmp(params.ChiefBaseBalance) >= 0 { 163 break 164 } 165 if atomic.LoadInt32(&self.mining) == 0 { 166 return 167 } 168 select { 169 case <-stop: 170 return 171 default: 172 <-time.After(time.Second * 7) 173 } 174 i++ 175 } 176 } 177 // may be pending at 'tribe.WaitingNomination' in 'worker.start' so change to async 178 go func() { 179 s := make(chan int) 180 self.worker.start(s) 181 select { 182 case <-stop: 183 return 184 case <-s: 185 self.worker.commitNewWork() 186 } 187 }() 188 189 } 190 191 func (self *Miner) dostop() { 192 self.stop.Range(func(k, v interface{}) bool { 193 defer func() { recover() }() 194 defer close(k.(chan struct{})) 195 self.stop.Delete(k) 196 return true 197 }) 198 } 199 200 func (self *Miner) Stop() { 201 self.dostop() 202 self.worker.stop() 203 atomic.StoreInt32(&self.mining, 0) 204 atomic.StoreInt32(&self.shouldStart, 0) 205 } 206 207 func (self *Miner) Register(agent Agent) { 208 if self.Mining() { 209 agent.Start() 210 } 211 self.worker.register(agent) 212 } 213 214 func (self *Miner) Unregister(agent Agent) { 215 self.worker.unregister(agent) 216 } 217 218 func (self *Miner) Mining() bool { 219 return atomic.LoadInt32(&self.mining) > 0 220 } 221 222 func (self *Miner) HashRate() (tot int64) { 223 if pow, ok := self.engine.(consensus.PoW); ok { 224 tot += int64(pow.Hashrate()) 225 } 226 // do we care this might race? is it worth we're rewriting some 227 // aspects of the worker/locking up agents so we can get an accurate 228 // hashrate? 229 for agent := range self.worker.agents { 230 if _, ok := agent.(*CpuAgent); !ok { 231 tot += agent.GetHashRate() 232 } 233 } 234 return 235 } 236 237 func (self *Miner) SetExtra(extra []byte) error { 238 if uint64(len(extra)) > params.MaximumExtraDataSize { 239 return fmt.Errorf("Extra exceeds max length. %d > %v", len(extra), params.MaximumExtraDataSize) 240 } 241 self.worker.setExtra(extra) 242 return nil 243 } 244 245 // Pending returns the currently pending block and associated state. 246 func (self *Miner) Pending() (*types.Block, *state.StateDB) { 247 return self.worker.pending() 248 } 249 250 // PendingBlock returns the currently pending block. 251 // 252 // Note, to access both the pending block and the pending state 253 // simultaneously, please use Pending(), as the pending state can 254 // change between multiple method calls 255 func (self *Miner) PendingBlock() *types.Block { 256 return self.worker.pendingBlock() 257 } 258 259 func (self *Miner) SetEtherbase(addr common.Address) { 260 self.coinbase = addr 261 self.worker.setEtherbase(addr) 262 }