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  }