github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/utilities/miner/miner.go (about)

     1  package miner
     2  
     3  import (
     4  	"fmt"
     5  	"sync/atomic"
     6  
     7  	"github.com/neatlab/neatio/chain/accounts"
     8  	"github.com/neatlab/neatio/chain/consensus"
     9  	"github.com/neatlab/neatio/chain/core"
    10  	"github.com/neatlab/neatio/chain/core/state"
    11  	"github.com/neatlab/neatio/chain/core/types"
    12  	"github.com/neatlab/neatio/chain/log"
    13  	"github.com/neatlab/neatio/neatdb"
    14  	"github.com/neatlab/neatio/neatptc/downloader"
    15  	"github.com/neatlab/neatio/params"
    16  	"github.com/neatlab/neatio/utilities/common"
    17  	"github.com/neatlab/neatio/utilities/event"
    18  )
    19  
    20  type Backend interface {
    21  	AccountManager() *accounts.Manager
    22  	BlockChain() *core.BlockChain
    23  	TxPool() *core.TxPool
    24  	ChainDb() neatdb.Database
    25  }
    26  
    27  type Pending interface {
    28  	Pending() (*types.Block, *state.StateDB)
    29  	PendingBlock() *types.Block
    30  }
    31  
    32  type Miner struct {
    33  	mux *event.TypeMux
    34  
    35  	worker *worker
    36  
    37  	coinbase common.Address
    38  	mining   int32
    39  	eth      Backend
    40  	engine   consensus.Engine
    41  	exitCh   chan struct{}
    42  
    43  	canStart    int32
    44  	shouldStart int32
    45  
    46  	logger log.Logger
    47  	cch    core.CrossChainHelper
    48  }
    49  
    50  func New(eth Backend, config *params.ChainConfig, mux *event.TypeMux, engine consensus.Engine, gasFloor, gasCeil uint64, cch core.CrossChainHelper) *Miner {
    51  	miner := &Miner{
    52  		eth:      eth,
    53  		mux:      mux,
    54  		engine:   engine,
    55  		exitCh:   make(chan struct{}),
    56  		worker:   newWorker(config, engine, eth, mux, gasFloor, gasCeil, cch),
    57  		canStart: 1,
    58  		logger:   config.ChainLogger,
    59  		cch:      cch,
    60  	}
    61  	miner.Register(NewCpuAgent(eth.BlockChain(), engine, config.ChainLogger))
    62  	go miner.update()
    63  
    64  	return miner
    65  }
    66  
    67  func (self *Miner) update() {
    68  	events := self.mux.Subscribe(downloader.StartEvent{}, downloader.DoneEvent{}, downloader.FailedEvent{})
    69  	defer events.Unsubscribe()
    70  
    71  	for {
    72  		select {
    73  		case ev := <-events.Chan():
    74  			if ev == nil {
    75  				return
    76  			}
    77  			switch ev.Data.(type) {
    78  			case downloader.StartEvent:
    79  				self.logger.Debug("(self *Miner) update(); downloader.StartEvent received")
    80  				atomic.StoreInt32(&self.canStart, 0)
    81  				if self.Mining() {
    82  					self.Stop()
    83  					atomic.StoreInt32(&self.shouldStart, 1)
    84  					self.logger.Info("Mining aborted due to sync")
    85  				}
    86  			case downloader.DoneEvent, downloader.FailedEvent:
    87  
    88  				self.logger.Debug("(self *Miner) update(); downloader.DoneEvent, downloader.FailedEvent received")
    89  				shouldStart := atomic.LoadInt32(&self.shouldStart) == 1
    90  
    91  				atomic.StoreInt32(&self.canStart, 1)
    92  				atomic.StoreInt32(&self.shouldStart, 0)
    93  				if shouldStart {
    94  					self.Start(self.coinbase)
    95  				}
    96  
    97  				return
    98  			}
    99  		case <-self.exitCh:
   100  			return
   101  		}
   102  	}
   103  }
   104  
   105  func (self *Miner) Start(coinbase common.Address) {
   106  	atomic.StoreInt32(&self.shouldStart, 1)
   107  	self.SetCoinbase(coinbase)
   108  
   109  	if atomic.LoadInt32(&self.canStart) == 0 {
   110  		self.logger.Info("Network syncing, will start miner afterwards")
   111  		return
   112  	}
   113  	self.worker.start()
   114  	self.worker.commitNewWork()
   115  }
   116  
   117  func (self *Miner) Stop() {
   118  	self.worker.stop()
   119  	atomic.StoreInt32(&self.shouldStart, 0)
   120  }
   121  
   122  func (self *Miner) Close() {
   123  	self.worker.close()
   124  	close(self.exitCh)
   125  }
   126  
   127  func (self *Miner) Register(agent Agent) {
   128  	if self.Mining() {
   129  		agent.Start()
   130  	}
   131  	self.worker.register(agent)
   132  }
   133  
   134  func (self *Miner) Unregister(agent Agent) {
   135  	self.worker.unregister(agent)
   136  }
   137  
   138  func (self *Miner) Mining() bool {
   139  	return self.worker.isRunning()
   140  }
   141  
   142  func (self *Miner) SetExtra(extra []byte) error {
   143  	if uint64(len(extra)) > params.MaximumExtraDataSize {
   144  		return fmt.Errorf("Extra exceeds max length. %d > %v", len(extra), params.MaximumExtraDataSize)
   145  	}
   146  	self.worker.setExtra(extra)
   147  	return nil
   148  }
   149  
   150  func (self *Miner) Pending() (*types.Block, *state.StateDB) {
   151  	return self.worker.pending()
   152  }
   153  
   154  func (self *Miner) PendingBlock() *types.Block {
   155  	return self.worker.pendingBlock()
   156  }
   157  
   158  func (self *Miner) SetCoinbase(addr common.Address) {
   159  	self.coinbase = addr
   160  	self.worker.setCoinbase(addr)
   161  }