github.com/dominant-strategies/go-quai@v0.28.2/core/miner.go (about) 1 // Copyright 2014 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 Quai block creation and mining. 18 package core 19 20 import ( 21 "fmt" 22 "runtime" 23 "time" 24 25 "github.com/dominant-strategies/go-quai/common" 26 "github.com/dominant-strategies/go-quai/common/hexutil" 27 "github.com/dominant-strategies/go-quai/consensus" 28 "github.com/dominant-strategies/go-quai/core/types" 29 "github.com/dominant-strategies/go-quai/ethdb" 30 "github.com/dominant-strategies/go-quai/event" 31 "github.com/dominant-strategies/go-quai/log" 32 "github.com/dominant-strategies/go-quai/params" 33 "github.com/dominant-strategies/go-quai/rlp" 34 ) 35 36 // Miner creates blocks and searches for proof-of-work values. 37 type Miner struct { 38 worker *worker 39 coinbase common.Address 40 hc *HeaderChain 41 engine consensus.Engine 42 startCh chan common.Address 43 stopCh chan struct{} 44 } 45 46 func New(hc *HeaderChain, txPool *TxPool, config *Config, db ethdb.Database, chainConfig *params.ChainConfig, engine consensus.Engine, isLocalBlock func(block *types.Header) bool, processingState bool) *Miner { 47 miner := &Miner{ 48 hc: hc, 49 engine: engine, 50 startCh: make(chan common.Address), 51 stopCh: make(chan struct{}), 52 worker: newWorker(config, chainConfig, db, engine, hc, txPool, isLocalBlock, true, processingState), 53 coinbase: config.Etherbase, 54 } 55 go miner.update() 56 57 miner.Start(miner.coinbase) 58 miner.SetExtra(miner.MakeExtraData(config.ExtraData)) 59 60 return miner 61 } 62 63 // update keeps track of the downloader events. Please be aware that this is a one shot type of update loop. 64 // It's entered once and as soon as `Done` or `Failed` has been broadcasted the events are unregistered and 65 // the loop is exited. This to prevent a major security vuln where external parties can DOS you with blocks 66 // and halt your mining operation for as long as the DOS continues. 67 func (miner *Miner) update() { 68 canStart := true 69 for { 70 select { 71 case addr := <-miner.startCh: 72 miner.SetEtherbase(addr) 73 if canStart { 74 miner.worker.start() 75 } 76 case <-miner.stopCh: 77 miner.worker.stop() 78 miner.worker.close() 79 return 80 } 81 } 82 } 83 84 func (miner *Miner) Start(coinbase common.Address) { 85 miner.startCh <- coinbase 86 } 87 88 func (miner *Miner) Stop() { 89 miner.stopCh <- struct{}{} 90 } 91 92 func (miner *Miner) Mining() bool { 93 return miner.worker.isRunning() 94 } 95 96 func (miner *Miner) StopMining() { 97 // Update the thread count within the consensus engine 98 type threaded interface { 99 SetThreads(threads int) 100 } 101 if th, ok := miner.engine.(threaded); ok { 102 th.SetThreads(-1) 103 } 104 // Stop the block creating itself 105 miner.Stop() 106 } 107 108 func (miner *Miner) Hashrate() uint64 { 109 if pow, ok := miner.engine.(consensus.PoW); ok { 110 return uint64(pow.Hashrate()) 111 } 112 return 0 113 } 114 115 func (miner *Miner) SetExtra(extra []byte) error { 116 if uint64(len(extra)) > params.MaximumExtraDataSize { 117 return fmt.Errorf("extra exceeds max length. %d > %v", len(extra), params.MaximumExtraDataSize) 118 } 119 miner.worker.setExtra(extra) 120 return nil 121 } 122 123 func (miner *Miner) MakeExtraData(extra []byte) []byte { 124 if len(extra) == 0 { 125 // create default extradata 126 extra, _ = rlp.EncodeToBytes([]interface{}{ 127 params.Version.Short(), 128 runtime.Version(), 129 runtime.GOOS, 130 }) 131 } 132 if uint64(len(extra)) > params.MaximumExtraDataSize { 133 log.Warn("Miner extra data exceed limit", "extra", hexutil.Bytes(extra), "limit", params.MaximumExtraDataSize) 134 extra = nil 135 } 136 return extra 137 } 138 139 // SetRecommitInterval sets the interval for sealing work resubmitting. 140 func (miner *Miner) SetRecommitInterval(interval time.Duration) { 141 miner.worker.setRecommitInterval(interval) 142 } 143 144 // Pending returns the currently pending block and associated state. 145 func (miner *Miner) Pending() *types.Block { 146 return miner.worker.pending() 147 } 148 149 // PendingBlock returns the currently pending block. 150 // 151 // Note, to access both the pending block and the pending state 152 // simultaneously, please use Pending(), as the pending state can 153 // change between multiple method calls 154 func (miner *Miner) PendingBlock() *types.Block { 155 return miner.worker.pendingBlock() 156 } 157 158 // PendingBlockAndReceipts returns the currently pending block and corresponding receipts. 159 func (miner *Miner) PendingBlockAndReceipts() (*types.Block, types.Receipts) { 160 return miner.worker.pendingBlockAndReceipts() 161 } 162 163 func (miner *Miner) SetEtherbase(addr common.Address) { 164 miner.coinbase = addr 165 miner.worker.setEtherbase(addr) 166 } 167 168 // SetGasCeil sets the gaslimit to strive for when mining blocks. 169 func (miner *Miner) SetGasCeil(ceil uint64) { 170 miner.worker.setGasCeil(ceil) 171 } 172 173 // EnablePreseal turns on the preseal mining feature. It's enabled by default. 174 // Note this function shouldn't be exposed to API, it's unnecessary for users 175 // (miners) to actually know the underlying detail. It's only for outside project 176 // which uses this library. 177 func (miner *Miner) EnablePreseal() { 178 miner.worker.enablePreseal() 179 } 180 181 // DisablePreseal turns off the preseal mining feature. It's necessary for some 182 // fake consensus engine which can seal blocks instantaneously. 183 // Note this function shouldn't be exposed to API, it's unnecessary for users 184 // (miners) to actually know the underlying detail. It's only for outside project 185 // which uses this library. 186 func (miner *Miner) DisablePreseal() { 187 miner.worker.disablePreseal() 188 } 189 190 // SubscribePendingLogs starts delivering logs from pending transactions 191 // to the given channel. 192 func (miner *Miner) SubscribePendingLogs(ch chan<- []*types.Log) event.Subscription { 193 return miner.worker.pendingLogsFeed.Subscribe(ch) 194 } 195 196 // SubscribePendingBlock starts delivering the pending block to the given channel. 197 func (miner *Miner) SubscribePendingHeader(ch chan<- *types.Header) event.Subscription { 198 return miner.worker.pendingHeaderFeed.Subscribe(ch) 199 }